We can apply comparable & comparator both on integers, as like below:
List<Integer> intList1 = Arrays.asList(1,9,4,8,2,3,7,4,5);
Optional<Integer> val1 = intList1.stream().sorted((a, b) -> a.compareTo(b)).skip(1).findFirst();
Optional<Integer> val2 = intList1.stream().sorted((a,b) -> a >= b ? 1 : -1).skip(1).findFirst();
Same I am trying to apply on integer getting from String.length(), like below:
List<String> strList = Arrays.asList("ab", "abc", "abcd");
Optional<String> strVal1 = strList.stream().sorted((a, b) -> a.length() >= b.length() ? 1 : -1 )
.skip(1).findFirst();
System.out.println(strVal1.get());
Optional<String> strVal2 = strList.stream().sorted((a, b) -> a.length().compareTo(a.length()))
.skip(1).findFirst();
System.out.println(strVal2.get());
Question: Showing error while applying compareTo() on a.length() which returns integer only for variable strVal2
What did you try:
Tried with comparator() and comparable() on custom objects also.
what were you expecting:
Explanation for such behaviour.
In the first code snippet, a
and b
are of the reference type java.lang.Integer
. This is a class that declares a method called compareTo
. Therefore, a.compareTo(b)
is valid.
In the second code snippet, a.length()
returns a value of the primitive type int
. This is a very different type from java.lang.Integer
. You cannot call methods on an int
, because it is not a reference type, like a class. For more differences between reference types and primitive types, see this post.
From the section of the Java Language Specification that talks about method invocations,
If the form is
Primary . [TypeArguments] Identifier
, then let T be the type of the Primary expression. The type to search is T if T is a class or interface type, or the upper bound of T if T is a type variable.[...]
It is a compile-time error if T is not a reference type.
In your case, Primary
is the expression a.length()
, whose type is the primitive type int
.
To compare primitive int
s, you can use the static Integer.compare
method.
(a, b) -> Integer.compare(a.length(), b.length())
Or, instead of a lambda, pass a Comparator
created using Comparator.comparingInt
:
Comparator.comparingInt(String::length)
Note that the code that passed (a,b) -> a >= b ? 1 : -1
and (a, b) -> a.length() >= b.length() ? 1 : -1
are incorrect. The general contract of Comparator
requires compareTo(x, y)
to have the opposite sign from compare(y, x)
, or both should return 0.