2

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.

2
  • In the first example, you are using Integer and in the second, you are using int. You can't dereference an int. Commented May 28, 2024 at 15:08
  • 1
    Does this answer your question? in java, use String::length for Comparator.comparing() Commented May 28, 2024 at 16:11

1 Answer 1

2

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 ints, 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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the explaination, also tried the suggested approach Answer tried: code ``` Optional<String> strVal2 = strList.stream().sorted((a, b) -> { // First approach /*Integer aLength = a.length(); Integer bLength = b.length(); return aLength.compareTo(bLength);*/ // Second approach (little bit shortcut) return ((Integer)a.length()).compareTo((Integer)b.length()); }).skip(1).findFirst(); ```
@AjitAAnkalle Okay boxing works too, but it would cause additional allocations, which might not be desirable.
Boxing is to just verify the suggested answer, there are various other approaches to sort the string. And yes, your answer is really helpful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.