Simplifying conditional logic for readibility - java

I have following code that sets vrstaProizvoda.
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
String vrstaProizvoda = null;
if (kreditJeAktivanKod != null && kreditJeAktivanKod.equals("Y")) {
vrstaProizvoda = VrstaProizvoda.STEP.value();
} else if (idArmPlana != null && !idArmPlana.isEmpty() && !idArmPlana.equals("0000")){
vrstaProizvoda = VrstaProizvoda.ARM.value();
}
return vrstaProizvoda;
}
Looking at else if statement, everything is negating values. Is there a better way to write idArmPlana condition so it is easier to read? Or is it not worth it?

You could write something along the lines of:
!(idArmPlana == null || idArmPlana.isEmpty() || idArmPlana.equals("0000"))
The logic is still the same, but it is slightly more readable. Having long chains of and's or or's is never super readable, but doing something like this where you have your simple conditions, or them together, then negate the result can work.

To make it easier to read, just create small functions that have a logical name:
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
String vrstaProizvoda = null;
if (isYes(kreditJeAktivanKod)) {
vrstaProizvoda = VrstaProizvoda.STEP.value();
} else if (!isZero(idArmPlana)){
vrstaProizvoda = VrstaProizvoda.ARM.value();
}
return vrstaProizvoda;
}
function boolean isYes(String string){
return (null != string && string.equals("Y");
}
function boolean isZero(String string){
return (null != string && !string.isEmpty() && string.equals("0000");
}

Not entirely sure about Arrays.asList, but the recurring idArmPlana could be used just once:
return "Y".equals(kreditJeAktivanKod)
? VrstaProizvoda.STEP.value()
: !Arrays.<String>asList("", "0000", null).contains(idArmPlana)
? VrstaProizvoda.ARM.value()
: null;

Using Apache commons-lang3 library you can:
import org.apache.commns.lang3.StringUtils;
if (StringUtils.isNotBlank(StringUtils.stripStart(idArmPlana,"0")))
stripStart stolen from How to remove leading zeros from alphanumeric text?

My preference is one of these:
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
if ( (kreditJeAktivanKod != null) && kreditJeAktivanKod.equals("Y") ) {
return VrstaProizvoda.STEP.value();
} else if ( (idArmPlana != null) && !idArmPlana.isEmpty() && !idArmPlana.equals("0000") ) {
return VrstaProizvoda.ARM.value();
} else {
return null;
}
}
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
if ( strEquals(kreditJeAktivanKod, "Y") ) {
return VrstaProizvoda.STEP.value();
} else if ( !strIsEmpty(idArmPlana) && !strEquals(idArmPlana, "0000") ) {
return VrstaProizvoda.ARM.value();
} else {
return null;
}
}
Here are a number of rewrites to show a range of alternatives, and to show how to reach the above with incremental adjustments:
Rewritten with more spaces and parenthesis. This makes it easier to pick out the long variable names, and relieves the reader of all need to organize the expression logic:
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
String vrstaProizvoda = null;
if ( (kreditJeAktivanKod != null) && kreditJeAktivanKod.equals("Y") ) {
vrstaProizvoda = VrstaProizvoda.STEP.value();
} else if ( (idArmPlana != null) && !idArmPlana.isEmpty() && !idArmPlana.equals("0000") ) {
vrstaProizvoda = VrstaProizvoda.ARM.value();
}
return vrstaProizvoda;
}
Rewritten to remove the default 'null' value. Having such a value is problematic. Consider if the logic were much more complex. Having a default value takes away the opportunity for the compiler to detect unhandled cases.
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
String vrstaProizvoda;
if ( (kreditJeAktivanKod != null) && kreditJeAktivanKod.equals("Y") ) {
vrstaProizvoda = VrstaProizvoda.STEP.value();
} else if ( (idArmPlana != null) && !idArmPlana.isEmpty() && !idArmPlana.equals("0000") ) {
vrstaProizvoda = VrstaProizvoda.ARM.value();
} else {
vrstaProizvoda = null;
}
return vrstaProizvoda;
}
Rewritten with multiple return values. This is my preference, but some prefer a single return statement, as was present in the original method.
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
if ( (kreditJeAktivanKod != null) && kreditJeAktivanKod.equals("Y") ) {
return VrstaProizvoda.STEP.value();
} else if ( (idArmPlana != null) && !idArmPlana.isEmpty() && !idArmPlana.equals("0000") ) {
return VrstaProizvoda.ARM.value();
} else {
return null;
}
}
Rewritten, with helper methods (see below). This is a little clearer, but at a cost of obscuring the test logic. Splitting code into a lot of small methods, while often encouraged, is not always preferred in practice.
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
if ( strEquals(kreditJeAktivanKod, "Y") ) {
return VrstaProizvoda.STEP.value();
} else if ( !strIsEmpty(idArmPlana) && !strEquals(idArmPlana, "0000") ) {
return VrstaProizvoda.STEP.value();
} else {
return null;
}
}
Helper methods:
// Test that two strings are equal. Handle null values.
private boolean strEquals(String value1, String value2) {
if ( value1 == null ) {
return ( value2 == null );
} else if ( value2 == null ) {
return false;
} else {
return value1.equals(value2);
}
}
// Test that two strings are equal. Handle null values.
private boolean strEquals(String value1, String value2) {
boolean result;
if ( value1 == null ) {
result = ( value2 == null );
} else if ( value2 == null ) {
result = false;
} else {
result = value1.equals(value2);
}
return result;
}
// Test if a string is neither null nor empty.
private boolean strIsNotEmpty(String value) {
return ( (value != null) && !value.isEmpty() );
}

To add one more alternative to the already given good answers:
private String napraviVrstuProizvoda(String kreditJeAktivanKod, String idArmPlana) {
return Optional.ofNullable(kreditJeAktivanKod).filter(e->e.equals("Y"))
.isPresent()? VrstaProizvoda.STEP.value() :
Optional.ofNullable(idArmPlana).filter(e->!e.equals("0000")).filter(e->!e.isEmpty())
.isPresent()? VrstaProizvoda.ARM.value():
null;
}

Related

Method refactoring to avoid to many npe checks

I have created the following method which returns a Triple of strings. However, I don't like the way I've written it because I think I've put in too many Npe checks making it unreadable.
private Triplet<String, String, String> getInfoFromTable(Person person) {
StringBuilder idWithText = new StringBuilder();
String idText;
Date time = null;
Level level;
Exercise exerciseRecord = getExercise(person);
if (exerciseRecord != null && exerciseRecord.getId() != null) {
if(exerciseRecord.getLevel1() != null && exerciseRecord.getLevel2() != null){
level = new Level(exerciseRecord.getLevel1(), exerciseRecord.getLevel2());
} else {
level = new Level("1", "1");
}
idText = getIdText(level, exerciseRecord.getId());
if(!Strings.isNullOrEmpty(idText)) {
idWithText = idWithText.append(exerciseRecord.getId()).append(" " + idText);
}
if (exerciseRecord.getTime() != null) {
time = exerciseRecord.getTime().toDate();
}
return new Triplet<>(idWithText.toString(), "1", formatTime(time));
}
return new Triplet<>("", "", "");
}
Ηow can I make the above code look simpler? I've seen a little use of Optional but I don't know if it's good to use them in my case. Could someone help with the method refactor?
You need to split the huge method into several simple, it will decrease complexity.
private Triplet<String, String, String> getInfoFromTable(Person person) {
Exercise exerciseRecord = getExercise(person);
if (exerciseRecord != null && exerciseRecord.getId() != null) {
return new Triplet<>(getIdWithText(exerciseRecord, getLevel(exerciseRecord)), "1", formatTime(exerciseRecord.getTime()));
}
return new Triplet<>("", "", "");
}
private String formatTime(LocalTime time) {
if (time == null) {
return "";
}
return formatTime(time.toDate());
}
private Level getLevel(Exercise exerciseRecord) {
Level level;
if(exerciseRecord.getLevel1() != null && exerciseRecord.getLevel2() != null){
level = new Level(exerciseRecord.getLevel1(), exerciseRecord.getLevel2());
} else {
level = new Level("1", "1");
}
return level;
}
private String getIdWithText(Exercise exerciseRecord, Level level) {
String idWithText = "";
String idText = getIdText(level, exerciseRecord.getId());
if(!Strings.isNullOrEmpty(idText)) {
idWithText = String.format("%s %s", exerciseRecord.getId(), idText);
}
return idWithText;
}

How to avoid lots of if else conditions with some conditions inside if else

I am trying to avoid if else conditions can you guys please help me?
if (getFromDate() != null && getToDate() != null && getBranchId() != null && getServiceGroupId() != null) {
return something;
} else if (getFromDate() != null && getToDate() != null && getBranchId() != null && getServiceGroupId() == null) {
return something;
} else if (getFromDate() != null && getToDate() != null && getServiceGroupId() != null && getBranchId() == null) {
return something;
} else if (getServiceGroupId() != null && getBranchId() != null && getFromDate() == null && getToDate() == null) {
return something;
} else if (getServiceGroupId() == null && getBranchId() == null && getFromDate() != null && getToDate() != null) {
return something;
} else if (getFromDate() == null && getToDate() == null && getBranchId() == null && getServiceGroupId() != null) {
return something;
} else if (getFromDate() == null && getToDate() == null && getBranchId() != null && getServiceGroupId() == null) {
return something;
} else {
return something;
}
You can use Stream.allMatch(x -> x == null) to check for mutiple null values from different or similar types. Declare Stream variables (or an array) using Stream.of(T... values).
It is best declared on some function boolean foo(T... varargs).
I see the following pattern in your code:
You have a group of boolean conditions (some value being null vs. not null) and want to return different values based on specific true/false combinations of these conditions.
If you encounter this pattern at multiple places, it might be worth to introduce a supporting class. Let's call it MultiBoolean, so you can write:
MultiBoolean nullCombinations = new MultiBoolean(
getFromDate() == null,
getToDate() == null,
getBranchId() == null,
getServiceGroupId() == null);
if (nullCombinations.matches(false, false, false, false) {
return something;
} else if (nullCombinations.matches(false, false, false, true) {
return something;
} else if (...) {
// and so on
The class might roughly look like:
public class MultiBoolean {
private boolean[] conditions;
public MultiBoolean(boolean... conditions) {
this.conditions = conditions;
}
public boolean matches(boolean... pattern) {
return Arrays.equals(conditions, pattern);
}
}
Disclaimer: I didn't test it.

What could be shortest code for this -- is any possibility with switch Case?

The below code has many duplicate lines, looking for a short thing for this.
if(null!= commonShipmentSplInstr.getIsGiftOrder() && GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getIsGiftOrder())) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_GIFT_ORDER);
giftMessageLine1 = commonShipmentSplInstr.getGiftMessageLine1();
giftMessageLine2 = commonShipmentSplInstr.getGiftMessageLine2();
giftMessageLine3 = commonShipmentSplInstr.getGiftMessageLine3();
} else if(null!= commonShipmentSplInstr.getSplInstr6() && GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getSplInstr6())) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_GIFT_ORDER);
giftMessageLine1 = commonShipmentSplInstr.getGiftMessageLine1();
giftMessageLine2 = commonShipmentSplInstr.getGiftMessageLine2();
giftMessageLine3 = commonShipmentSplInstr.getGiftMessageLine3();
} else if (null != sellingChannel && InvoiceHelper.isZolaSellingChannel(sellingChannel)) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_ZOLA_ORDER);
} else {
printObj.setDOCUMENT(DOCUMENT_FOR_PRINT_INVOICE_LABEL_FOR_PROSHIP);
}
In the setDOCUMENT method, all are Constants.
Just combine the two first if clause into one, they seem to be doing exactly the same:
if(commonShipmentSplInstr != null && (GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getIsGiftOrder()) || GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getSplInstr6()))) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_GIFT_ORDER);
giftMessageLine1 = commonShipmentSplInstr.getGiftMessageLine1();
giftMessageLine2 = commonShipmentSplInstr.getGiftMessageLine2();
giftMessageLine3 = commonShipmentSplInstr.getGiftMessageLine3();
}
else if (null != sellingChannel && InvoiceHelper.isZolaSellingChannel(sellingChannel)) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_ZOLA_ORDER);
}
else {
printObj.setDOCUMENT(DOCUMENT_FOR_PRINT_INVOICE_LABEL_FOR_PROSHIP);
}

how to avoid multiple if-else statements for vaildation in Java

I have lots of multiple if-else statements. For code optimization, I need to write one function for all if else logic. As of now my code structure is in below.
input request is in JSONObject(org.json.simple.JSONObject), which have more than 10 values.
String s = (String) inputObj.get("test");
String s1 = (String) inputObj.get("test");
String s2 = (String) inputObj.get("test");
String s3 = (String) inputObj.get("test");
if (s != null && s.trim().isEmpty()) {
if (s1 != null && s1.trim().isEmpty()) {
if (s2 != null && s2.trim().isEmpty()) {
if (s3 != null && s3.trim().isEmpty()) {
if (s4 != null && s4.trim().isEmpty()) {
........
} else {
return;
}
} else {
return;
}
} else {
return;
}
} else {
return;
}
} else {
return;
}
How to avoid this kind of looping and throw an error message in common method.
Advance thanks.
Consider adding all your strings to array or ArrayList of string, and looping thru each entry in it, and check them for null or emptiness.
You can try this.
void main() {
List<String> sList = new ArrayList<>();
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
for(String s : sList){
try {
checkString(s);
}catch (Exception e){
//log or print the exception, however you like
}
}
}
void checkString(String s) throws Exception{
if(s!= null && !s.trim().isEmpty()){
//doStuff
}else{
throw new Exception("String is null or empty !!!");
}
}
You should also check this out.
public class YourClass{
private boolean isBlankDataPresent(JSONObject inputObj, String[] keys) throws Exception {
for (String key : keys) {
String input = (String) inputObj.get(key);
if( input == null || input.trim().isEmpty())
throw new Exception(key +" is Empty");
}
return false;
}
public boolean validateData(JSONObject inputObj, String[] keys) throws Exception {
boolean isBlankDataPresent= isBlankDataPresent(inputObj, keys);
if (!isBlankDataPresent) {
// do Your Stuff and return true
}
}
}
public Integer checkIsEmapty(String checkingString){
if(checkingString != null && !checkingString.trim().isEmpty()){
return 1;
}
return 0;
}
public String method(){
String s ="";
String s1 = "hi";
String s2 = "java";
String s3 = null;
String s4 = null;
Integer s1i = checkIsEmapty(s);
Integer s2i = checkIsEmapty(s1);
Integer s3i = checkIsEmapty(s2);
Integer s4i = checkIsEmapty(s3);
Integer s5i = checkIsEmapty(s4);
Integer total = s1i + s2i + s3i + s4i + s5i;
switch (total){
case 1 :
// To DO
case 2 :
// To DO
}
}
in switch used to checking the value, U can pass binary and Integer also
Like #Emre Acre mentioned,
List<String> sList = new ArrayList<>();
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
sList.add(inputObj.get("test"));
boolean allDataValid = sList
.stream()
.allMatch(s -> s != null && s.trim().isEmpty());
if(allDataValid) {
......
} else {
return;
}

Comparison method violates its general contract and method compareTo

I have a class Contact with fields firstName, lastName and emails. I need to sort them using Collection.sort(...), but I got an exception:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
My compareTo method:
#Override
public int compareTo(Contact another) {
int compareFirstName = 0;
if (this.getFirstName() != null && another.getFirstName() != null) {
compareFirstName = this.getFirstName().compareToIgnoreCase(
another.getFirstName());
if (compareFirstName == 0) {
int compareLastName = 0;
if (this.getLastName() != null && another.getLastName() != null) {
compareLastName = this.getLastName().compareToIgnoreCase(
another.getLastName());
if (compareLastName == 0) {
int compareEmail = 0;
if (this.getEmails() != null
&& another.getEmails() != null) {
compareEmail = this.getEmails()
.compareToIgnoreCase(another.getEmails());
return compareEmail;
} else {
return 0;
}
} else {
return compareLastName;
}
} else {
int compareEmail = 0;
if (this.getEmails() != null && another.getEmails() != null) {
compareEmail = this.getEmails().compareToIgnoreCase(
another.getEmails());
return compareEmail;
} else {
return 0;
}
}
} else {
return compareFirstName;
}
} else {
int compareLastName = 0;
if (this.getLastName() != null && another.getLastName() != null) {
compareLastName = this.getLastName().compareToIgnoreCase(
another.getLastName());
if (compareLastName == 0) {
int compareEmail = 0;
if (this.getEmails() != null && another.getEmails() != null) {
compareEmail = this.getEmails().compareToIgnoreCase(
another.getEmails());
return compareEmail;
} else {
return 0;
}
} else {
return compareLastName;
}
} else {
int compareEmail = 0;
if (this.getEmails() != null && another.getEmails() != null) {
compareEmail = this.getEmails().compareToIgnoreCase(
another.getEmails());
return compareEmail;
} else {
return 0;
}
}
}
}
Please help me to find error in my compareTo method. Thanks.
Your implementation does violate the contract.
Suppose you have 3 Contacts :
contact1 : First Name = "John", Last Name = "Doe", Email = "x#gmail.com"
contact2 : First Name = "John", Last Name = "Doe", Email = null
contact3 : First Name = "John", Last Name = null, Email = "y#gmail.com"
Based on your logic :
contact1.compareTo(contact2) returns 0 (since they have the same first and last name).
contact2.compareTo(contact3) also returns 0 (since you only compare by first name).
But contact1.compareTo(contact3) doesn't return 0 (since they have different emails).
compareTo must be transitive.
The way to fix this is not to ignore a property that is null only in one of the contacts you are comparing. For example, if this.getLastName()==null && another.getLastName() != null, return 1 (assuming you want to order the null last names after the non-null last names).

Categories

Resources