How to compare Integer correctly in Java [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Integer wrapper class and == operator - where is behavior specified?
I known Java integer use cache in -127~128.
If
Integer i = 1;
Integer j = 1;
Integer m = 128;
Integer n = 128;
i == j // true
m == n // false
But I met a strange phenomenon.First,look at following snippet.
List<CustomerNotice> customerNotice = findByExample(example); // use Hibernate findByExample method
for(CustomerNotice n : customerNotice){
if(n.getConfirmStatus() == NoticeConfirmStatus.UNCONFIRMED.getValue()){
// do sth
}
}
public enum NoticeConfirmStatus{
UNCONFIRMED(1), //
CONFIRMED(2), //
FAILED_TO_CONFIRM(3); //
private final Integer value;
private NoticeConfirmStatus(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}
public class CustomerNotice {
#Column(name = "CONFIRM_STATUS")
private Integer confirmStatus;
public Integer getConfirmStatus() {
return this.confirmStatus;
}
public void setConfirmStatus(Integer confirmStatus) {
this.confirmStatus = confirmStatus;
}
}
Although the if expression is not recommended, I think it will be return true,because n.getConfirmStatus()==1, but the result is false.I'm very confusing.
In addition, theList<CustomerNotice> customerNotice acquired by Hibernate findByExample method. Is there some Autoboxing or new operation when retrieve the resultset?
Thank you.

SHORT: (answers question)
If you want to compare Integers as the objects, you should use .equals:
i.equals(j);
m.equals(n);
With this, they should both return true. But if you really want to use ==, you need to get the primitive int value:
i.intValue() == j.intValue();
m.intValue() == j.intValue();
LONG: (explains answer)
The basis of this is that Objects are always stored separately in memory (except for some special cases like m=n), and to be compared properly, they need to be broken down into primitive types that can be compared successfully using ==.
Every Object has a .equals() method, which is inherited from Object as its superclass. However, it must be overridden to do a proper comparison. Integer overrides this method to compare to Integer objects successfully, while using == checks to see if both objects point to the same space in memory, and because two instances of an Object cannot point to the same space in memory, this will always return false.
However, as your code points out, there are some special cases that work, like these:
Your code uses a Integer i = 1, which is considered a "standard instance" and is able to be compared using ==.
If you set one Object equal to another using =, Java tells both objects to point to the same location in memory, which means that == will return true.
There are many others, but those are the two that come to mind and seem relevant.

You'll drive yourself crazy and waste a lot of time trying to figure out specific cases where this works or does not work. It depends on the implementation of code which isn't always visible to you.
The bottom line: never, ever, use == to compare Integer instances, period. As you have seen, it works sometimes, under some circumstances, and fails miserably the rest of the time. If you have a method that returns an Integer, then assign the value to an int, and then you can use == to compare that int to another int.

Related

Java Map Value Equality [duplicate]

This question already has answers here:
Comparing Integer objects vs int
(5 answers)
Closed 6 years ago.
While writing a graph algorithm, I saw that this -
Definition:
Map<Integer, Integer> componentNames = new HashMap<Integer, Integer>();
CASE I:
if (componentNames.get(A) == componentNames.get(B)) {
System.out.printn("Hi");
}
Does not print anything.
CASE II:
int componentNameA = componentNames.get(A);
int componentNameB = componentNames.get(B);
if (componentNameA == componentNameB) {
System.out.printn("Hi");
}
Prints "Hi"
I have printed to check the values. And, they were indeed same.
This is the first time I have seen strange behavior for Java.
What could be the reason for this?
CASE I:
if (componentNames.get(A) == componentNames.get(B)) {
System.out.printn("Hi");
}
The code doesn't enter the if condition because you are trying to compare two Integer references using == which will only return true if the LHS and RHS refer to the same object. In your case, it is safe to assume that componentNames.get(A) and componentNames.get(B) both return a reference to a separate Integer object.
It would be helpful to know that the JVM caches the values for wrapper classes and it is quite possible that the above if condition may be true if the JVM has cached the int value returned by componentNames.get(A) and componentNames.get(B). The JVM used to cache Integer values ranging between -128 to 127 but modern JVMs can cache values greater than this range as well.
int componentNameA = componentNames.get(A);
int componentNameB = componentNames.get(B);
if (componentNameA == componentNameB) {
System.out.printn("Hi");
}
The code enters condition because you are unboxing an Integer into an int and the comparison is done between two primitive values.
In general, two references when compared using == will only return true if both the references point to the same object. Therefore, it is advisable to compare two references using equals if you are checking for equality and compare them using == if you are looking to check for identity.
CASE 1:
componentNames.get(A) and componentNames.get(B) are references / pointers of two different instances of Integer Class.
So, componentNames.get(A) == componentNames.get(B) is false.
CASE 2:
int componentNameA and int componentNameB are int type variables.
As they both contain same value, componentNameA == componentNameB is true.

why Comparator<Integer[]> throws exception? [duplicate]

This question already has answers here:
Java: Integer equals vs. ==
(7 answers)
Closed 7 years ago.
I got an exception
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
at java.util.TimSort.mergeAt(TimSort.java:485)
at java.util.TimSort.mergeCollapse(TimSort.java:408)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at Main.main(Main.java:64)
when using this code :
Arrays.sort(arr, new Comparator<Integer[]>(){ //arr is 2D array
public int compare(Integer[] o1, Integer[] o2){
return o1[2]==o2[2]?0:o1[2]>o2[2]?1:-1;
}
});
which I believe is related to not satisfying transitivity of comparison, but when I made a little change like this :
Arrays.sort(arr, new Comparator<Integer[]>(){ //arr is 2D array
public int compare(Integer[] o1, Integer[] o2){
return o1[2].compareTo(o2[2]); // here is the change
}
});
the exception is no longer generated.
I can't understand an explanation of this issue as I'm sure that the Integer instance can be compared using relational operators (>, <, =) besides compareTo() method
Integer x = 1;
Integer y = 2;
System.out.println(x<y);
prints true as expected
can any body clarify ?
The problem is with:
o1[2]==o2[2]
This is comparing the Integers for identity. Equal instances are not necessarily identical. For example:
Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a == b); // False, instances are not identical.
System.out.println(a.equals(b)); // True, instances are equal.
It should be:
o1[2].equals(o2[2])
Or, to handle o1[2] being null:
Objects.equal(o1[2], o2[2])
since you are using Integer and not int, this is not valid:
o1[2]==o2[2]?0:o1[2]>o2[2]?1:-1;
you need to use equals or compareTo, not ==
The array you are sorting is made up of Integer objects. These are different than just plain old integers.
A plain old integer is just a number sitting in memory.
An Integer object is a an instance of a class that fills the same role as a basic integer, but also has a bunch of methods and data associated with it. That's the difference between being a piece of data or being an object.
The == operator compares numbers in memory. In the case of an instance of an object, it will compare the locations in memory, not the values of the numbers as you intend.
For Integer (and other number-like) objects, you must use the compareTo() method instead.
Your solution here is to either use the compareTo() method as suggested, or change your array to plain old integers.
You could also leave it as Integer objects and then use the Integer.intValue() to get a plain old integer returned, and then you can use the == comparison. But that's quite convoluted, IMO.

Why isn't Integer.MIN_VALUE equal to stored Integer.MIN_VALUE in variable?

I made an Interval class with the following fields:
...
private static final Integer MINF = Integer.MIN_VALUE;
Integer head,tail;
...
when I make an instance of this class, making this.head = Integer.MIN_VALUE, and I want to check if the value of head is equal to MINF, it says that they aren't equal.
Interval i = new Interval(Integer.MIN_VALUE,10);
System.out.println(i.toString()); //[-2147483648,10]
So I went ahead and tried to print the values,
public String toString() {
...
//What the hell?
System.out.println("MINF == Integer.MIN_VALUE: " + (MINF == Integer.MIN_VALUE)); //true
System.out.println("MINF == this.head: " + (MINF == this.head)); //false
System.out.println("Integer.MIN_VALUE == this.head: " + (Integer.MIN_VALUE == this.head)); //true
...
return "*insert interval in format*";
}
Which says
MINF == Integer.MIN_VALUE is true
MINF == this.head is false, although this.head = -2147483648
Integer.MIN_VALUE == this.head is true
Am I missing something for why the second one is false?
Integer is the wrapping class, child of Object and containing an int value.
If you use only the primitive type int, == does a numerical comparison and not an object address comparison.
Mind that Integer.MIN_VALUE of course is an int too.
You are missing the fact that when stored in Integer (that is, you store Integer.MIN_VALUE in two different integers) and using == between them, the comparison is not of the values, but of the objects.
The objects are not identical because they are two different objects.
When each object is compared to Integer.MIN_VALUE, since Integer.MIN_VALUE is an int, the object is autounboxed and compared using int comparison.
No one here has addressed the REASON why they're different objects. Obviously:
System.out.println(new Integer(10) == new Integer(10));
outputs false, for reasons that have been discussed to death in the other answers to this question and in Comparing Integer objects
But, why is that happening here? You don't appear to be calling new Integer. The reason is that:
Integer.MIN_VALUE returns an int, not an Integer.
You have defined MINF to be an Integer
Autoboxing uses valueOf. See Does autoboxing call valueOf()?
valueOf calls new Integer if the int is not in the integer cache,
The cache is only the values -128 -> 127 inclusive.
And that is why you are seeing the "two Integer objects are not == behavior", because of autoboxing. Autoboxing is also why equality does not appear to be transitive here.
You can fix this problem by instead using:
private static final int MINF = Integer.MIN_VALUE;
And, in general: don't use Integer for simple fields.; only use it as a generic type where you actually need the object.
You are using Integer objects. The use of == should be used as a comparison of individual primitive's values only. Since you used the Integer class rather than the primitive int then it is comparing the object's references between the two variables rather than their values.
Because MINF is a separate object to head you are receiving false for a direct comparison using ==.

Comparing two objects in Java

I have two different objects of same entity “Community”
And two objects(community and com) have same values
Communty.java have following variables:
private Integer communityId;
private String communityName;
private String description;
// many to many relationship
private Set<Faculty> faculties = new HashSet<Faculty>();
private Set<User> users = new HashSet<User>();
and I used equal method as:
#Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj==null)
return false;
if(obj==this)
return true;
if(!(obj instanceof Community)) return false;
Community community = (Community)obj;
return community.getCommunityId() == this.getCommunityId();
}
When I checked community==com , it returns false .. why? What mistake I have done? Both the objects are retrieved from the database!
== compares links to the objects.
You should explicitly call community.equals(com). Also take care of the null checks.
Because you're comparing objects (the IDs) using == rather than equals(). == tests if both variables reference the same object. equals() tests if the two variables reference two functionally equal integers (i.e. with the same int value).
It's almost always a bug to compare objects using ==, except for enums.
== compares the two references which may be pointing to two different locations irrespective of the object content.
You should use community.equals(com) to check for equality'
Also, your equals method contains the following segment :
community.getCommunityId() == this.getCommunityId()
as communityId is an Integer object, the == operator may give negative result for integer values which are not in the range [-127, 128] due to interning, thats a separate concept, you can check it later.
You need to use equals() there as well or compare the .intValue()
return community.getCommunityId().equals(this.getCommunityId())
Because, they don't refer same object. == used to check, whether both referring same object.
== for object refer to same.
equals content equivalency.
try this
return community.getCommunityId().equals(this.getCommunityId());
The problem of your equals method is that you are using == operator for Objects. And here the CommunityId must be the same object in order to return true:
return community.getCommunityId() == this.getCommunityId();
It should be
return community.getCommunityId().equals(this.getCommunityId());
When I checked community==com , it returns false .. why
This means; are these two references exactly the same. i.e. to the same object. What you intended was
boolean equal = community.equals(com);
BTW Your if (obj == null) check is redundant.
== operator in Java compares the memory address of the two objects,in your case comm and community must be two different objects stored at two different memory addresses
You are comparing two distinct objects communityId's.
is it necessary to declare communityId as Integer? because Integer is an object.
Why don't you simply declare communityId with a primitive type int;
int communityId should work.

Comparing two identical strings with == returns false [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I am making an archive for my family. There are no syntax errors, however whenever I type in "Maaz", it evaluates realName == "Maaz" to false and goes to the else statement.
import java.util.Scanner;
public class MainFamily {
public static void main (String [] args) {
System.out.println("Enter you're name here");
Scanner name = new Scanner(System.in);//Scanner variable = name
String realName;
realName = name.nextLine();//String variable = user input
System.out.println("Name: "+ realName);
if (realName == "Maaz") {
System.out.println("Name: Maaz");
} else {
System.out.println("This person is not in the database");
}
}
}
TL;DR
You wrote (this doesn't work):
realName == "Maaz"
You meant this:
realname.equals("Maaz")
or this:
realname.equalsIgnoreCase("Maaz")
Explanation
In Java (and many other Object-Oriented programming languages), an object is not the same as a data-type. Data-types are recognized by the runtime as a data-type.
Examples of data-types include: int, float, short.
There are no methods or properties associated with a data-type. For example, this would throw an error, because data-types aren't objects:
int x = 5;
int y = 5;
if (x.equals(y)) {
System.out.println("Equal");
}
A reference is basically a chunk of memory that explicitly tells the runtime environment what that data-block is. The runtime doesn't know how to interpret this; it assumes that the programmer does.
For example, if we used Integer instead of int in the previous example, this would work:
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x.equals(y)) {
System.out.println("Equal");
}
Whereas this would not give the expected result (the if condition would evaluate to false):
Integer x = new Integer(5);
Integer y = new Integer(5);
if (x == y) {
System.out.println("Equal");
}
This is because the two Integer objects have the same value, but they are not the same object. The double equals basically checks to see if the two Objects are the same reference (which has its uses).
In your code, you are comparing an Object with a String literal (also an object), which is not the same as comparing the values of both.
Let's look at another example:
String s = "Some string";
if (s == "Some string") {
System.out.println("Equal");
}
In this instance, the if block will probably evaluate to true. Why is this?
The compiler is optimized to use as little extra memory as is reasonable, although what that means depends on the implementation (and possibly runtime environment).
The String literal, "Some string", in the first line will probably be recognized as equivalent to the String literal in the second line, and will use the same place in memory for each. In simple terms, it will create a String object and plug it into both instances of "Some string". This cannot be relied upon, so using String.equals is always a better method of checking equivalence if you're only concerned with the values.
do this instead
if (realName.equals("Maaz"))
equals() should be used on all non-primitive objects, such as String in this case
'==' should only be used when doing primitive comparisons, such as int and long
use
if(realName.equals("Maaz"))
use == with primitive data type like int boolean .... etc
but if you want to compare object in java you should use the equals method
You have to compare objects with realName.equals ("Maaze"), not with ==.
It is best practice to compare Strings using str.equals(str2) and not str == str2. As you observed, the second form doesn't work a lot of the time. By contrast, the first form always works.
The only cases where the == approach will always work are when the strings are being compared are:
string literals or references to string literals, or
strings that have been "interned" by application-level code calling str = str.intern();.
(And no, strings are not interned by default.)
Since it is generally tricky to write programs that guarantee these preconditions for all strings, it is best practice to use equals unless there is a performance-related imperative to intern your strings and use ==.
Before that you decide that interning is a good idea, you need to compare the benefits of interning with the costs. Those costs include the cost of looking up the string in the string pool's hash table and the space and GC overheads of maintaining the string pool. These are non-trivial compared with the typical costs of just using a regular string and comparing using equals.
You can also use
realname.equalsIgnoreCase("Maaz")
This way you can accept Maaz, maaz, maaZ, mAaZ, etc.
== tests shallow equality. It checks if two objects reference the same location in memory.
Intriguing. Although, as others have stated, the correct way is to use the .equals(...) method, I always thought strings were pooled (irrespective of their creation). It seems this is only true of string literals.
final String str1 = new String("Maaz");
final String str2 = new String("Maaz");
System.out.println(str1 == str2); // Prints false
final String str3 = "Laaz";
final String str4 = "Laaz";
System.out.println(str3 == str4); // Prints true
Since you are working on strings, you should use equals to equalsIngnorecase method of String class. "==" will only compare if the both objects points to same memory location, in your case, both object are different and will not be equal as they dont point to same location. On the other hand, equals method of String class perform a comparison on the basis of the value which objects contains. Hence, if you will use equals method, your if condition will be satisfied.
== compares object references or primitive types (int, char, float ...)
equals(), you can override this method to compare how both objects are equal.
for String class, its method equal() will compare the content inside if they are the same or not.
If your examples, both strings do not have the same object references, so they return false, == are not comparing the characters on both Strings.
It seems nobody yet pointed out that the best practice for comparing an object with a constant in Java is calling the equals method of the constant, not the variable object:
if ("Maaz".equals (realName)) {}
This way you don't need to additionally check if the variable realName is null.
if(realName.compareTo("Maaz") == 0) {
// I dont think theres a better way do to do this.
}

Categories