IntelliJ IDEA Reporting Contract Violation Warning - java

Here is the Java code:
public static boolean anyEqual(Object needle, Object... haystack) {
if(needle == null || haystack == null) {
return false;
}
if(haystack.length == 0) {
return false;
}
for(Object match : haystack) {
if(match != null && needle.getClass() == match.getClass() && needle.equals(match)) {
return true; // warning from IntelliJ here, 'contract clause !null, null -> false is violated'
}
}
return false;
}
Does anyone have any idea why this is being shown? contract clause !null, null -> false is violated? Thanks!
IntelliJ 14.0.2 build: 139.659
Screenshot:

IntelliJ is inferring the formal contract of your method to be this:
null, _ -> false; !null, null -> false
What this actually means:
The first contract specifies that, so long as the first parameter is null, it will return false. This is observed by your first if statement:
if(needle == null || haystack == null) {
return false;
}
The second contract specifies that, if the second parameter is null, then it will return false. This is also specified by the same if statement above.
My gut is telling me that IntelliJ is having some trouble discerning what the loop's formal contract is in addition to all of the above, although it'd be as simple as another condition in the contract expression.
for(Object match : haystack) {
if(match != null && needle.getClass() == match.getClass() && needle.equals(match)) {
return true;
}
}
Let's briefly go through this.
The enhanced-for statement won't fire if haystack is of length 0, so that's something to take into consideration.
The elements inside of the array could be null, and I'm not entirely sure that IntelliJ's static analysis covers that piece yet.
We've established already that needle must be non-null, so there's nothing violating the contract at that line.
If we have a scenario in which match != null && needle.getClass() == match.getClass() && needle.equals(match) is true, we return true. Otherwise, we return false.
There's nothing that I can see in the formal documentation that gives us the expression we require to say, "hey - we're checking elements of an array!"; it may be the case that the analysis is tripping up on the fact that we're returning true in spite of what we stated above (since haystack is non-null).
Allow me to stress this point:
haystack has to be non-null in order for you to enter into the enhanced-for. Your code will not work otherwise.
All in all, I wouldn't worry about it. Better yet, file a bug against it so that this sort of thing could be fixed or expanded upon.

This looks like an IntelliJ bug to me, since by removing the static keyword from the method the warning disappears.
Something must be confusing the static analysis here. One can always submit this to youtrack so jetbrains devs can look at it.
Someone already reported this issue Here
(tested on v14.0.3)

This message is being shown because IntelliJ checks for method contract violations. It's a relatively new feature, read more at https://www.jetbrains.com/idea/features/annotation_java.html

Related

Why does Intellij idea warn about nullpointer in that if condition?

Here is my code
if (!multipartFile.isEmpty() && multipartFile.getOriginalFilename() != null && !multipartFile.getOriginalFilename().isBlank()) {
String fileName = StringUtils.cleanPath(multipartFile.getOriginalFilename());
dishCreationDto.setImageFileName(fileName);
dishService.saveWithFile(dishCreationDto, multipartFile);
} else {
dishService.save(dishCreationDto);
}
Here is how I see that code
As you can see, the last part of IF condition is underlined as Idea thinks that getOriginalFilename can return null, but I've checked this with that line of a code
multipartFile.getOriginalFilename() != null. What am I doing wrong?
Idea thinks that getOriginalFilename can return null
Because it can.
but I've checked this with that line of a code multipartFile.getOriginalFilename() != null
You checked that the previous invocation did not return null. The next one still can.
What am I doing wrong?
Calling a method twice in rapid succession, instead of storing its result in a variable and using that one for the check and the further processing. In fact you then call it for a 3rd time.
(this was just a copy of my comment from above)
While there may be ways to simplify the condition as the other answer shows, as you also need the result of getOriginalFilename() inside the if, I would assume the IDE will complain about that one next, and at the end you will probably have to bite the bullet and have a variable for it:
String originalFilename = multipartFile.getOriginalFilename();
if (!multipartFile.isEmpty() && originalFilename != null && !originalFilename.isBlank()) {
String fileName = StringUtils.cleanPath(originalFilename);
dishCreationDto.setImageFileName(fileName);
dishService.saveWithFile(dishCreationDto, multipartFile);
} else {
dishService.save(dishCreationDto);
}
You could simplify that expression by using the StringUtils:
!StringUtils.isNullOrEmpty(multipartFile.getOriginalFilename())
There are other functions in that utility class that might be helpful depending on what you're trying to do.
IntelliJ isn't always right but is always good to look a bit more in detail to our code to see what can be improved/simplified for better debugging/readability.

Reducing conditions within a if statement

I have a code snippet as below. Here there is a nested if else loop as well as multiple conditions [all different parameters]. What is the best way to optimize this.
if(request!=null && !StringUtils.isBlank(request)) {
if(request.getFirstName()!=null && !StringUtils.isBlank(request.getFirstName())
&& request.getLastName()!=null && !StringUtils.isBlank(request.getLastName())
&& request.getAge()!=null && !StringUtils.isBlank(request.getAge())
&& request.getAddress()!=null && !StringUtils.isBlank(request.getAddress())
&& request.getPhoneNumber()!=null && !StringUtils.isBlank(request.getPhoneNumber())) {
return true;
}else {
return false;
}
}else {
return false;
}
I had thought of using switch case and for loop as well but all the conditions are based on different variables, I didn't see it as compatible.
StringUtils from commons-lang already has a method which accepts an array of Strings. It will check for null or empty or blank strings. So all your checks boil down to:
return !(request == null || StringUtils.isAnyBlank(
request.getFirstName, request.getLastName,
request.getAge, request.getPhoneNumber));
You can try StringUtils.isAnyBlank(). Please refer attached link.
isAnyBlank : https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#isAnyBlank-java.lang.CharSequence
If you don't use commons-lang dependency you can simply use Stream API (Java 8+)
Boolean allNonBlank = Stream.of(
request.getFirstName(),
request.getLastName(),
request.getAge(),
request.getPhoneNumber())
.allMatch(it -> it != null && !String.isBlank(it));
You have a few syntax errors
You are passing request to StringUtils but it doesn't appear to implement CharSequence
You are using !! instead of !
You invocation of the get methods does not include the () to mark it as methods.
Although not an error, you do not need nested if-statements here. Using unnecessary if-else-blocks can make it harder to decipher what the code is doing. It can, however, allow for comments to describe why certain conditions are being checked or whatever. None of that seems relevant here. In fact, you can pass the result of the boolean operation without any if-statement. Using if-statements that return true or false looks like this.
if (<condition-is-true?>) return true
else return false;
Which can be simplified to...
return <condition-is-true?>;
Further, assuming you are using using Apache StringUtils, you do not need to check for null first - the isEmpty(CharSequence) method does that. Additionally, StringUtils includes the isAnyEmpty(CharSequence...) method so you can pass all of the Strings at once.
return request != null && !StringUtils.isAnyEmpty(
request.getFirstName(),
request.getLastName(),
request.getAge(),
request.getAddress(),
request.getPhoneNumber());

Difference between ()->object.method() and object::method when it comes to null object [duplicate]

This question already has answers here:
java.lang.NullPointerException is thrown using a method-reference but not a lambda expression
(2 answers)
Closed 3 years ago.
I work with some legacy code that goes back decades and has a lot of objects where a field being null means "we don't have that information". As such, it has a lot of methods where it wants to do some math on fields, but only if they are not null. This leads to many ugly if statements that look like a procession of null checks, and happen multiple times per method for various length sets of things that can't be null if the contents are going to be used.
For example
public class Foo
{
public Bar getBar()
{
//returns a Bar object that may or may not be null
}
}
Then, elsewhere
if(foo1 != null && foo1.getBar() != null && foo2 != null && .... etc) {
//do math with foo1.getBar(), foo2.getBar(), etc...
}
Anywho, I made a utility to help make these look a little nicer (and also quiet down SonarQube about too many checks in an if) by making a utility class that looks like this:
public class NullCheckUtil
{
private NullCheckUtil()
{}
public static Boolean anyNull(Object... objects)
{
return Stream.of(objects).anyMatch(Objects::isNull);
}
}
Then realized that if foo1 is null, will get NullPointerException before even going in the anyNull.
Ok, lets make it a stream, so they are not evaluated on declaration:
public static Boolean anyNull(Supplier<Object>.... suppliers)
{
return Stream.of(suppliers).map(Supplier::get).anyMatch(Objects::isNull);
}
Then if check can be
if(!NullCheckUtil.anyNull(foo1, foo1::getBar, foo2, foo2::getBar,.... etc){//do the math}
And my IDE seemed happy with that, no problems. But when I ran from console, I'd get NPE with the error claiming to be on the if line again. Whaaaa?
So I did some digging and at first thought maybe this is the reason:
Does Java's ArrayList.stream().anyMatch() guarantee in-order processing?
So I changed the anyNull again to
public static Boolean anyNull(Supplier<Object>... suppliers)
{
for(Supplier<Object> supplier : suppliers)
{
if(supplier == null || supplier.get() == null)
{
return true;
}
}
return false;
}
NOPE, still doesn't fix it (for console).
Experimenting to see what could do it I changed the if to
if(!NullCheckUtil.anyNull(()->foo1, ()->foo1.getBar(), ()->foo2, ()->foo2.getBar(), etc...)
And that works fine in IDE and also in console. Tried both in Java 8.151 and Java 8.221, same behavior.
In other words
try
{
NullCheckUtil.anyNull(()->foo1, ()->foo2, ()->foo1.getBar(), ()->foo2.getBar());
}
catch(NullPointerException npe)
{
//does not happen
}
try
{
NullCheckUtil.anyNull(()->foo1, ()->foo2, foo1::getBar, foo2::getBar);
}
catch(NullPointerException npe)
{
// *DOES* happen. What tha….?
}
So there is some difference between ()->obj.method() and obj::method lambdas in that the latter gets interpreted right away on declaration? What is that?
If the Objects you want to check are always Foo, then you can rewrite the method to:
public static boolean isAnyFooNullOrReturnsAnyGetBarNull(final Foo... foos) {
return Stream.of(foos)
.map(foo -> Objects.IsNull(foo) || Objects.isNull(foo.getBar()))
.reduce(false, Boolean::logicalOr);
}
Ideone example
Notice that this example uses an immutable class Foo. This property is essential since this guarantees that Foo::getBar() for a certain instance will always return the same Bar. If this property is not given, then the problem is not solvable in a streamified solution.
This is also the reason why the attempt of using a Producer<Bar> will not work: the first call to a producer could return a non-null value, while the second call will return a null value. Some classes behave this way, i.e. they allow only a single consumption of a resource/property.
If the parameter of the method has to be Object..., then the problem is not solvable with Streams.
Found older 100% applicable and correct answer after modifying the search terms (i had tried earlier with no luck): java.lang.NullPointerException is thrown using a method-reference but not a lambda expression
It even answers why Eclipse is behaving "nice" (Eclipse bug).

Elegant solution for two Optionals, if one is present the other must not be empty

I look for a more elegant solution of this code:
var first = Optional.ofNullable(a);
var second = Optional.ofNullable(b);
if ((unit.isPresent() && value.isEmpty()) || (value.isPresent() &&
unit.isEmpty())) {
throw new ExpWhatever();
}
Conditions are:
if both optionals are null -> ok, no error/excpt.
if one of the given optionals is present the other must not be empty too (otherwise: excpt.)
Thanks for any ideas or help.
It sounds like it's an error for isPresent() to be true for exactly one of them - so XOR works well:
if (unit.isPresent() ^ value.isPresent()) {
// Throw an exception
}
If you want both optionals to be either present or empty (i.e. they have the same "emptiness" state), you could use this:
if (unit.isPresent() != value.isPresent()) {
//throw an exception
}

Cyclomatic Complexity, joining conditions and readability

Consider the following method (in Java - and please just ignore the content):
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (object == null) {
return false;
}
if (getClass() != object.getClass()) {
return false;
}
if (hashCode() != object.hashCode()) {
return false;
}
return true;
}
I have some plugin that calculates: eV(g)=5 and V(g)=5 - that is, it calculates Essential and common CC.
Now, we can write the above method as:
public boolean equals2(Object object) {
if (this == object) {
return true;
}
if (object == null || getClass() != object.getClass()) {
return false;
}
return hashCode() == object.hashCode();
}
and this plugin calculates eV(g)=3 and V(g)=3.
But how I do understand CC, the values should be the same! CC is not about counting the lines of code, but the independent paths. Therefore, joining two if in one line does not really reduces CC. In fact, it only can make things less readable.
Am I right?
EDIT
Forgot to share this small convenient table for calculating CC quickly: Start with a initial (default) value of one (1). Add one (1) for each occurrence of each of the following:
if statement
while statement
for statement
case statement
catch statement
&& and || boolean operations
?: ternary operator and ?: Elvis operator.
?. null-check operator
EDIT 2
I proved that my plugin is not working well, since when I inline everything in one line:
public boolean equals(Object object) {
return this == object || object != null && getClass() == object.getClass() && hashCode() == object.hashCode();
}
it returns CC == 1, which is clearly wrong. Anyway, the question remains: is CC reduced
[A] 5 -> 4, or
[B] 4 -> 3
?
Long story short...
Your approach is a good approach to calculate CC, you just need to decide what you really want to do with it, and modify accordingly, if you need so.
For your second example, both CC=3 and CC=5 seem to be good.
The long story...
There are many different ways to calculate CC. You need to decide what is your purpose, and you need to know what are the limitations of your analysis.
The original definition from McCabe is actually the cyclomatic complexity (from graph theory) of the control flow graph. To calculate that one, you need to have a control flow graph, which might require a more precise analysis than your current one.
Static analyzers want to calculate metrics fast, so they do not analyze the control flow, but they calculate a complexity metric that is, say, close to it. As a result, there are several approaches...
For example, you can read a discussion about the CC metric of SonarQube here or another example how SourceMeter calculates McCC here.
What is common, that these tools count conditional statements, just like you do.
But, these metrics wont be always equal with the number of independent execution paths... at least, they give a good estimation.
Two different ways to calculate CC (McCabe and Myers' extension):
V_l(g) = number of decision nodes + 1
V_2(g) = number of simple_predicates in decision nodes + 1
If your goal is to estimate the number of test cases, V2 is the one for you. But, if you want to have a measure for code comprehension (e.g. you want to identify methods that are hard to maintain and should be simplified in the code), V1 is easier to calculate and enough for you.
In addition, static analyzers measure a number of additional complexity metrics too (e.g. Nesting Level).
Converting this
if (hashCode() != object.hashCode()) {
return false;
}
return true;
to this
return hashCode() == object.hashCode();
obviously reduces CC by one, even by your quick table. There is only one path through the second version.
For the other case, while we can't know exactly how your plugin calculates those figures, it is reasonable to guess that it is treating if (object == null || getClass() != object.getClass()) as "if a non-null object's class matches then ...", which is a single check and thus adds just one to CC. I would consider that a reasonable shortcut since null checks can be rolled up into "real" checks very easily, even within the human brain.
My opinion is that the main aim of a CC-calculating IDE plugin should be to encourage you to make your code more maintainable by others. While there is a bug in the plugin (that inlined single-line conditional is not particularly maintainable), the general idea of rewarding a developer by giving them a better score for more readable code is laudable, even if it is slightly incorrect.
As to your final question: CC is 5 if you strictly consider logical paths; 4 if you consider cases you should consider writing unit tests for; and 3 if you consider how easy it is for someone else to quickly read and understand your code.
In the second method
return hashCode() == object.hashCode(); costs 0 so you win 1. It's considered as calculation and not logical branch.
But for the first method I don't know why it's cost 5, I calculate 4.
As far as style is concerned, I consider the following the most readable:
public boolean equals(Object object) {
return this == object || (object != null && eq(this, object));
};
private static boolean eq(Object x, Object y) {
return x.getClass() == y.getClass()
&& x.hashCode() == y.hashCode(); // safe because we have perfect hashing
}
In practice, it may not be right to exclude subclasses from being equal, and generally one can not assume that equal hash codes imply equal objects ... therefore, I'd rather write something like:
public boolean equals(Object object) {
return this == object || (object instanceof MyType && eq(this, (MyType) object));
}
public static boolean eq(MyType x, MyType y) {
return x.id.equals(y.id);
}
This is shorter, clearer in intent, just as extensible and efficient as your code, and has a lower cyclomatic complexity (logical operators are not commonly considered branches for counting cyclomatic complexity).

Categories