I'm working on a project and the maintainer suggested me to split a method into two because checks dose not allow to exceed a certain cyclomatic complexity.
#Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
final Suppression suppression = (Suppression) other;
return Objects.equals(lineNo, suppression.lineNo)
&& Objects.equals(columnNo, suppression.columnNo)
&& Objects.equals(suppressionType, suppression.suppressionType)
&& Objects.equals(text, suppression.text)
&& Objects.equals(eventSourceRegexp, suppression.eventSourceRegexp)
&& Objects.equals(eventMessageRegexp, suppression.eventMessageRegexp)
&& Objects.equals(eventIdRegexp, suppression.eventIdRegexp)
&& Objects.equals(firstLine, suppression.firstLine)
&& Objects.equals(lastLine, suppression.lastLine);
}
this is the overridden equals method and it is exceeding the maximum cyclomatic complexity limit because of the return statements ig.
He suggested splitting it into two, how can I do that.
I'm a beginner so I don't know about java that much, so if this question is completely invalid, then please tell me😅
Related
i try to find out what is the right way to implement java equals.
reading on the net I saw that there are many Thoughts on the subject I narrow down to 2 options
1 using instance of and on using getClass() != obj.getClass()
to follow the rules of :
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
this is my final result :
public class Foo {
private List<Long> days;
private String project;
public boolean equals(Object obj) {
if (this == obj)
return true;
//avoid symmetry problem
if (obj == null || getClass() != obj.getClass())
return false;
Foo test = (Foo)obj;
return equals(this.project,test.project) && equals(this.days,test.days);
}
public static boolean equals(Object a,Object b) {
return a == b || a != null && b!=null && a.equals(b);
}
}
what do you say ?
Your code looks good in general. getClass() != obj.getClass() is sufficient enough. It will only fail for positive scenario if someone goes crazy with tricky custom code to load same class with different classloaders.
I would also replace your custom equals on fields with standard Objects.equals at the end:
return Objects.equals(days, foo.days) &&
Objects.equals(project, foo.project);
It's always good to override hashcode when you override equals too.
You may want to custom the equals on the list if the order matter.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Foo foo = (Foo) o;
return Objects.equals(days, foo.days) && Objects.equals(project, foo.project);
}
#Override
public int hashCode() {
return Objects.hash(days, project);
}
You would rewrite your code with the following consideration, we use equals() to compare objects otherwise, = sign used to compare data types
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.
So today my data structures final had an exam question that asked this:
"Consider the BinaryTree class and add two recursive methods (independent from each other) named compBT to compare two binary trees. If the two binary trees are structurally identical (i.e., they look the same when the objects stored in the nodes are ignored), each of the two methods returns true; otherwise, each returns false. The first method should be an instance method and the second method should be a class method. Do not access the underlying data structure directly. Note: each method should not take more than 6 lines and be properly indented."
I was able to produce this for the class method:
public static boolean compareTrees(BinaryTree t1, BinaryTree t2) {
if (t1 == null && t2 == null) return true;
if ((t1 == null && t2 != null) || (t1 != null && t2 == null)) return false;
return compareTrees(t1.left, t2.left) && compareTrees(t1.right, t2.right);
}
I felt pretty confident about this answer, but writing the instance method had me totally stumped, especially since it had to be independent from the class method. All I was able to produce was the following:
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
return (compareTrees(this.left) && (t.left)) && (compareTrees(this.right) && compareTrees(t.right));
}
I know the method is incorrect since it will always return false because there is only one base case which will always be met. My thought process behind that particular base case is that if the parameter is null, then return false since there is a structural inequality because the caller cannot be null (only non-null references can call instance methods). But I didn't know what else to do from there.
Can anyone chime in? I thought this problem was pretty interesting.
Edit: adding in BinaryTree class.
Here's what the BinaryTree class looked like:
class BinaryTree {
public int value;
public BinaryTree left;
public BinaryTree right;
public BinaryTree(int x) { value = x;}
}
For instance method, all that changes is that check is before recursion, no in it:
public boolean compareTrees(BinaryTree other) {
if (left == null) != (other.left == null) return false;
if (right == null) != (other.right == null) return false;
if (left != null && !left.compareTrees(other.left)) return false;
if (right != null && !right.compareTrees(other.right)) return false;
return true;
}
I think you've recognized the basic problem. In your static method, you can pass null for both child trees when you call the method recursively. But in your instance method, you can only do that for the parameter. You can't do that for the instance method, since you can't call an instance method on null.
Well, if you can't call the instance method recursively on a null child, you have to handle the null child case before the recursive call. That's the key here, the realization that you will have to rearrange your logic. So your logic will need to be something like this:
If the parameter is null, return false (like you already did)
If the instance's left child is null, then:
2.1 If the parameter's left child is not null, return false
2.2 If the parameter's left child is null, keep going with step 4
If the instance's left child is not null, then call recursively on the left child (it doesn't matter if the parameter's left child is null, because that will be caught be #1), and return false if the recursive call returns false
4-5. Same steps for the right child
If we've gotten this far, and no check has failed, then we can return true
So the code looks something like this:
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
if (this.left == null) {
if (t.left != null) {
return false;
}
}
else if (!this.left.compareTrees(t.left)) {
return false;
}
if (this.right == null) {
if (t.right != null) {
return false;
}
}
else if (!this.right.compareTrees(t.right)) {
return false;
}
return true;
}
EDIT: I just now noticed the requirement that the method not be more than 6 lines. So I guess my answer won't work. On the other hand, I could make it work by compressing a bunch of stuff onto a few lines.
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
if (this.left == null && t.left != null) return false;
if (this.left != null && !this.left.compareTrees(t.left)) return false;
if (this.right == null && t.right != null) return false;
if (this.right != null && !this.right.compareTrees(t.right)) return false;
return true;
}
I could make it even shorter by combining the last two lines into one. But
if your professor is going to reward compressed, harder-to-read code such as this, and fail cleaner code like I had in my earlier example, shame on him.
More: OK, if your professor measures code quality by a smaller number of lines, this should make him ecstatic, even though all my colleagues would blast it in a code review:
public boolean compareTrees(BinaryTree t) {
return !((t == null) || (this.left == null && t.left != null) || (this.left != null && !this.left.compareTrees(t.left)) || (this.right == null && t.right != null) || (this.right != null && !this.right.compareTrees(t.right)) );
}
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.
Our project contains several classes that we have equals() and hashCode() methods generated by Eclipse (Right Click -> Source -> Generate hashCode() and equals()).
Example:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final MyTO other = (MyTO) obj;
if (num != other.num)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (table == null) {
if (other.table != null)
return false;
} else if (!table.equals(other.table))
return false;
return true;
}
These methods that work well for our application, but unfortunately do not pass our cyclomatic complexity checks with Checkstyle. Since these methods are auto-generated, we are not concerned with their complexity. We could suppress the entire class from Checkstyle, but we would prefer to be able to exclude just these two methods.
Does anyone know how to create a custom rule in Checkstyle that will allow us to exclude generated equals() and hashCode() methods in any way, without excluding the entire class?
You should set up a SupressionCommentFilter. More info on this here.
Sometimes there are legitimate reasons for violating a check. When this is a matter of the code in question and not personal preference, the best place to override the policy is in the code itself. Semi-structured comments can be associated with the check.