How does compareTo() in Java work with Lists? [duplicate] - java

What is the difference between returning 0, returning 1 and returning -1 in compareTo() in Java?

Official Definition
From the reference docs of Comparable.compareTo(T):
Compares this object with the
specified object for order. Returns a
negative integer, zero, or a positive
integer as this object is less than,
equal to, or greater than the
specified object.
The implementor must ensure
sgn(x.compareTo(y)) ==
-sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must
throw an exception iff y.compareTo(x)
throws an exception.)
The implementor must also ensure that
the relation is transitive:
(x.compareTo(y)>0 && y.compareTo(z)>0)
implies x.compareTo(z)>0.
Finally, the implementor must ensure
that x.compareTo(y)==0 implies that
sgn(x.compareTo(z)) ==
sgn(y.compareTo(z)), for all z.
It is strongly recommended, but not
strictly required that
(x.compareTo(y)==0) == (x.equals(y)).
Generally speaking, any class that
implements the Comparable interface
and violates this condition should
clearly indicate this fact. The
recommended language is "Note: this
class has a natural ordering that is
inconsistent with equals."
In the foregoing description, the
notation sgn(expression) designates
the mathematical signum function,
which is defined to return one of -1,
0, or 1 according to whether the value
of expression is negative, zero or
positive.
My Version
In short:
this.compareTo(that)
returns
a negative int if this < that
0 if this == that
a positive int if this > that
where the implementation of this method determines the actual semantics of < > and == (I don't mean == in the sense of java's object identity operator)
Examples
"abc".compareTo("def")
will yield something smaller than 0 as abc is alphabetically before def.
Integer.valueOf(2).compareTo(Integer.valueOf(1))
will yield something larger than 0 because 2 is larger than 1.
Some additional points
Note: It is good practice for a class that implements Comparable to declare the semantics of it's compareTo() method in the javadocs.
Note: you should read at least one of the following:
the Object Ordering section of
the Collection Trail in the Sun Java
Tutorial
Effective Java by
Joshua Bloch, especially item 12:
Consider implementing Comparable
Java Generics and Collections by
Maurice Naftalin, Philip Wadler, chapter 3.1: Comparable
Warning: you should never rely on the return values of compareTo being -1, 0 and 1. You should always test for x < 0, x == 0, x > 0, respectively.

I use this mnemonic :
a.compareTo(b) < 0 // a < b
a.compareTo(b) > 0 // a > b
a.compareTo(b) == 0 // a == b
You keep the signs and always compare the result of compareTo() to 0

Answer in short: (search your situation)
1.compareTo(0) (return: 1)
1.compareTo(1) (return: 0)
0.comapreTo(1) (return: -1)

take example if we want to compare "a" and "b", i.e ("a" == this)
negative int if a < b
if a == b
Positive int if a > b

It can be used for sorting, and 0 means "equal" while -1, and 1 means "less" and "more (greater)".
Any return value that is less than 0 means that left operand is lesser, and if value is bigger than 0 then left operand is bigger.

int x = thisObject.compareTo(anotherObject);
The compareTo() method returns an int with the following characteristics:
negative If thisObject < anotherObject
zero If thisObject == anotherObject
positive If thisObject > anotherObject

System.out.println(A.compareTo(B)>0?"Yes":"No")
if the value of A>B it will return "Yes" or "No".

Related

Binary search implementation in Java

if(this.passenger.validatePassengerDetails() && checkEngine() && this.capacity <= 200) {
if(Arrays.binarySearch(airlineClassAir, "flightClass") >=0 && (destination.equals("tx") || destination.equals("ca"))) {
int index = Arrays.binarySearch(airlineClassAir, "flightClass");
int amount = airlineClassPriceAir[index];
double totalAmount = amount + amount* (18/100);
I am trying to understand how the binary search is being implemented here? Can someone explain if(Arrays.binarySearch(airlineClassAir, "flightless") >=0 is trying to do here?
As documented on Arrays.binarySearch(Object[], Object) (emphasis mine):
Returns:
index of the search key, if it is contained in the array; otherwise,
(-(insertion point) - 1). The insertion point is
defined as the point at which the key would be inserted into the
array: the index of the first element greater than the key, or
a.length if all elements in the array are less than the specified
key. Note that this guarantees that the return value will be >= 0 if
and only if the key is found.
In other words, you compare with >= 0 to check if the value exists in the array. Be aware though of the requirement that the array must be sorted (an earlier version of your answer showed it wasn't sorted), otherwise the behaviour is undefined: it might find the item, or it might return a negative value even if the value exists.
To explicitly answer the question, the expression Arrays.binarySearch(airlineClassAir, "flightless") >=0 will be true if airlineClassAir contains the string "flightless", and false otherwise (assuming it is sorted, otherwise it might return false even if the value is in the array).
Personally, if your requirement is to check for existence and there are no other uses of that array, I would use a Set<String> and use its contains method instead, as that expresses intent more clearly.

How to understand the order induced by the comparator in Java?

I was so confused about comparator and Collections.sort() in Java.
I don't understand the order induced by the comparator. I don't clear about which number the compare function should return to get the sorting direction. I also don't know how Collections will use that compare result to sort the input data. Should I learn them by heart? Is there anything easier to understand them? Can anybody explain it for me? Thanks.
public int compare(Obj a, Obj b){
if(a.age > b.age) return 1;
if(a.age < b.age) return -1;
else return 0;
}
Update
After received some explanations from some friendly Software Engineer, I understood that the comparator define the order of elements in a Collections. For example, when compare a and b, if the comparator return -1 then a should be put before b in the list.
Key thing to remember is if comparison returns positive value ( >0) swap happens. Otherwise not during sorting algorithm.
Example:
4(a) 2(b) 6
For ascending order:
a > b (4 > 2) return 1 (swap requires between a and b i.e place 2 4 6)
For descending order:
a > b ( 2 > 4 ) return -1 (swap not needed between a and b i.e place 4 2 6, because it is already in order).
This logic implemented under sorting algorithm, So, just think if a and b are already in order as you expected then return -1 otherwise return 1.
To sort a set of items, we should be able to compare each pair of items in that set and say which is "bigger" and which is "smaller".
Imagine you are given the task of sorting below numbers manually.
4, 2, 7, 8, 3
How would you use your mind to achieve this task? You would have to look at pairs of numbers and compare them and then figure out which is the smallest number to place at the begging.
Similarly, to achieve a sorting task, a computer needs to compare pairs of items and say which is "bigger" and which is "smaller".
So, the comparator object we write is "the definition" of which is bigger and which is smaller. When we sort numbers, this definition should say which is bigger and which is smaller. When we sort strings, this definition should say which letter in the alphabet comes first and which letter comes after.
Step 1
One way to simplify and correlate this could be that your code:
public int compare(Obj a, Obj b){
if(a.age > b.age) return 1;
if(a.age < b.age) return -1;
else return 0;
}
would be represented as following(given age is int variable)
public int compare(Obj a, Obj b) {
return Integer.compare(a.getAge(), b.getAge());
}
where Integer.compare internally does the same logic as you were doing previously:
return (x < y) ? -1 : ((x == y) ? 0 : 1)
Step 2
Now this can further be represented using a comparator as:
Comparator<Obj> ageComparator = Comparator.comparingInt(Obj::getAge);
which Comparator.comparingInt internally performs
return (Comparator<T> & Serializable)
(c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
Hence the order eventually induced by all these three forms would be same when for example you would call
objList.sort(ageComparator);
Comparable's compareTo method can elaborate more on the part of comparison
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object.
and hence that is considered to be the natural ordering of the Obj when you override the compareTo extending to a Comparable<Obj>.

Comparing doubles in Java gives odd results

I really can'get my head around why the following happens:
Double d = 0.0;
System.out.println(d == 0); // is true
System.out.println(d.equals(0)); // is false ?!
This however works as expected:
Double d = 0.0;
System.out.println(d == 0.0); // true
System.out.println(d.equals(0.0)); // true
I'm positive that this is related to autoboxing in some way, but I really don't know why 0 would be boxed differently when the == operator is used and when .equals is called.
Doesn't this implicitly violate the equals contract ?
* It is reflexive: for any non-null reference value
* x, x.equals(x) should return
* true.
EDIT:
Thanks for the fast answers. I figured that it is boxed differently, the real question is: why is it boxed differently ? I mean that this would be more intuitive if d == 0d than d.equals(0d) is intuitive and expected, however if d == 0 which looks like an Integer is true than 'intuitively' d.equals(0) should also be true.
just change it to
System.out.println(d.equals(0d)); // is false ?! now true
You were comparing double with Integer 0
Under the cover
System.out.println(d.equals(0)); // is false ?!
0 will be autoboxed to Integer and an instance of Integer will be passed to equals() method of Double class, where it will compare like
#Override
public boolean equals(Object object) {
return (object == this)
|| (object instanceof Double)
&& (doubleToLongBits(this.value) == doubleToLongBits(((Double) object).value));
}
which is going to return false of course.
Update
when you do comparison using == it compares values so there is no need to autobox , it directly operates on value. Where equals() accepts Object so if you try to invoke d1.equals(0) , 0 is not Object so it will perform autoboxing and it will pack it to Integer which is an Object.
Number objects only equal to numbers with the same value if they are of the same type. That is:
new Double(0).equals(new Integer(0));
new BigInteger("0").equals(new BigDecimal("0"));
and similar combinations are all false.
In your case, the literal 0 is boxed into an Integer object.
It's probably worth noting that you should compare floating point numbers like this:
|x - y| < ε, ε very small
d.equals(0) : 0 is an int. The Double.equals() code will return true only for Double objects.
When you perform
d == 0
this is upcast to
d == 0.0
however there are no upcasting rules for autoboxing and even if there were equals(Object) gives no hits that you want a Double instead of an Integer.

Java, comparing BigInteger values

BigInteger bigInteger = ...;
if(bigInteger.longValue() > 0) { //original code
//bigger than 0
}
//should I change to this?
if(bigInteger.compareTo(BigInteger.valueOf(0)) == 1) {
//bigger than 0
}
I need to compare some arbitary BigInteger values. I wonder which approach is correct. Given the above code which one should be used? The original code is on the top.. I am thinking to change it to the second approach.
The first approach is wrong if you want to test if the BigInteger has a postive value: longValue just returns the low-order 64 bit which may revert the sign... So the test could fail for a positive BigInteger.
The second approach is better (see Bozhos answer for an optimization).
Another alternative: BigInteger#signum returns 1 if the value is positive:
if (bigInteger.signum() == 1) {
// bigger than 0
}
If you are using BigInteger, this assumes you need bigger numbers than long can handle. So don't use longValue(). Use compareTo. With your example it better be:
if (bigInteger.compareTo(BigInteger.ZERO) > 0) {
}
This is not a direct answer, but an important note about using compareTo().
When checking the value of compareTo(), always test for x < 0, x > 0 and x == 0.
Do not test for x == 1
From the Comparable.compareTo() javadocs:
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
Note:
A negative integer, not -1.
A positive integer, not 1.
True, checking for ==1 and ==-1 would work for BigInteger. This is the BigInteger.compareTo() code:
public int compareTo(BigInteger val) {
if (signum == val.signum) {
switch (signum) {
case 1:
return compareMagnitude(val);
case -1:
return val.compareMagnitude(this);
default:
return 0;
}
}
return signum > val.signum ? 1 : -1;
}
But it's still bad practice, and explicitly recommended against in the JavaDocs:
Compares this BigInteger with the specified BigInteger. This method is provided in preference to individual methods for each of the six boolean comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for performing these comparisons is: (x.compareTo(y) <op> 0), where <op> is one of the six comparison operators.

What do the return values of Comparable.compareTo mean in Java?

What is the difference between returning 0, returning 1 and returning -1 in compareTo() in Java?
Official Definition
From the reference docs of Comparable.compareTo(T):
Compares this object with the
specified object for order. Returns a
negative integer, zero, or a positive
integer as this object is less than,
equal to, or greater than the
specified object.
The implementor must ensure
sgn(x.compareTo(y)) ==
-sgn(y.compareTo(x)) for all x and y. (This implies that x.compareTo(y) must
throw an exception iff y.compareTo(x)
throws an exception.)
The implementor must also ensure that
the relation is transitive:
(x.compareTo(y)>0 && y.compareTo(z)>0)
implies x.compareTo(z)>0.
Finally, the implementor must ensure
that x.compareTo(y)==0 implies that
sgn(x.compareTo(z)) ==
sgn(y.compareTo(z)), for all z.
It is strongly recommended, but not
strictly required that
(x.compareTo(y)==0) == (x.equals(y)).
Generally speaking, any class that
implements the Comparable interface
and violates this condition should
clearly indicate this fact. The
recommended language is "Note: this
class has a natural ordering that is
inconsistent with equals."
In the foregoing description, the
notation sgn(expression) designates
the mathematical signum function,
which is defined to return one of -1,
0, or 1 according to whether the value
of expression is negative, zero or
positive.
My Version
In short:
this.compareTo(that)
returns
a negative int if this < that
0 if this == that
a positive int if this > that
where the implementation of this method determines the actual semantics of < > and == (I don't mean == in the sense of java's object identity operator)
Examples
"abc".compareTo("def")
will yield something smaller than 0 as abc is alphabetically before def.
Integer.valueOf(2).compareTo(Integer.valueOf(1))
will yield something larger than 0 because 2 is larger than 1.
Some additional points
Note: It is good practice for a class that implements Comparable to declare the semantics of it's compareTo() method in the javadocs.
Note: you should read at least one of the following:
the Object Ordering section of
the Collection Trail in the Sun Java
Tutorial
Effective Java by
Joshua Bloch, especially item 12:
Consider implementing Comparable
Java Generics and Collections by
Maurice Naftalin, Philip Wadler, chapter 3.1: Comparable
Warning: you should never rely on the return values of compareTo being -1, 0 and 1. You should always test for x < 0, x == 0, x > 0, respectively.
I use this mnemonic :
a.compareTo(b) < 0 // a < b
a.compareTo(b) > 0 // a > b
a.compareTo(b) == 0 // a == b
You keep the signs and always compare the result of compareTo() to 0
Answer in short: (search your situation)
1.compareTo(0) (return: 1)
1.compareTo(1) (return: 0)
0.comapreTo(1) (return: -1)
take example if we want to compare "a" and "b", i.e ("a" == this)
negative int if a < b
if a == b
Positive int if a > b
It can be used for sorting, and 0 means "equal" while -1, and 1 means "less" and "more (greater)".
Any return value that is less than 0 means that left operand is lesser, and if value is bigger than 0 then left operand is bigger.
int x = thisObject.compareTo(anotherObject);
The compareTo() method returns an int with the following characteristics:
negative If thisObject < anotherObject
zero If thisObject == anotherObject
positive If thisObject > anotherObject
System.out.println(A.compareTo(B)>0?"Yes":"No")
if the value of A>B it will return "Yes" or "No".

Categories