I use PMD to check my code. It gives me very useful hints in most cases, but I can't figure out what could be improved in the following scenario.
The original code looks something like this:
if ((getSomething() != null && getSomethingElse() != null)
|| (getSomething() == null && getSomethingElse() == null))
{
...
}
PMD tells me:
Sometimes two 'if' statements can be consolidated by separating their
conditions with a boolean short-circuit operator.
For simplicity, let's just use a and b as boolean variables. Then this piece of code looks like this:
if ((!a && !b) || (a && b))
This can be transformed to one of the following:
if ((!a || b) && (a || !b))
if (!(a^b))
and finally
if (a==b)
So I simplified my code to
if ((getSomething() == null) == (getSomethingElse() == null))
However, PMD keeps complaining (in fact about all three versions). Is this a false positive or is there a better way of writing the if-condition?
The problem was something different. The if-statement was the only code inside another if (the code comes from a validation-method):
if (...)
{
...
}
else if (...)
{
...
}
else if (...)
{
if ((getSomething() == null) == (getSomethingElse() == null))
{
...
}
}
What the PMD-message means, is that I could combine the conditions of the last else-if and the inner if-clause:
if (...)
{
...
}
else if (...)
{
...
}
else if (... && ((getSomething() == null) == (getSomethingElse() == null)))
{
...
}
However, I'm not sure, if I'll do this, because the original version seems much clearer to understand.
if ((a != null) && (b != null) && (a==b))
..although personally, I'd do the null checking prior to this if statement so I could handle the a == null and b == null cases individually
The issue is that large blocks of conditionals are difficult to reason about.
OTOH, not every warning PMD emits needs to be paid attention to--consider the ROI. Is it worth refactoring or restructuring to make it cleaner? Can the same functionality be handled in a different way?
If it's not worth it, don't bother.
Related
I am using Talend to filter out some rows from an excel file and they don't allow block statements. Everything has to be simple logic or using the ternary operator. So the problem is that the code/logic I need will be used across every cell in the column, BUT some of the cells are null, some are Strings and the rest are Strings that represent integers.
My logic needs to be this:
Return true if and only if PlanName == null || PlanName == 0 but as you can tell, it will fail when it tries to run this on a cell that contains the null or the cell that contains a String that isn't a number.
Is it possible to have this logic in java without the try-catch or block statements? This is what I have right now:
input_row.PlanName == null || Integer.parseInt(input_row.PlanName) == 0
Thanks!
Edit: Basically, I just need to write logic that does this:
Return true if input_row.PlanName == null OR if input_row.PlanName == 0
This needs to be done without using block-statements or try-catches because I am using Talend. So I can only use logical operators like && and || and I can use ternary operators as well.
In your situation, i'll go for routines : reusable bunch of code, handy for this kind of rules that would be hard to implement without if/else etc.
You can create two Routines in Talend, with static methods that you would be able to use in a tMap or a tJavaRow.
First Routine to know if your plan is a numeric or not :
public static boolean isNumeric(String strNum) {
if (strNum == null) {
return false;
}
try {
double d = Double.parseDouble(strNum);
} catch (NumberFormatException nfe) {
return false;
}
return true;
}
Then another routine like :
public static boolean correctPlanName(String planName) {
if(Relational.ISNULL(planName)){
return false;
}
else{
if(!isNumeric(planName)){
return false;
}
else {
return true;
}
}
}
Then you call Routines.correctPlanName(input_row.planName) in tMap/tJavaRow.
It should do the trick.
You can use a regular expression to check if the String only contains digits, then check if num == 0.
input_row.PlanName == null || (input_row.PlanName != null && input_row.PlanName.matches("\\d+") && Integer.parseInt(input_row.PlanName) == 0)
Edit: Probably overkill but to cover other cases e.g. floating point types, numbers prefixed with +/-, you could also do:
input_row.PlanName != null && input_row.PlanName.matches("[-+]?\\d*\\.?\\d+") && Double.parseDouble(input_row.PlanName) == 0)
I need to simplify following code in java. Are there any way to using set and do this ?
if (!(((AdministrativeState.PLANNED == dispensingOccasionModel.getOccasionDTO().getAdminState()) ||
(AdministrativeState.MISSED == dispensingOccasionModel.getOccasionDTO().getAdminState()) ||
(AdministrativeState.SKIPPED == dispensingOccasionModel.getOccasionDTO().getAdminState()) ||
(AdministrativeState.SELF_ADMINISTERED == dispensingOccasionModel.getOccasionDTO().getAdminState()) ||
(AdministrativeState.SELF_ADMINISTERED_BY_RANGE == dispensingOccasionModel.getOccasionDTO().getAdminState())) &&
isSpecialDoseType(doseDetail))
Using Set, you can initialize the valid enum types and perform a contains as #shmosel also pointed out in the comments :
Set<AdministrativeState> administrativeStates = Set.of(PLANNED, MISSED, SKIPPED, SELF_ADMINISTERED, SELF_ADMINISTERED_BY_RANGE)
if (!administrativeStates.contains(dispensingOccasionModel.getOccasionDTO().getAdminState())
|| !isSpecialDoseType(doseDetail))
It is unclear what data types are we dealing with here so I can't give you a better answer until you can shed more light on this. But assuming AdministrativeState is an enumerator you can do something like this:
public enum AdministrativeState {
NONE, PLANNED, MISSED, SKIPPED, SELF_ADMINISTERED,
SELF_ADMINISTERED_BY_RANGE;
}
public static class OccasionModel {
AdministrativeState state;
OccasionModel() {
this.state = AdministrativeState.NONE;
}
OccasionModel setState(AdministrativeState state) {
this.state = state;
}
}
public static void checkAdminState(OccasionModel model) {
OccasionModel dispensingOccasionModel = model;
if (dispensingOccasionModel.state != AdministrativeState.NONE) {
// Do something here...
}
else System.out.println("Administrative state is not set yet");
}
public static void main(String[] args) throws IOException {
checkAdminState(new OccasionModel());
checkAdminState(new OccasionModel().setState(AdministrativeState.PLANNED));
}
I am not sure if this is what you're looking for but this doesn't have anything to do with Java 8 in particular. If you can provide more information about what's what I can help you out further.
Provided the get methods have no side effects and return always the same value (within the scope of your sample),
you can use refactoring
Extract variable
s =dispensingOccasionModel.getOccasionDTO().getAdminState());
Also, you can statically import AdministrativeState.*.
You then get:
AdministrativeState s =dispensingOccasionModel.getOccasionDTO().getAdminState();
if (!(((PLANNED == s) || (MISSED == s ) || (SKIPPED == s) ||
(SELF_ADMINISTERED == s) ||
(SELF_ADMINISTERED_BY_RANGE == s))
&& isSpecialDoseType(doseDetail))
Then taking into account that the double pipe (Boolean OR) operator has quite a lot priority you can remove the parentheses around single comparisons:
(a==b)||(c==d) ===> a==b||c==d.
You get:
if (!((PLANNED == s ||
MISSED == s ||
SKIPPED == s ||
SELF_ADMINISTERED == s ||
SELF_ADMINISTERED_BY_RANGE == s))
&& isSpecialDoseType(doseDetail))
There are double parentheses after ! And before &&. They can be reduced to a single one.
if (!(PLANNED == s ||
MISSED == s
|| SKIPPED == s ||
SELF_ADMINISTERED == s ||
SELF_ADMINISTERED_BY_RANGE == s)
&& isSpecialDoseType(doseDetail))
Now you can use the rule of inverting logical expressions:
!(a==b|| c==d) ===> a!=b&&c!=d,
Which basically inverts all the operations due to the NOT (!) Operator. Since you will have only && operators left to combine Boolean sub expressions, then you can drop the parentheses.
if (PLANNED != s
&& MISSED != s
&& SKIPPED != s
&& SELF_ADMINISTERED != s
&& SELF_ADMINISTERED_BY_RANGE != s
&& isSpecialDoseType(doseDetail)
)
Now if you have good domain knowledge you could know if you can combine self
Administered into one variable and shipped/missed into another to have something like: neither ( planned nor stoppedOrMissed nor selfAdministered)&& isSpecial. But without such knowledge I would live the expression at this level.
I have a problem with the logic expression on my method matches1().
Problem
SonarQube is telling me there is an error:
(expectedGlobalRule == null && actual != null)
SonarQube:
Change this condition so that it does not always evaluate to
"true".
Conditions should not unconditionally evaluate to "TRUE" or to "FALSE"
I'm essentially doing this logic to avoid a NPE on my "Block to be executed".
My code
matches1()
private boolean matches1(GbRule actual, GbRule expected) {
if(actual == null && expected == null) {
return true;
} else if((expected == null && actual != null) || (expected != null && actual == null)) {
return false;
} else {
//Block to be executed
}
}
I inverted the logic in to see what SonarQube would tell me and he doesn't complain about it.
matches2()
private boolean matches2(GbRule actual, GbRule expected) {
if(actual == null && expected == null) {
return true;
} else if(expected != null && actual != null) {
//Block to be executed
} else {
return false;
}
}
Question
Do the problem is in my boolean logic or it's SonarQube that lost
his mind?
If the problem is within sonarQube, how could I resolve it?
The problem is in your logic. Let's take it piece by piece:
if(actual == null && expected == null) {
return true;
At this point if both vars are null then we're no longer in the method. So if we get any further, then at least one of them is non-null.
The viable options at this point are:
actual = null, expected = non-null
actual = non-null, expected = null
actual = non-null, expected = non-null
Now, let's look at the next bit of code:
} else if((expected == null && actual != null)
We already know that both variables can't be null, so as soon as we know expected == null, there's no need to test whether actual != null. That has already been proven by the fact that we got this far. So actual != null is always true, which is why an issue is raised.
Edit
This means that your code could be boiled down to:
private boolean matches1(GbRule actual, GbRule expected) {
if(actual == null && expected == null) {
return true;
} else if(actual == null || expected == null) {
return false;
}
//Block to be executed
}
Note that the else isn't needed & dropping it makes the code easier to read.
Even when the code is correct; seriously, it makes my eyes hurt. Thing is: it is hard to read. Such kind of nested conditions is something that one should not be writing in the first place.
If you can't avoid it; at least refactor it into something like
private boolean areActualAnedExpectedBothNull(args ...) {
return actual == null && expectedGlobalRule == null;
}
And please note; you can dramatically simply your code:
if (areActualAnedExpectedBothNull(actual, expected)) {
return true;
}
if (actual == null) {
return false;
}
if (expected == null) {
return false;
}
do your thing ...
and use such methods in your other code. And of course, you do a lot of unit testing; probably with coverage measurements; just to make sure that your tests really test all possible paths through this maze.
But as said; you better step back and think if there are ways to avoid writing such code in the first place.
The typical answer to booleans, and if/else chains in OO programming is polymorphism. So instead of asking something about its state; you turn to interfaces/abstract classes; and have different implementations of those. And then you have a factory giving you that implementation you need; and then you just call methods on that; without further need for if/else/whatever.
If you don't know what I am talking about - watch these videos; especially the second one!
The problem is with SonarQube.
See this article for more info on ignoring that issue: https://www.bsi-software.com/en/scout-blog/article/ignore-issues-on-multiple-criteria-in-sonarqube.html
You can just set it up to ignore that error within that file.
The gist of it is
Open the Settings (SonarQube General Settings or project Settings) and
select the Exclusions category. Switch to the Issues Exclusions and
scroll down to “Ignore Issues on Multiple Criteria”. Set squid:S00112
as Rule Key Pattern and **/*Activator.java as File Path Pattern.
You will need to change the rule key pattern to the pattern associated with the rule that is being violated for your code and the file pattern as the path of your .java file.
I'm trying to do something to the effect of:
if (firstChoice == A || B && secondChoice == A || B){
//passes check.
}
Logically, I want this to pass if the first and second choice are either A or B. Is this syntax valid? Is there a better way to do it?
You can't do == A || B; you can do this (but shouldn't, see below):
if ((firstChoice == A || firstChoice == B) &&
(secondChoice == A || secondChoice == B)) {
That's about as readable as you're going to get it. Breaking it over a line makes it easier to follow the logic; horizontal scrolling is almost always a bad thing, and breaking it at the && operator is the most readable way.
However, there's a way to make it more readable: create a helper method, which does what you want.
private boolean isAorB(YourObject choice) {
return choice == A || choice == B;
}
Then your if statement would be:
if(isAorB(firstChoice) && isAorB(secondChoice)) {
This would be much more readable for future readers, including yourself, which is what you're really going for here.
if (((firstChoice == A) || (firstChoice == B)) && ((secondChoice == A) || secondChoice == B)))
{
//passes check.
}
if ((firstChoice == A || firstChoice == B) && (secondChoice == A || secondChoice == B)) {
//do stuff
}
The thing to note here is that stuff like (firstChoice == A || B) makes sense when you read "firstChoice is equal to A or B" in your head but it doesn't make sense to Java. The left and right side of the || operator have to evaluate to a boolean. 'B' is not a boolean type (I'm assuming), but the condition firstChoice == B is.
Also, you can use parentheses to mark the order of operations, like you do with normal arithmetic. Even if they are not needed, it usually helps with readability.
As I mentioned in a comment and others have mentioned, there's no shorthand for saying "if X equals A or B or C or..." or anything like that. You have to say if (x == a || x == b || x == c), etc. (COBOL does allow that kind of expression, but unfortunately this useful feature hasn't found its way into the design of too many other languages.)
You can say:
if (isOneOf(firstChoice, A, B) || isOneOf(secondChoice, A, B)) {
...
}
if you define an isOneOf method like this:
#SuppressWarnings("unchecked")
public static <T> boolean isOneOf(T obj, T... choices) {
for (T choice : choices) {
if (choice.equals(obj)) {
return true;
}
}
return false;
}
[Note that this allows for more than two choices.]
Is this bad practice or any performance hit, this is to check x is not equal to null
if( !(x == null) ){
System.out.println("x is not a null value");
}
The normal way to do this is:
if(x != null){
System.out.println("x is not a null value");
}
There's nothing wrong with checking if the value is not null!
It is bad practice to do without making the reason to do so clear. It's not clear in your example why you are making the check. A common example might be something like
if (s == null || s.isEmpty()) // if s empty or not set.
or
if (s != null && s.length() > 0)
Usually, you do this when you need it in which case performance isn't important.
Normally you would write
if(x != null)
or better
if (x == null) {
// handle null, assuming this is not empty.
} else {
// handle not null
}
Performance-wise it is unlikely to be relevant, because you can trust the compiler to optimize that.
It's just a question of style. Style is always subjective, but I would say if (x != null) is more concise and more readable.
if(x != null) is recommended and easy to read "X is not equal to null"
if(!(x == null)) can't be read as "X is not equal to null"
Just to add here best practice is to do
if(null != x) {
System.out.println("x is not null");
}
instead of
if(x != null) {
System.out.println("x is not null");
}
I know in java anyways will work but this will save you in other languages like c++ where you might accidently assign null to x for example,
if(x = null) {
printf("x is not null");
}
if( !(x == null) ){
System.out.println("x is not a null value");
}
well if condition returns a boolean true of false. so, writing above will not effect anything. according, to above code the condition you wrote is "if is not true" then do something! and as others have suggested to write code as if(x != null) is better way and less confusing ;)