Jul 20, 2019

9 tips to Increase your Java performance

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