The values of boxed primitives cannot be compared using the == and != operators by default. This is because these are interpreted as reference comparison operators.
This noncompliant example (adopted from \[[Bloch 09|AA. Java References#Bloch 09]\]), defines a {{Comparator}} with a {{compare()}} method. The {{compare()}} method accepts two boxed primitives as arguments. Note that primitive integers are also accepted by this declaration as they are appropriately autoboxed. The main issue is that the {{==}} operator is being used to compare the two boxed primitives. This however, compares their references and not the actual values. |
static Comparator<Integer> cmp = new Comparator<Integer>() {
public int compare(Integer i, Integer j) {
return i < j ? -1 : (i == j ? 0 : 1);
}
};
|
To be compliant, use any of the four comparison operators <, >, <= and >=. The == and != operators should not be used to compare boxed primitives.
public int compare(Integer i, Integer j) {
return i < j ? -1 : (i > j ? 1 : 0) ;
}
|
Sometimes a list of integers is desired. Recall that the type parameter inside the angle brackets of a list cannot be of a primitive type. It is not possible to form an ArrayList<int>. With the help of the wrapper classs and autoboxing, storing primitive integer values in ArrayList<Integer> becomes possible.
In this noncompliant code example, it is desired to count the integers of arrays list1 and list2. As class Integer can only cache integers from -127 to 128, when an int number is beyond this range, it is autoboxed into the corresponding wrapper type. The == operator returns false when these distinct wrapper objects are compared. As a result, the output of this example is 0.
import java.util.ArrayList;
public class Wrapper {
public static void main(String[] args) {
// Create an array list of integers, where each element
// is greater than 127
ArrayList<Integer> list1 = new ArrayList<Integer>();
for(int i=0;i<10;i++)
list1.add(i+1000);
// Create another array list of integers, where each element
// is the same as the first list
ArrayList<Integer> list2 = new ArrayList<Integer>();
for(int i=0;i<10;i++)
list2.add(i+1000);
int counter = 0;
for(int i=0;i<10;i++)
if(list1.get(i) == list2.get(i))
counter++;
// print the counter
System.out.println(counter);
}
}
|
If it were possible to expand the cache inside Integer (cache all the integer values -32K-32K, which means that all the int values may be autoboxed to the same Integer object), then the results may have differed.
This compliant solution uses the equals() method for performing comparisons of wrapped objects. It produces the correct output 10.
public class TestWrapper1 {
public static void main(String[] args) {
// Create an array list of integers, where each element
// is greater than 127
ArrayList<Integer> list1 = new ArrayList<Integer>();
for(int i=0;i<10;i++)
list1.add(i+1000);
// Create another array list of integers, where each element
// is the same as the first one
ArrayList<Integer> list2 = new ArrayList<Integer>();
for(int i=0;i<10;i++)
list2.add(i+1000);
int counter = 0;
for(int i=0;i<10;i++)
if(list1.get(i).equals(list2.get(i))) counter++;
System.out.println(counter);
}
}
|
Using the equal and not equal operators to compare boxed primitives can lead to erroneous comparisons.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
EXP32- J |
low |
likely |
medium |
P6 |
L2 |
TODO
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
\[[Bloch 09|AA. Java References#Bloch 09]\] 4. "Searching for the One" \[[Pugh 09|AA. Java References#Pugh 09]\] Using == to compare objects rather than .equals |
EXP31-J. Avoid side effects in assertions 03. Expressions (EXP) 04. Scope (SCP)