How do I fix PMD Warning: UseCollectionIsEmpty? - java

I'm getting a PMD warning UseCollectionIsEmpty and the exact message it gives is:
Substitute calls to size() == 0 (or size() != 0, size() > 0, size() <
1) with calls to isEmpty()
on the last else if statement.
My issue is that my statement is checking if my ArrayList is NOT empty. But the PMD warning is telling me to change it to isEmpty(), which is not what I need to do. What's the work around to fix this?
if (theNeighbors.get(getDirection()) == Terrain.CROSSWALK) {
myDirection = getDirection();
} else if (theNeighbors.get(getDirection().left()) == Terrain.CROSSWALK) {
myDirection = getDirection().left();
} else if (theNeighbors.get(getDirection().right()) == Terrain.CROSSWALK) {
myDirection = getDirection().right();
} else if (myPossDir.size() > 0) {
myDirection = myPossDir.get(random.nextInt(myPossDir.size()));
} else {
myDirection = getDirection().reverse();
}

Instead of
} else if (myPossDir.size() > 0) {
myDirection = myPossDir.get(random.nextInt(myPossDir.size()));
} else {
myDirection = getDirection().reverse();
}
You should use:
} else if (myPossDir.isEmpty()) {
myDirection = getDirection().reverse();
} else {
myDirection = myPossDir.get(random.nextInt(myPossDir.size()));
}
This will make the above PMD warning go away, and it more clearly states your intent, you want to check that the collection is not empty. Using size() is for other cases - when you don't compare it to zero.
EDIT: Changed order of ifs, so now you use isEmpty() instead of !isEmpty() (another PMD warning, and negated ifs are not as easily readable as not negated ones)

Instead of;
if ( myCollection.size() > 0)
you can use
if(myCollection !=null && !mycollection.isEmpty())
to fix this PMD error.

Related

compareTo() method throwing "This method must return int" error despite returning int in method

I'm working on an assignment for my computer science course requiring me to implement a Comparable interface.
We haven't discussed the interface at any sort of length except just being told it compares two objects and returns less than, greater than and equal to, but literally that's about it, which is frustrating.
I intend to do more research on it, but for now I am finding I'm confused as to why my implementation of the compareTo() method isn't working.
Eclipse is giving me an error that compareTo() must return an int, but if you notice, I am returning an integer value. So what might be the issue?
public int compareTo(Task taskToCompare) {
if(this.complete && taskToCompare.isComplete()) {
if(this.priority == taskToCompare.getPriority()) {
return 0;
}
else if(this.priority < taskToCompare.getPriority()){
return -1;
}
else if(this.priority > taskToCompare.getPriority()) {
return 1;
}
} else if(this.complete == true && taskToCompare.isComplete() == false) {
return -1;
} else if(this.complete == false && taskToCompare.isComplete() == true) {
return 1;
}
}
If the return type is int, you will have to return an int or throw an exception. Just exiting the method without a return will lead to a compiler error.
If you have a if-else-if condition, there may be a case where none of the blocks is called. You therefore should create an else statement with a return.
Also, the result of isComplete() and taskToCompare.getPriority() may change if you call the method multiple times. The compiler doesn't know if your logic prevents that.
For example, this is the case if complete is false and isComplete() also returns false. As before, the compiler doesn't know if your logic prevents that.
I think you want something like:
public int compareTo(Task taskToCompare) {
if(this.complete && taskToCompare.isComplete()) {
if(this.priority == taskToCompare.getPriority()) {
return 0;
}
else if(this.priority < taskToCompare.getPriority()){
return -1;
}
else{
return 1;
}
} else if(this.complete == true && taskToCompare.isComplete() == false) {
return -1;
} else if(this.complete == false && taskToCompare.isComplete() == true) {
return 1;
}else{
return 0;
}
}
What if this.complete == false and taskToCompare.isComplete() == false?
The compiler is complaining because you haven't covered every case.
more compact version:
public int compareTo(Task taskToCompare) {
int completeCompare = (this.complete == taskToCompare.complete) ? 0 : (this.complete ? 1 : -1);
if(completeCompare==0) {
return this.priority-taskToCompare.getPriority();
}
return completeCompare;
}

Refactoring empty if-statements

I currently working on a project that I need to remove a class that is being used by different other classes. There are cases that I can remove the one line of code that consists of that class where it will never affect the functionality of the program, but also there are cases that the class that you want to be removed is inside an if-statement. The main problem is that once I removed the line of code consisting of that class where is it inside the if-statement, it will be an empty if-statement that will violates the sonar.
Is there another way to refactor an empty if-statement other that negating the condition of one of the statements? Because when I'm just negating the condition, the readability of the code reduced.
For Example:
if((example_A >= 0) && (condition_A))
{
removeThisClass();
}
else if((example_B >= )) && (condition_B))
{
doSomething();
}
else
{
doAnything();
}
Refactored:
if(!((example_A >= 0) && (condition_A)) && ((example_B >= )) && (condition_B)))
{
doSomething();
}
else
{
doAnything();
}
You can put this code in separate method (https://refactoring.com/catalog/extractFunction.html) and write it like this:
public void DoSomeStuff() {
if((example_A >= 0) && (condition_A))
return;
if((example_B >= )) && (condition_B)) {
doSomething();
return;
}
doAnything();
}
If I understand you right, the line removeThisClass(); should be removed, and you don't want to be left with an empty block like this:
if((example_A >= 0) && (condition_A))
{
}
else if((example_B >= )) && (condition_B))
{
doSomething();
}
else
{
doAnything();
}
In order to not do the "A" tests twice, you need to negate the condition, e.g. like this:
if ((example_A < 0) || ! (condition_A))
{
if ((example_B >= )) && (condition_B))
{
doSomething();
}
else
{
doAnything();
}
}
Your refactored code is wrong, because if the "A" condition is true, the original code would execute removeThisClass();, which means it should now do nothing, but your code will call doAnything(); when "A" is true.
You can put in a comment. Sonar should accept that and it could also help the reader.
void doSomething() {
for (int i = 0; i < 42; i++) // Non-Compliant
{
}
for (int i = 0; i < 42; i++); // Compliant
if (myVar == 4) // Compliant - contains a comment
{
// Do nothing because of X and Y
}
else // Compliant
{
doSomething();
}
try // Non-Compliant
{
}
catch (Exception e) // Compliant
{
// Ignore
}
}

Questions on if and else statements

This is the question I saw on CodingBat:
Given 2 positive int values, return the larger value that is in the range 10..20 inclusive, or return 0 if neither is in that range.
And this is the code I have written:
public int max1020(int a, int b) {
if ( a>=10 && a<=20 && b>=10 && b<=20 && a>b)
return a;
if (a>=10 && a<=20 && b>=10 && b<=20 && b>a)
return b;
if (a>=10 && a<=20 && b<=10 || b>=20)
return a;
if (a<=10 || a>=20 && b>=10 && b<=20)
return b;
else return 0;
}
I am fairly confident that it is correct but still then I click run, the websites says that: max1020(9, 21) → 0 BUT my code returns 9. Can someone help me to check through my codes what is wrong with it? :)
public int max1020(int a, int b) {
if ( a>=10 && a<=20 && b>=10 && b<=20 && a>b)
return a;
if (a>=10 && a<=20 && b>=10 && b<=20 && b>a)
return b;
if ((a>=10 && a<=20) && (b<=10 || b>=20))
return a;
if ((a<=10 || a>=20) && (b>=10 && b<=20))
return b;
else return 0;
}
Adding brackets in 3rd and 4th line will fix the problem.
I suggest you change the if statements and use else if. It is just good coding practice to use else if statements instead of several if when possible.
Your code is breaking in the third if condition, where you have || b>=20. 3rd and 4th conditions should be more specific like below:
if (a>=10 && a<=20 && (b<=10 || b>=20))
return a;
if ((a<=10 || a>=20) && b>=10 && b<=20)
return b;
Adding these parentheses will do the trick.
i would prefer to assign the checks to a variable to have a more "readable" code. but this depends on personal preferences.
public int max1020(int a, int b) {
final boolean aInRange = a>=10 && a<=20;
final boolean bInRange = b>=10 && b<=20;
if (aInRange && bInRange) {
if (a > b) {
return a;
} else if (a < b) {
return b;
} else {
return 0;
}
} else if (aInRange) {
return a;
} else if (bInRange) {
return b;
} else {
return 0;
}
}
Of course Varun's answer is correct. Additionally, I'd like to elaborate on some comments, and show an alternative approach to the problem that's much simpler and less likely to contain mistakes.
While reading the problem statement, you may notice that the method is to return a value if some conditions are met, or return 0 otherwise. So you could initialize a result with the default value of 0, change the result if the conditions are met, then return the result. That would reduce the code to:
public int max1020(int a, int b) {
int result = 0;
if (a >= 10 && a <= 20) result = a;
if (b >= 10 && b <= 20 && b > result) result = b;
return result;
}
Can't make it much simpler, I'd think. (But if you can, please comment, I love KISS! :) )
This solution produces a slightly different result, if both a and b are in range and a=b, it will return a. The problem statement is not really clear if this should happen, as also shown by the comments to Varun's answer. Coincidentally (or not) Codingbat doesn't check that condition. The proposed solution on the site also returns a in this case.
If you think it should return 0 when a=b, it's quite easy to adjust,
public int max1020(int a, int b) {
int result = 0;
if (a != b) {
if (a >= 10 && a <= 20) result = a;
if (b >= 10 && b <= 20 && b > result) result = b;
}
return result;
}
Still pretty simple :)
To explain TJCrowder's comment about indentation: If you put the body of the if statement on the next line, you should use curly braces and indent the line. Otherwise, it's far too easy to misread it, or make a mistake when you change the code.
// this can be error prone and harder to read,
// especially if you have multiple if statements,
// or add a statement to the body of the if statement in the future
// (shouldn't do this)
if (condition)
statement;
// Personally I think this is totally fine for a simple statement.
// But I know not everybody will agree
if (condition) statement;
// Usually, you'll see this formatting.
// Even without reading anything, the formatting makes it instantly clear
// which statements belong to the body of the if
if (condition) {
statement;
}
Side note: the else statement in your code belongs only to the last if. Your formatting could make that clear by not putting an empty line between those, e.g.
if (condition) statement;
else statement;
if (condition) {
statement;
} else {
statement;
}
In your code the else statement is actually obsolete, you could simply return 0; on the last line.
Varun's suggestion that you could use else ifs is correct. Theoretically, if the condition of the first if statement is true, using else if would make the code skip the tests for the other ifs and be a little more efficient. Additionally, it'd show that subsequent if statements are only reached if the previous if statements were false.
Practically however, in your code it doesn't really matter, because the method will finish and return a value if the condition is true, and subsequent if statements will never be reached anyway.

How to compare three boolean values

Compare three boolean values and display the first one that is true.
Hey guys, I am trying to write a program that compares three boolean values and displays the first true one. I am comparing three words for their length, and it will display the longest. The error that I am getting is that my else tags aren't working. Take a look at the code.
//Check which word is bigger
if (len1 > len2)
word1bt2 = true;
if (len2 > len3)
word2bt3 = true;
if (len1 > len3)
word1bt3 = true;
//Check which word is the longest
if (word1bt2 == true && word1bt3 == true);
System.out.println(wor1);
else if (word2bt3 == true);
System.out.println(wor2);
else System.out.println(wor3);
I have set boolean values for word1bt2, word2bt3 and word1bt3. In eclipse, I am getting a syntax error under the elses in my code above. Any help would be great!
if (word1bt2 == true && word1bt3 == true);
Is wrong, you need to remove the semicolon:
if (word1bt2 == true && word1bt3 == true)
Same for the elses
else (word2bt3 == true);
Is wrong too, it should be
else if (word2bt3 == true)
Side note: boolean values can be used as condition, so your if statements should be
if (word1bt2 && word1bt3) // The same as if (word1bt2 == true && word1bt3 == true)
How to compare three boolean values?
Dont!
If you find yourself needing to compare three variable you may as well cater for any number of variables immediately - there's no point hanging around - do it properly straight away.
public String longest(Iterator<String> i) {
// Walk the iterator.
String longest = i.hasNext() ? i.next() : null;
while (i.hasNext()) {
String next = i.next();
if (next.length() > longest.length()) {
longest = next;
}
}
return longest;
}
public String longest(Iterable<String> i) {
// Walk the iterator.
return longest(i.iterator());
}
public String longest(String... ss) {
// An array is iterable.
return longest(ss);
}
Remove the ; and change it with brackets {}.
if (word1bt2 && word1bt3) {
System.out.println(wor1);
} else if (word2bt3) {
System.out.println(wor2);
} else {
System.out.println(wor3);
}
Issue with the else blocks: use {} insteaad of () to enclose instructions...
Remove the ; at the first if!!!!! - Quite common mistake, with very puzzling results!
//Check which word is the longest
if (word1bt2 == true && word1bt3 == true) { //leave ; and always add bracket!
System.out.println(wor1);
}
else if(word2bt3 == true)
{
System.out.println(wor2);
}
else {
System.out.println(wor3);
}
if you need a condition in an else branch, you have to use if again - plain else won't have such a feature...
ALWAYS use brackets for bodies of if statements, loops, etc!!!
Be extremely careful NOT to use ; in the lines that don't behave well with it:
if statements
for loops
while() {...} loops' while statement
try this, if lenght are equal then s1 is considered as Bigger. Also i have not added null check
public class Test {
public static void main(String[] args) {
String word1 = "hi";
String word2 = "Hello";
String word3 = "Hell";
String Bigger = null;
if(word1.length() >= word2.length() && word1.length() >= word3.length() ){
Bigger = word1;
}else if(word2.length() >= word1.length() && word2.length() >= word3.length()){
Bigger = word2;
}else if(word3.length() >= word2.length() && word3.length() >= word1.length()){
Bigger = word3;
}
System.out.println(Bigger);
}
}

Java - modified compareTo method says it needs to return an int, but it should be returning one

I'm learning basic Java right now and have a problem with my code that I can't figure out. It's basically what the title says. My Java compiler is telling me that there's an error with my custom compareTo method, saying that it needs to return an int. The problem is, as far as I can tell, it IS returning an int. Yet it's still giving me an error. Could someone please point out in my code what's wrong? And also I have already implemented Comparable in my class. Here's my method:
public int compareTo(Homework other) {
if (getDaysLate() < other.getDaysLate()) {
return -1;
} else if ((dateSubmitted == other.dateSubmitted)
&& (files.compareTo(other.files) == -1)) {
return -1;
} else if ((dateSubmitted == other.dateSubmitted)
&& (files == other.files)) {
if (name.compareTo(other.name) == -1) {
return -1;
} else if (name.compareTo(other.name) == 1) {
return 1;
} else if (name.compareTo(other.name) == 0) {
return 0;
}
} else {
return 0;
}
}
There is a path in the third else that does't return anything.
else if ((dateSubmitted == other.dateSubmitted) && (files == other.files)) {
if (name.compareTo(other.name) == -1) {
return -1;
}
else if (name.compareTo(other.name) == 1) {
return 1;
}
else if (name.compareTo(other.name) == 0) {
return 0;
} else return ...
}
BTW, I'm not sure if I'm following the logic of your implementation, since it seems that you are returning 0 if dateSubmitted != other.dateSubmitted. compareTo should also be anti-symetric (i.e. sgn(x.compareTo(y)) == -sgn(y.compareTo(x))), but your implementation is not.
How can you be sure (with all these if and else) that you are always returning an int? It does not seem so obvious to me and aparently the compiler agrees with me too.
One way to solve this (probably not the best one) is to add a return -1; //or whatever value at the end of your function.
In your second else-if statement you have a code path that may not return anything. You say:
else if ((dateSubmitted == other.dateSubmitted) && (files == other.files)) {
if (name.compareTo(other.name) == -1) {
return -1;
}
else if (name.compareTo(other.name) == 1) {
return 1;
}
else if (name.compareTo(other.name) == 0) {
return 0;
}
, but what if none of those else if's are true? Try changing the last else-if in your second else-if statement to else.
You are missing an else after this branch:
else if (name.compareTo(other.name) == 0) {
return 0;
}
If the test fails (compareTo doesn't return 0) the method would have to exit without a return value, which is illegal in Java.
Also, compareTo may return any integer value, not only 0, 1, and -1.
The method should return appropriate value on all code flow paths; in other words, on all conditions when the method returns. In the following if block it does not return on one path that I've marked.
else if ((dateSubmitted == other.dateSubmitted) && (files == other.files)) {
if (name.compareTo(other.name) == -1) {
return -1;
}
else if (name.compareTo(other.name) == 1) {
return 1;
}
else if (name.compareTo(other.name) == 0) {
return 0;
}
// It should return something here, if none of the above "if" statements match.
// Or one of the above "else if" should be changed to "else"
}

Categories