Anti-pattern:
An anti-pattern (or antipattern) is a common response to a recurring problem
that is usually ineffective and risks being highly counterproductive. The term,
coined in 1995 by Andrew Koenig, was inspired by a book, Design Patterns, in
which the authors highlighted a number of design patterns in software
development that they considered to be highly reliable and effective.
— source http://en.wikipedia.org/wiki/Anti-pattern
Here at Schuberg we spend quite some time going through bugs reports from
automated scanners, you have probably seen the mails coming by on the ML. As
part of our work we have encountered a number of problems that keep on popping
up in the code base. So here is my first attempt to clarify why a certain
pattern is wrong and hopefully help developers to avoid this.
So first up is the equality operator, ==. This operator is commonly used in
many languages to compare if two items are equal. The trick with this operator
in java is to know exactly what you are comparing, because it matters.
Consider this piece of code:
public class App
{
public static void main(String[] args)
{
int a = 1;
int b = 1;
if (a == b) {
System.out.println("Equal!");
} else {
System.out.println("Different!");
}
}
}
The expected outcome is “Equal!” and indeed it prints just that. Now consider
the following code:
public class App
{
public static void main(String[] args)
{
Integer a = new Integer(1);
Integer b = new Integer(1);
if (a == b) {
System.out.println("Equal!");
} else {
System.out.println("Different!");
}
}
}
The result of running this bit of code is “Different!”. With == you are telling
the java compiler to compare the two variables. The variable are references to
Objects, so it will do exactly what you tell it to do, compare the two object
references. As you give it two different objects, the result willl be
“Different!”. The correct way of comparing the contents of two objects is to
use the equals method. Consider the following piece of code:
public class App
{
public static void main(String[] args)
{
Integer a = new Integer(1);
Integer b = new Integer(1);
if (a.equals(b)) {
System.out.println("Equal!");
} else {
System.out.println("Different!");
}
}
}
This will again be “Equals!”.
Why is this often a problem? There are a lot or reasons why these bugs came to
exist in CloudStack (or any other project). For example somebody might cause
this bug by changing the return type of a function from long to Long. The first
one is a primitive which can be compared with == and the second one is an
Object which might result in another comparison than you intended. Findbugs
will catch these types of comparisons and warn you for them. See commit
d1efdca50622a0b67ae1a286aad3297b1c748e9e for an example.
Oh and what does this print?
public class App
{
public static void main(String[] args)
{
Integer a = 1;
Integer b = 1;
if (a.equals(b)) {
System.out.println("Equal!");
} else {
System.out.println("Different!");
}
}
}
Surprise!, it prints “Equals!”. This is a boxed integer and java keeps a pool
of these so internally the object is cached and both a and b get the same
objects assigned to them by the internal boxing logic. Just never rely on this!
It only works in specific cases and is implementation specific per JVM vendor
and JVM version.
Cheers,
Hugo
P.S. If you have another anti pattern feel free to post em in this thread.