Jul 20, 2019

9 tips to Increase your Java performance

A little bit more performance is always awesome.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler

But the itch to write a high performance code is always there for any developer. Let us see how to make Java code to run even faster.

Note: The JVM optimizes the code efficiently. So you do not need to optimize it for a general use cases. But if you want to drain the maximum performance out of JVM. Here we go.

All the tests are taken in OpenJDK 12.0.1 in a Macbook Pro 2017 laptop.

1. Instantiate in constructor

If your collections are initialized only once, it is better to initialize the values in the collection constructor itself rather than instantiating the collections and setting the values using addAll.

// Slower 🚶‍♂️
Set<String> set = new HashSet<>();
set.addAll(Arrays.asList("one", "two", "three"));

// Faster 🚀
Set<String> set = new HashSet<>(Arrays.asList("one", "two", "three"));

Let us verify this using JMH benchmarks.

The results unit isoperations/second (op/s). More the number higher the performance is.

@State(Scope.Thread)
public static class MyState {

    @Setup(Level.Trial)
    public void doSetup() {
        var arr = new Integer[100000];
        for (var i = 0; i < 100000; i++) {
            arr[i] = i;
        }
        list = Arrays.asList(arr);
    }

    public List list;
}

// Faster 🚀 > ~148,344 op/s
@Benchmark
public HashSet usingConstructor() {
    var set = new HashSet<>(list);
    return set;
}

// Slower 🚶‍♂️ > ~112,061 op/s
@Benchmark
public HashSet usingAddAll() {
    var set = new HashSet<>();
    set.addAll(list);
    return set;
}

The construtor version provides ~36000 op/s more than the addAll version.


2. AddAll is faster than Add

Similarly, addAll provides higher operations per second when compared with add. So next time when you are adding something to an array make sure that you pile them and add it using addAll.

// Slower 🚶‍♂️ ~116116op/s
@Benchmark
public ArrayList<Integer> usingAdd() {
    var a = new int[1000];
    for (var i = 0; i < 1000; i++) {
        a[i] = i;
    }


    var arr = new ArrayList<Integer>();
    for (var i = 0; i < 1000; i++) {
        arr.add(a[i]);
    }

    return arr;
}

// Faster 🚀 ~299130 op/s
@Benchmark
public ArrayList<Integer> usingAddAll() {
    var a = new Integer[1000];
    for (var i = 0; i < 1000; i++) {
        a[i] = i;
    }

    var arr = new ArrayList<Integer>();
    arr.addAll(Arrays.asList(a));
    return arr;
}

The addAll is almost twice as fast as the add version.


3. Use EntrySet for Map over KeySet

Do you iterate a lot over the map? Then use entrySet over the keySet.

// Slower 🚶‍♂️ ~37000 op/s
@Benchmark
public HashMap<Integer, Integer> keySetIteration(Blackhole blackhole) {
    var someMap = new HashMap<Integer, Integer>();

    for (var i = 0; i < 1000; i++) {
        someMap.put(i, i);
    }

    var sum = 0;
    for(Integer i: someMap.keySet()) {
        sum += i;
        sum += someMap.get(i);
    }
    blackhole.consume(sum);
    return someMap;
}

// Faster 🚀 ~45000 op/s
@Benchmark
public HashMap<Integer, Integer> entrySetIteration(Blackhole blackhole) {
    var someMap = new HashMap<Integer, Integer>();

    for (var i = 0; i < 1000; i++) {
        someMap.put(i, i);
    }

    var sum = 0;
    for(Map.Entry<Integer, Integer> e: someMap.entrySet()) {
        sum += e.getKey();
        sum += e.getValue();
    }

    blackhole.consume(sum);

    return someMap;
}

The entrySet can run 9000 operations more than its keySet variant in a second.

4. Use SingletonList instead of an array with single element.

// Faster 🚀
var list = Collections.singletonList("S");

// Slower 🚶‍♂️
var list = new ArrayList(Arrays.asList("S"));

5. Use EnumSet instead of HashSet. EnumSet is much faster.

// Faster 🚀
public enum Color {
    RED, YELLOW, GREEN
}

var colors = EnumSet.allOf(Color.class);

// Slower 🚶‍♂️
var colors = new HashSet<>(Arrays.asList(Color.values()));

More about EnumSet here.


6. Do not initialize objects at will. Try to reuse at the maximum.

// Faster 🚀
 var i = 0 ;
 i += addSomeNumber();
 i -= minusSomeNumber();
 return i;


 // Slower 🚶‍♂️
 var i = 0 ;
 var j = addSomeNumber();
 var k = minusSomeNumber();
 var l = i + j - k;
 return l;

7. Use String.isEmpty() method to check whether the String is empty.

String is a byte[] and isEmpty just checks the length of an Array. So it is much faster.

public boolean isEmpty() {
        return value.length == 0;
    }

8. If you are using String with a single character replace them with a Character

// Faster 🚀
 var r = 'R' ;
 var g = 'G' ;
 var b = 'B' ;


 // Slower 🚶‍♂️
 var r = "R" ;
 var g = "G" ;
 var b = "B" ;

9. Use StringBuilder wherever you can.

// Faster 🚀
StringBuilder str = new StringBuilder();
str.append("A");
str.append("B");
str.append("C");
str.append("D");
str.append("E");
....

// Slower 🚶‍♂️
var str = "";
str += "A";
str += "B";
str += "C";
str += "D";
str += "E";
....

But when you have to do a single concatenation. instead of using a StringBuilder it is faster to use +.


Up Next


யாதும் ஊரே யாவரும் கேளிர்! தீதும் நன்றும் பிறர்தர வாரா!!

@sendilkumarn