2

I have the following class:

import java.util.*;

class ClassA {
    public static void main(String...args) {
        var list = new ArrayList<String>();
        list.add("test");
        list.add("abc");

        Collections.sort(list, (a, b) -> a.length() >= b.length() ? 1 : 0); // [test, abc]
        //Collections.sort(list, (a, b) -> a.compareTo(b));                 // [abc, test]

        System.out.println(list);
    }
}

I thought Collection.sort() would sort accending. I thought a.length() is 4 and b.length() is 3 which would evaluate as (4 >= 3) true. So a.length() >= b.length() ? 1 : 0 would return 1 and mean that "test" is greater than "abc". So it should be sorted like [abc, test].

But I only get the result [abc, test] when I change the code to a.length() >= b.length() ? 1 : -1, which seems to indicate that a.length() >= b.length()evaluates as false. Why is that?

Why does the first lambda expression lead to [test, abc], while the modified version leads to [abc, test]?

Collections.sort(list, (a, b) -> a.compareTo(b)); works like expected.

1 Answer 1

9

Read the doc of Comparator: compare, or the lambda you're using to implement it, must return a negative value if a < b, not just a positive value if a > b. It must also return zero if a is equal to (or compares equal to) b. This differs from the expectation in some other programming languages, which is, I assume, what confused you.

It would be an entirely valid implementation of sort to never pay attention to positive outputs, only negative outputs. It would appear that it didn't do the comparison in the order you expected.

You can implement this comparator correctly as (a, b) -> Integer.compare(a.length(), b.length()), or much more simply as Comparator.comparingInt(String::length).

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

4 Comments

Also IIRC needs to return 0 if equal, so returning 1 for same length is also not a good idea.
I understand that a < b should be negative, a == b should be 0 and a > b should be positive, which is what a.compareTo(b) does. What I don't get is why changing the ternary operator false case will change the result of the sorting. I still don't get how it works. To clarify: I'm more interested in why this works the way it does then in finding a way to get the correct result.
@richard Regarding your comment "a == b"… No, double-equals-sign means identical object reference, that both a & b point to the same object, to the very same place in memory. The discussion here is not about object identity. The discussion here is about the Comparator#compare method. This method usually considers content of the object's state rather than object identity. Two different objects in memory may be considered equal in the mind of a comparator.
Yeah right, my mistake. I meant a.equals(b). So the problem is that (a, b) does not mean it will result in "test" >= "abc", but in this case it will compare "abc" >= "test" and give me 0 for it, which results in the list not being sorted in the expected order. I think I understand now.

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.