Expressions should not be too complex for conditional operators - java

I am using Sonar and its giving me the suggestion "Expressions should not be too complex"
How can I make a better representation of below code?
Code
if (eDelivery != null && Boolean.parseBoolean(eDelivery.getReceiveConfirmationElectronically()) &&
!Boolean.parseBoolean(eDelivery.getInvalidEmailAddress()) && !Boolean.parseBoolean(eDelivery.getEmailUndeliverable()) &&
eDelivery.getUserEmailAddress() != null && !eDelivery.getUserEmailAddress().isEmpty()) {
// Implementation code
}

These conditions all relate to the eDelivery object, so deal with this there.
First, there's the question of why you're doing all these parseBoolean calls for properties that look like they should be boolean to start with. But okay, let's assume that you can't change that. Fine, so add 2ndary methods:
public class EDelivery {
public boolean isReceiveConfirmationElectronically() {
return Boolean.parseBoolean(getReceiveConfirmationElectronically())
}
// &etc...
Already that cleans it up considerably:
if (eDelivery != null && eDelivery.isReceiveConfirmationElectronically() &&
!eDelivery.isInvalidEmailAddress() && !eDelivery.isEmailUndeliverable() &&
eDelivery.getUserEmailAddress() != null && !eDelivery.getUserEmailAddress().isEmpty()) {
// Implementation code
But that doesn't address the number of conditions. So now:
// in EDelivery class
public boolean isEmailGood() {
return !isInvalidEmailAddress() && !isEmailUndeliverable() &&
getUserEmailAddress() != null && !getUserEmailAddress().isEmpty())
}
So now we're at:
if (eDelivery != null && eDelivery.isReceiveConfirmationElectronically() &&
eDelivery.isEmailGood()) {
// Implementation code
At this point you've met the requirement, but if you wanted to take it a little further:
// in EDelivery class
public boolean canSendElectronicConfirmation(){
return isEmailGood() && isReceiveConfirmationElectronically();
}
Which reduces your original if statement to
if (eDelivery != null && eDelivery.canSendElectronicConfirmation()) {
// Implementation code

Related

How to combine isEmpty, isBlank and null check while validating string in java [duplicate]

This question already has answers here:
how to check multiple string value are empty or blank at one shot using java
(2 answers)
Closed 1 year ago.
I'm validating given string is null, isEmpty or isBlank and I've use case where I've to check either productId or productItem should present or productName and productPrice should contains value. For that I've written below if condition but it looks very clumsy and not readable. Can someone please help me how can we simplify this if condition and write in more readable format.
public class validate {
public static void main(String[] args) {
String productId = "";
String productItem = "";
String productName = "Apple";
String productPrice = "1500";
if ((!productId.isEmpty() && !productId.isBlank() && productId != null
|| !productItem.isEmpty() && !productItem.isBlank() && productItem != null)
|| (!productName.isEmpty() && !productName.isBlank() && productName != null
&& !productPrice.isEmpty() && !productPrice.isBlank() && productPrice != null)) {
System.out.println("valid");
} else {
System.out.println("not valid");
}
}
}
In general, you can often simplify code by defining auxiliary methods.
Define this helper:
boolean isNullEmptyOrBlank(String s) {
return s == null || s.isEmpty() || s.isBlank());
}
then
if (isNullEmptyOrBlank(productId) && isNullEmptyOrBlank(productItem) && isNullOrEmptyOrBlank(productName)) {
// invalid - unknown product
}
else if (isNullOrEmptyOrBlank(productValue)) {
// invalid - unknown price
}
else {
// valid
}
I'm not sure if I got your intended logic correct, but you should get the idea.
In practice, I'd probably decide isNullEmptyOrBlank was a clunky name, and call it something like isSet instead.

How to prevent the error: null > 0 java

I currently have an enumlist. The enumlist gets filled at random, so there is a possibility that one has the value null. That is logical because it doesn't get filled.
The problem is further in my code I have:
if (player.Enumlist().get(CART_BLACK) > 0) {
}
Java throws a NullPointerException. Is there something I could add to the if-statement to prevent this error?
If get(CART_BLACK) may return null:
Get the value before the condition and replace it with a negative value if it's null:
Integer cartBlack = player.Enumlist().get(CART_BLACK);
if (cartBlack == null) cartBlack = -1;
if (cartBlack > 0) {
If player.Enumlist() may return null
Similar, but not quite identical:
final Enumlist list = player.Enumlist();
final int cartBlack = list == null ? -1 : list.get(CART_BLACK);
if (cartBlack > 0) {
You'll need to guard against nullity:
if(player.Enumlist().get(CART_BLACK) != null &&
player.Enumlist().get(CART_BLACK) > 0) {...}
or a more efficient version:
Integer temp = player.Enumlist().get(CART_BLACK);
if (temp != null && temp > 0){...}
if( player.Enumlist().get(CART_BLACK) != null && player.Enumlist().get(CART_BLACK) > 0) {
}
This will work because ifs are checked from left to right, and if one condition fails the rest won't be evaluated and you won't get the NPE.
Correcting the issue at the end makes the trick but it is not fine because it means that it may occur in other invocations. Besides, as a consequence, you may finish by overusing not null guards as you will never know if the null is a normal case.
So you should favor the use of Optional (Java 8 or Guava) as return rather than null to make your API clearer (it may return an empty thing so convey that) and more robust (the contained object has to be specifically unwrapped).
For example :
Optional<Integer> optValue = player.Enumlist().get(CART_BLACK);
optValue.filter(v -> v > 0)
.ifPresent( v -> ...);
You need to do Null Checking:
if (player == null || player.Enumlist () == null) {
throw new Exception("Player or Enumlist cannot be null");
}
You should also check that the Integer value is not null, but I guess that would be pretty weird if you wrote the code.
You are using get which could give you an IndexOutOfBoundsException eventually. You could check that using the size method or using streams.
If (player.Enumlist().size() > CART_BLACK && player.Enumlist().get(CART_BLACK) != null && player.Enumlist().get(CART_BLACK) > 0) {
//...
}
You may check for Null also handle the exception using try..catch block
try
{
if( player.Enumlist().get(CART_BLACK)!=null && player.Enumlist().get(CART_BLACK) > 0)
{
}
}
catch(NullPointerException)
{
//handle exception here
}

Java Multiple comparision in java

Pardon me if this is a stupid question.. I was wondering if there is any support for following comparison in Java:
(a, b, c .... != null) in place for :
(a != null && b != null && c != null && d ! null and so on ..)
I was trying to make code more readable as my code which is almost unreadable due to multiple condition in single statement.
code :
variable = (rest.host != null && rest.payload != null
&& rest.lockQueue != null && rest.endpoint != null ) || rest.default.setState
|| rest.scheduler.locked && rest.scheduler.queue.isFull()
&& lastPayload.getActivity.status.executing ? onExecute(rest.payload) : wait(TIME);
If your elements are in a collection, use collection.stream().allMatch(x -> x != null). Actually, there's even a predicate for that: collection.stream().allMatch(Objects::nonNull).
If your elements aren't in a collection, you can still use Arrays.asList() to create an ad-hoc list from them. So, in your case:
Arrays.asList(rest.host, rest.payload, rest.lockQueue, rest.endpoint).stream().allMatch(Objects::nonNull)
EDIT: actually, as someone mentioned in another answer, there is a method that creates a stream directly, namely Stream.of(...). So:
Stream.of(rest.host, rest.payload, rest.lockQueue, rest.endpoint).allMatch(Objects::nonNull)
You could do something like this to make sure everything is not null, if using a Java version lower than 8. Otherwise I would go with the other people's answers using streams.
private boolean checkIfNotNull( Object ... objects ) {
for(int i = 0; i < objects.length; i++) {
if(objects[i] == null)
return false;
}
return true;
}
and you could pass in all the objects that you want to check if they are null.
then you can call this in the if statement such as
if( checkIfNotNull( a, b, c, d, e, f, g ) ) {
//do stuff
}
In java 8, it could be done as next Stream.of(a, b, c, d).allMatch(Objects::nonNull), it will return true if they are all non null.
I think if you want your code more readable, you should replace your comparisons with method calls that "says" what each comparison is.
Example:
if (isAllRight(a, b, c)) {
...
}
In other cases you can break them into single comparisons and check one by one:
if (a == NUL) {
return false;
}
if (b == NULL) {
return false;
}
return true;

Findbugs-NP - NP_NULL_ON_SOME_PATH

Findbugs is showing NP_NULL_ON_SOME_PATH for a line.
It says that there is a branch of statement that, if executed, guarantees that a null value will be dereferenced, which would generate a NullPointerException when the code is executed.
Of course, the problem might be that the branch or statement is infeasible and that the null pointer exception can't ever be executed; deciding that is beyond the ability of FindBugs.
Here is the code:
public int compare(Object o1, Object o2)
{
....
String sTypeName1 = row1.getFieldValue(OBJECT_TYPE_FIELD_NAME);
String sTypeName2 = row2.getFieldValue(OBJECT_TYPE_FIELD_NAME);
if (sTypeName1!= null && sTypeName1.indexOf("~") != -1)
{
sTypeName1 = m_oc.getString(sTypeName1);
}
if (sTypeName2!= null && sTypeName2.indexOf("~") != -1)
{
sTypeName2 = m_oc.getString(sTypeName2);
}
int cf = sTypeName1.compareTo(sTypeName2);
if (cf == 0)
{
cf = o1.toString().compareTo(o2.toString());
}
return cf;
}
It is showing 2 errors of same kind for the code:
int cf = sTypeName1.compareTo(sTypeName2);
Here it says that there is a possible null pointer dereference from the value loaded from sTypeName1.
So I had to put a null check before this code like:
if(sTypeName1 != null && sTypeName2 != null)
{
int cf = sTypeName1.compareTo(sTypeName2);
}
but the issue is not resolved. :(
Could anyone suggest a solution and also what is wrong with my approach?
Thanks a lot for going through my question :)
For me the issue is resolved. This code does not produce a bug report:
String sTypeName1 = row1.getFieldValue("qqq");
String sTypeName2 = row2.getFieldValue("www");
if (sTypeName1 != null && sTypeName1.indexOf("~") != -1) {
sTypeName1 = m_oc.getString(sTypeName1);
}
if (sTypeName2 != null && sTypeName2.indexOf("~") != -1) {
sTypeName2 = m_oc.getString(sTypeName2);
}
int cf = 0;
if (sTypeName1 != null && sTypeName2 != null) {
cf = sTypeName1.compareTo(sTypeName2);
}
if (cf == 0) {
cf = o1.toString().compareTo(o2.toString());
}
return cf;
Probably you did not recompile your code or did not perform the FindBugs analysis again.
From my experience this can be caused by situations like this:
Situation 1 - Findbugs will complain if you only set b under some conditions, such as if a is not null, then later reference b. If a could really be null, you need to handle what to do if b is null too as a result. If a is never null, remove the null check. Also, for me it identified the line where b was defined as the first problematic line, rather than when b.doSomething() is called.
if (a != null) {
b = a.getB();
}
b.doSomething();
Situation 2 - You nullcheck in one place, but not another. Nullcheck everywhere, or nowhere
if (x != null) {
x.doSomething1();
}
x.doSomething2();

handling Null for bigdecimal

My code looks like below,
caseX caseXObj = caseXBo.getCaseXDao().findCaseXBySID(selectedID);
if(caseXObj != null && caseXObj.getCaseInGrossAmt() != null){
} else {
caseXObj.setCaseAmt(BigDecimal.ZERO);
}
I have handled NUll pointer for the caseX and also for getter and when null set the bigdeciaml to a default ZERO value. Still I get Null pointer exception in the setter line.Any suggestions?
It's quite possible that caseXObj is null, so it'll cause the NullPointerException. You should test the three cases like this:
caseX caseXObj = caseXBo.getCaseXDao().findCaseXBySID(selectedID);
if (caseXObj != null && caseXObj.getCaseInGrossAmt() != null) {
// do something with caseXObj
} else if (caseXObj == null) {
// initialize caseXObj, you were misssing this case!
} else {
caseXObj.setCaseAmt(BigDecimal.ZERO);
}
In essence, the error was that you were testing for only two cases - and there are three of them.
Assuming it is OK for getCaseXDao() to return null, you need to assign to caseXObj rather than use it as a pointer in the else clause.
That because you don't check for null in your else part.
It should be:
caseX caseXObj = caseXBo.getCaseXDao().findCaseXBySID(selectedID);
if(caseXObj != null && caseXObj.getCaseInGrossAmt() != null)
{
//...
}
else
{
if (caseXObj != null)
{
caseXObj.setCaseAmt(BigDecimal.ZERO);
}
}

Categories

Resources