Home » Java » Core Java » Java8 Sorting – Performance Pitfall

About Daniel Shaya

Daniel Shaya
Daniel has been programming in Java since it was in beta. Working predominantly in the finance industry he has created real time trading and margin risk applications. He is currently a director at OpenHFT where we are building next generation Java low latency products.

Java8 Sorting – Performance Pitfall

Java 8 brings all the goodness of lambdas to enable us to program using a declarative style. But is it really free? And should we be concerned about the price we have to pay for the new programming goodies?

Here’s an example where we might have to worry.

Consider sorting instances of this simple class:
 
 
 
 
 

private static class MyComparableInt{
        private int a,b,c,d;

        public MyComparableInt(int i) {
            a = i%2;
            b = i%10;
            c = i%1000;
            d = i;
        }

        public int getA() { return a; }
        public int getB() { return b; }
        public int getC() { return c; }
        public int getD() { return d; }
}

We can sort using the new Java 8 declarative syntax as below:

List<MyComparableInt> mySortedComparableList = 
      myComparableList.stream()
       .sorted(Comparator.comparing(
         MyComparableInt::getA).thenComparing(
         MyComparableInt::getB).thenComparing(
         MyComparableInt::getC).thenComparing(
         MyComparableInt::getD))
       .collect(Collectors.toList());

Or we can sort the old way (still using lambdas) using this code:

List<MyComparableInt> mySortedComparableList = 
         myComparableList.stream()
           .sorted(MyComparableIntSorter.INSTANCE)
           .collect(Collectors.toList());


 public enum MyComparableIntSorter implements 
     Comparator<MyComparableInt>{
        INSTANCE;

        @Override
        public int compare(MyComparableInt o1, MyComparableInt o2) {
            int comp = Integer.compare(o1.getA(), o2.getA());
            if(comp==0){
                comp = Integer.compare(o1.getB(), o2.getB());
                if(comp==0){
                    comp = Integer.compare(o1.getC(), o2.getC());
                    if(comp==0){
                        comp = Integer.compare(o1.getD(), o2.getD());
                    }
                }
            }
            return comp;
        }
 }

When I ran this test with 10m objects the sort took ~6.5s using the declarative syntax but only 1.5s using the old syntax. That’s almost 4 times as long!

So where is the time going? Presumably it’s in the overhead for marshalling between the thenComparing methods.

Interestingly, if you try exactly the same test but replace int for String the times change as follows. Again for 10m objects, using the new syntax takes ~11.5s whilst the old syntax takes ~7s. Using String, when the marshalling is less significant the new syntax takes only 1.5 times as long as the old syntax.

In summary, whilst the new syntax looks great and is wonderfully expressive, if you are worried about performance you should stick to the old syntax.

Once again it seems that there is no such thing as a free lunch!

Reference: Java8 Sorting – Performance Pitfall from our JCG partner Daniel Shaya at the Rational Java blog.
(0 rating, 0 votes)
You need to be a registered member to rate this.
4 Comments Views Tweet it!
Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

4
Leave a Reply

avatar
3 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
AndreyFrancescoJacob Zimmermanperceptron8 Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest most voted
Notify of
perceptron8
Guest
perceptron8

How about…?

List mySortedComparableList =
myComparableList.stream()
.sorted(Comparator.comparingInt(
MyComparableInt::getA).thenComparingInt(
MyComparableInt::getB).thenComparingInt(
MyComparableInt::getC).thenComparingInt(
MyComparableInt::getD))
.collect(Collectors.toList());

Andrey
Guest

comparingInt/thenComparingInt seems to be a bit faster than comparing/thenComparing version.
However it’s still much slower than Comparable/Comparator approach.

http://pastebin.com/neV0vVfE

Jacob Zimmerman
Guest

Good stuff.
This doesn’t go for or against your point, but I just wanted to point out that the benefits of the first extend beyond more than readability and ease of use. What is probably the biggest benefit is the reuse factor. If you composed your Comparator from several small comparators, you could mix, match, and rearrange them as you please for other comparisons in other places.
This, of course, does not make your point wrong. It’s just another thing to consider when choosing how you want to do it.

Francesco
Guest
Francesco

what if you replace int with the wrapper type Integer?