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

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.

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.

How to show !equals in if statement (Java)? [duplicate]

This question already has answers here:
How can I express that two values are not equal to eachother?
(4 answers)
Closed 8 years ago.
How is it possible to show if it's not equal (!=, something like this maybe) in an if statement?
For example:
for (int g = 0; g < doglist.size(); g++){
if(doglist.get(g).equals(name)){
System.out.println("There is no dog with that name: ");
}
}
So in this code I want to print the message if the entry in the list is not equal to name. So instead of equals(name) I'll have to use something different. How is this possible?
You can use the NOT operator ! with appropriate parentheses for clarity (though not strictly required).
if (!(condition))
so in your case....
if(!(doglist.get(g).equals(name)))
You should write
if (!doglist.get(g).equals(name))
About your idea of using !=: For primitive data types, yes, it's correct to test equality using !=. .equals() is for object data types. However, applying != to an object would be testing whether the memory location of the operands is the same, which is not the relevant information. .equals() is what tests for whether the objects are actually equal.
For example, when comparing ints (a primitive type), you would use !=:
int a = 0, b = 1;
if (a != b) doSomething(); //Calls the method
Primitive types do not recognize the .equals() method at all. But if you want to compare Strings (an object type), you would use !<object>.equals():
String s1 = "Hello", s2 = "World";
if (!s1.equals(s2)) doSomething(); //Calls the method
If you used != with an object, it would compile, but likely would not produce the desired output:
String s1 = "Hello!";
String s2 = "Hello!"; //Make a new object with the same data -- contains "Hello!"
if (s1 != s2) doSomething(); //Will run doSomething(), even though s1.equals(s2)

Using Arraylist in Java

I have a problem using Arraylists in java my code looks something like this:
List<Integer> numbers1 = new ArrayList<>();
List<Integer> numbers2 = new ArrayList<>();
boolean bcompare;
I add to the lists the same numbers, but when i try to compare the numbers of the index 0 of the lists like this the result of the boolean is false when it should be true:
bcompare = numbers1.get(0)==numbers2.get(0);
bcompare is false
But here is the thing when I use some temp variables and then compare them it gives me what i expected, a true value on bcompare:
int a=numbers1.get(0);
int b=numbers2.get(0);
bcompare = a==b;
bcompare is true
What am I doing wrong here?
It is cause you use the wrapper classes Integer. So an == compares the "references".
Use the equals() method instead to compare values of objects:
bcompare = numbers1.get(0).equals(numbers2.get(0));
The second comparison is true, because a int is a primitive type and contains only the value.
Have a look at http://mindprod.com/jgloss/intvsinteger.html for more details about the difference between int and Integer
When compare the results of get, you are comparing Integers. Using ==, this will compare the two object references to see if they are the same reference. With the exception of Integer caching, this will be false.
When you first assign the numbers to int, Java unboxes the Integer to int, so that == can compare the primitive values directly. This works as you intended.
Use the last code which uses int values.
return type of get() method is Object so when you are comparing like this
bcompare = numbers1.get(0).equals(numbers2.get(0));
It compares the reference of two different object so giving false.
either use equals() method or downcast it to the Integer class.
Using equals() method is good idea out of these both.
As,others have already said bcompare = numbers1.get(0)==numbers2.get(0); compares references of 2 Integer objects (which are not same, so, it will be false). int a=numbers1.get(0); extracts the int value from Integers ( by calling integer.intValue() implicitly) and compares them so, a==b; will be true.
Byte code :
public static void main(java.lang.String[]);
*** some code here***
30: if_acmpne 37 // byte code instruction to compare references
49: invokevirtual #27 // Method java/lang/Integer.intValue:()I
*** some other code here **

How to compare Integer correctly in Java [duplicate]

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.

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