Professional Documents
Culture Documents
Equality and Comparison in Java - Pitfalls and Best Practices PDF
Equality and Comparison in Java - Pitfalls and Best Practices PDF
You have 2 free stories left this month. Sign up and get an extra one for free.
Before we can learn about the pitfalls and best practices of equality and
comparison in Java, we need to understand the different kinds of types
and their behavior.
. . .
Primitives
Primitives in Java can’t be uninitialized or null , they always have a
default value. It represents 0 , suitable for the specific data type:
Ability to be null.
etc.
Our List uses the wrapper type Integer , but our code compiles even
though we add an int . That's possible thanks to the compiler changing
our code by autoboxing the i:
Even though we use operators like % and + that aren't available to the
object type Integer , the code compiles fine. Because the compiler
unboxes the wrapper type. The actual compiled code looks more like this:
. . .
Equality
If we look at other programming languages, the most logical conclusion
for how to compare values might be the == operator and its antagonist
!= .
Yes, we can use them to check for equality, and they compare values
against each other, but it might not be the value you're expecting.
Primitives
Primitives are literals, fixed values in memory, that can be tested for
equality with == .
In contrast to the other primitive data types, the floating-point data types
float and double can't reliably be checked for equality with == , due to
their storage method in memory. They aren't exact values:
Arrays
Another pitfall is primitive arrays, because arrays aren’t a primitive type,
they’re objects.
Objects
If you compare objects with == , it will also compare the value of the
object. The only problem here is that the value of an object is actually its
reference, hence the name object reference type.
This means two values are only equal if they point to the same object in
memory.
String a = "a";
String b = "b";
String ab = "ab";
The compiler and the JVM might optimize string constants, so result2 is
true . And result3 is false because a + b creates a new object in
memory. All of this can be implementation-dependent and differ
between different JVMs.
1 Integer a = 127;
2 Integer b = 127;
3 Integer c = 128;
4 Integer d = 128;
5 boolean equal = (a == b); // true
6 boolean notEqual = (c == d); // false
7 boolean equalAgain = (new Integer(128) == 128); // true
actually cache values for specific ranges (-128 to 127), making a and b
the same object, but not c and d . And thanks to unboxing, equalAgain is
true .
true .
Hash code: Equal objects must have the same hash code.
1 class MyClass {
2 private final String title;
3 private final Integer value;
4 public MyClass(String title, Integer value) {
5 this.title = title;
6 this.value = value;
7 }
8 @Override
9 public boolean equals(Object obj) {
10 // Reflexive
11 if (this == obj) {
12 return true;
13 }
14 // Null-handling
15 if (obj == null) {
16 return false;
17 }
18 // Different types can't be equal
19 if (getClass() != obj.getClass()) {
20 return false;
21 }
22 MyClass other = (MyClass) obj;
23 // Let the helper do the rest
24 return Objects.equals(this.title, other.title) && //
25 Objects.equals(this.value, other.value);
26 }
27 @Override
28 public int hashCode() {
29 return Objects.hash(this.title,
30 this.value);
31 }
32 }
Of course, we can design our objects that even subclasses are equal to
their parents. But the definition of equality must be the same for both,
the hash code calculation must occur in the base class.
. . .
Comparison
Just testing for equality is seldom enough. The other significant kinds of
operations are comparisons of values.
Primitives
Like in other languages, we can compare the values of primitives with the
< , > , <= , and >= operator.
java.lang.Comparable<T>
Objects don’t support these operators. To compare object types we need
to implement the interface java.lang.Comparable<T> with its single
method int compareTo(T) .
The result represents the natural order of our type, not just arithmetical
comparability. This way, we can make collections of our type sortable.
. . .
Best Practices
There are some simple rules we should follow not to get the wrong
results when comparing values for equality or their natural order.
Be aware of autoboxing/unboxing
Because the compiler does this behind the scenes, we must be sure to
compare primitives, or wrapper objects, thanks to Integer / Long caching.
. . .
Resources
Primitive data types (Oracle)
Autoboxing (Oracle)
Comparable<T> (Oracle)
146 claps
WRIT T EN BY
Reusable Vue / Vuetify Optionals in Swift What is Binary Search? A Layman’s Introduction
components Explained: 5 T hings You Vaishali T hakur to Recursion
Nick Pate Should Know Darrow Palast in Better
Antoine van der lee in Programming
Better Programming
So how does the Blueshift by QuantInsti: How to test Clojure Empower a Lightweight
backend work anyway? A powerful new tool for systems using di erent Python Data Structure:
Stephanie Zou in T he Startup algorithmic trading seam techniques From Tuples to
McKlayne Marshall Daniel Zurawski in T he Namedtuples
Startup Yong Cui, Ph.D. in T he Startup