9 tips to Increase your Java performance ☕️ 🚀 🚶‍♂️
Tags: java, performance, codequality, codenewbie
Published: 2019-07-20 21:52:06

> 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.

![](https://thepracticaldev.s3.amazonaws.com/i/15159pnizjj24gjuimqr.gif)

> 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`.

```java
// 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](http://tutorials.jenkov.com/java-performance/jmh.html). 

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

```java
@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`.

```java
// 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`.

```java

// 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.

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

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

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

```java
// 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](https://www.baeldung.com/java-enumset).

--- 

# 6. Do not initialize objects at will. Try to reuse at the maximum. 
 
```java
 // 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.

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

--- 

# 8. If you are using String with a single character replace them with a `Character`
 
```java
 // Faster 🚀
 var r = 'R' ;
 var g = 'G' ;
 var b = 'B' ;


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

# 9. Use [StringBuilder](https://docs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html) wherever you can. 

```java

// 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 `+`.

--- 
If you have an interesting performance tip / something is wrong, please leave that in the comment.

You can follow me on [Twitter](https://twitter.com/sendilkumarn).

If you like this article, please leave a like or a comment. :heart: