3

I came to this code

Collections.sort(list, (o1, o2) -> o1.getValue().compareTo(o2.getValue()));

and I'm wondering, is it just a syntactic sugar for

Collections.sort(list, new Comparator<CodeTableEntry>() {
    @Override
    public int compare(CodeTableEntry o1, CodeTableEntry o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
});

or it is something smarter? Is it optimized not to create new instance everytime?

It's just my opinion, but such non-trivial one-liner is not better as easy to follow straightforward code... (which is not the one above, but one below)

static final Comparator<CodeTableEntry> codeTableEntryValueComparator = new Comparator<CodeTableEntry>() {
    @Override
    public int compare(CodeTableEntry o1, CodeTableEntry o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
};

... 
    Collections.sort(list, codeTableEntryValueComparator);
...

Clarification to "Is it optimized not to create new instance everytime?"

As there is just one new I believed it's clear, seems it's not. I did this code to check:

public class ComparatorTest {

    private static void sort(List<String> list) {
        Collections.sort(list, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                System.out.println("comparator: " + this);
                return s1.compareTo(s2);
            }
        });
        System.out.println("sorted: " + list);
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("c");
        sort(list);
        list.add("b");
        sort(list);
        list.add("a");
        sort(list);
    }

}

and the output is

sorted: [c]
comparator: ComparatorTest$1@7852e922
sorted: [b, c]
comparator: ComparatorTest$1@4e25154f
comparator: ComparatorTest$1@4e25154f
comparator: ComparatorTest$1@4e25154f
comparator: ComparatorTest$1@4e25154f
sorted: [a, b, c]

which I believe shows, there is new instance of Comparator (because of different hash code) created for each method call


How to check with lambdas, just for my testing I printed stacktrace when I created an exception

Collections.sort(list, (o1, o2) -> getValue(o1).compareTo(o2));

where getValue is

public static String getValue(String s) {
    RuntimeException re = new RuntimeException();
    re.printStackTrace(System.out);
    return s;
}

and it printed

sorted: [c]
java.lang.RuntimeException
    at ComparatorTest.getValue(ComparatorTest.java:20)
    at ComparatorTest.lambda$0(ComparatorTest.java:15)
    at java.util.TimSort.countRunAndMakeAscending(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at ComparatorTest.sort(ComparatorTest.java:15)
    at ComparatorTest.main(ComparatorTest.java:32)
sorted: [b, c]
java.lang.RuntimeException
    at ComparatorTest.getValue(ComparatorTest.java:20)
    at ComparatorTest.lambda$0(ComparatorTest.java:15)
    at java.util.TimSort.countRunAndMakeAscending(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at ComparatorTest.sort(ComparatorTest.java:15)
    at ComparatorTest.main(ComparatorTest.java:34)
java.lang.RuntimeException
    at ComparatorTest.getValue(ComparatorTest.java:20)
    at ComparatorTest.lambda$0(ComparatorTest.java:15)
    at java.util.TimSort.countRunAndMakeAscending(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at ComparatorTest.sort(ComparatorTest.java:15)
    at ComparatorTest.main(ComparatorTest.java:34)
java.lang.RuntimeException
    at ComparatorTest.getValue(ComparatorTest.java:20)
    at ComparatorTest.lambda$0(ComparatorTest.java:15)
    at java.util.TimSort.binarySort(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at ComparatorTest.sort(ComparatorTest.java:15)
    at ComparatorTest.main(ComparatorTest.java:34)
java.lang.RuntimeException
    at ComparatorTest.getValue(ComparatorTest.java:20)
    at ComparatorTest.lambda$0(ComparatorTest.java:15)
    at java.util.TimSort.binarySort(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at ComparatorTest.sort(ComparatorTest.java:15)
    at ComparatorTest.main(ComparatorTest.java:34)
sorted: [a, b, c]

and there seems to be just one ComparatorTest.lambda$0...

Betlista
  • 10,327
  • 13
  • 69
  • 110
  • 5
    *"Is it optimized not to create new instance everytime?"* Create a new instance of what? – Robby Cornelissen May 16 '18 at 08:52
  • 4
    I think that all of your answers will be answered here https://stackoverflow.com/questions/47407180/do-lambda-expressions-have-any-use-other-than-saving-lines-of-code – Eugene May 16 '18 at 08:54
  • @Eugene : Indeed, your duplicate looks better, but too late unfortunately. – Arnaud May 16 '18 at 08:56
  • Calling anonymous inner classes that implement a single method and are passed in as method arguments *"easy to follow straightforward code"* is not something I'd heard before. – Robby Cornelissen May 16 '18 at 08:56
  • 1
    @Berger does not matter, since it is still a *duplicate*, nonetheless one of those insanely awesome answers from Holger – Eugene May 16 '18 at 08:57
  • Thanks guys for a right direction, I tried, but didn't find what I was looking for. I'll definitely read all linked materials ;-) – Betlista May 16 '18 at 09:08
  • @RobbyCornelissen add new instances: from context it's clear I's day - `new Comparator()` – Betlista May 16 '18 at 09:10
  • @RobbyCornelissen ad inner classes, this is question related, I'd create regular class (not anonyous one) for comparator and there would be just one instance in memory... – Betlista May 16 '18 at 09:12
  • In regards to your "from context it's clear I's day" (sic): my comment requesting for clarification has 5 upvotes, so I'd argue that at least 6 people don't find it "clear as day". – Robby Cornelissen May 16 '18 at 09:13
  • @RobbyCornelissen I added clarification for that "new instance" question. For now I'm not going to re-open, I'll read all linked first and I'll see... In my code I assume it is the same as lambdas, I do not know how to add that print statement in lambda version, feel free to add the same to question if you feel it's worth it. – Betlista May 16 '18 at 09:32
  • 1
    Whether or not a lambda expression creates a new object every time it's evaluated is unspecified. Possibly see https://stackoverflow.com/questions/27524445/does-a-lambda-expression-create-an-object-on-the-heap-every-time-its-executed. BTW, stack traces can't be used to test object identity, because they just tell you the line number in a particular class. The most convenient way to test whether an object is created every time a particular expression is evaluated could be to use a static `Collections.newSetFromMap(new IdentityHashMap<>())` and test its size. – Radiodef May 17 '18 at 18:05

0 Answers0