Boost Java Performance: 5 Proven HashMap & Enum Optimizations

This article presents five practical Java performance tweaks—pre‑allocating HashMap capacity, using object keys, caching Enum values, replacing String constants with Enums, and upgrading the JDK—backed by JMH benchmarks that show up to 9.5× speed gains.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Boost Java Performance: 5 Proven HashMap & Enum Optimizations

This article introduces several small yet effective performance‑optimization tricks for Java developers, emphasizing that premature optimization should be avoided.

Tip: Do not optimize for the sake of optimization; it can increase code complexity.

The benchmarks were run using JMH version 1.33 on JDK 17 (OpenJDK 64‑Bit Server VM, 17+35‑2724).

Pre‑allocate HashMap size, improving performance by about 25%.

Optimize HashMap keys by using object references instead of concatenated strings, achieving a 9.5× speedup.

Avoid using Enum.values() for iteration; cache the values array to reduce allocation overhead.

Replace String constants with Enums; using EnumMap outperforms HashMap by roughly 1.5×.

Use a newer JDK version; basic operations can be 2–5× faster.

Pre‑allocate HashMap Size

HashMap is a frequently used collection in Java. When its capacity needs to grow, the operation is slow, so it is advisable to set an appropriate initial size based on the load factor (default 0.75).

@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 5, time = 3)
public class HashMapSize {
    @Param({"14"})
    int keys;
    @Param({"16", "32"})
    int size;
    @Benchmark
    public HashMap<Integer, Integer> getHashMap() {
        HashMap<Integer, Integer> map = new HashMap<>(size);
        for (int i = 0; i < keys; i++) {
            map.put(i, i);
        }
        return map;
    }
}

With an initial capacity of 16, inserting 14 elements triggers a resize; with capacity 32, no resize occurs because 32 × 0.75 = 24 slots are available.

# JMH version: 1.33
# VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724

Benchmark               (keys)  (size)   Mode  Cnt        Score        Error  Units
HashMapSize.getHashMap      14      16  thrpt   25  4825825.152 ± 323910.557  ops/s
HashMapSize.getHashMap      14      32  thrpt   25  6556184.664 ± 711657.679  ops/s

The 32‑capacity HashMap processes about 26% more operations per second, confirming a roughly 1/4 performance improvement.

Optimize HashMap Key

When a HashMap key consists of multiple strings, encapsulating those strings in a custom object and using that object as the key is faster than concatenating strings.

@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 5, time = 3)
public class HashMapKey {
    private int size = 1024;
    private Map<String, Object> stringMap;
    private Map<Pair, Object> pairMap;
    private String[] prefixes;
    private String[] suffixes;

    @Setup(Level.Trial)
    public void setup() {
        prefixes = new String[size];
        suffixes = new String[size];
        stringMap = new HashMap<>();
        pairMap = new HashMap<>();
        for (int i = 0; i < size; ++i) {
            prefixes[i] = UUID.randomUUID().toString();
            suffixes[i] = UUID.randomUUID().toString();
            stringMap.put(prefixes[i] + ";" + suffixes[i], i);
            pairMap.put(new MutablePair(prefixes[i], suffixes[i]), i);
        }
    }

    @Benchmark
    @OperationsPerInvocation(1024)
    public void stringKey(Blackhole bh) {
        for (int i = 0; i < prefixes.length; i++) {
            bh.consume(stringMap.get(prefixes[i] + ";" + suffixes[i]));
        }
    }

    @Benchmark
    @OperationsPerInvocation(1024)
    public void pairMap(Blackhole bh) {
        for (int i = 0; i < prefixes.length; i++) {
            bh.consume(pairMap.get(new MutablePair(prefixes[i], suffixes[i])));
        }
    }
}
# JMH version: 1.33
# VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724

Benchmark               Mode  Cnt          Score          Error  Units
HashMapKey.pairMap    thrpt   25  89295035.436 ± 6498403.173  ops/s
HashMapKey.stringKey  thrpt   25   9410641.728 ±  389850.653  ops/s

Using an object reference as the key is about 9.5 times faster than using a concatenated string.

Avoid Enum.values() Iteration

Calling Enum.values() creates a new array each time. Caching the array eliminates this allocation.

@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 5, time = 3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class EnumIteration {
    enum FourteenEnum {
        a,b,c,d,e,f,g,h,i,j,k,l,m,n;
        static final FourteenEnum[] VALUES;
        static { VALUES = values(); }
    }

    @Benchmark
    public void valuesEnum(Blackhole bh) {
        for (FourteenEnum v : FourteenEnum.values()) {
            bh.consume(v.ordinal());
        }
    }

    @Benchmark
    public void enumSetEnum(Blackhole bh) {
        for (FourteenEnum v : EnumSet.allOf(FourteenEnum.class)) {
            bh.consume(v.ordinal());
        }
    }

    @Benchmark
    public void cacheEnums(Blackhole bh) {
        for (FourteenEnum v : FourteenEnum.VALUES) {
            bh.consume(v.ordinal());
        }
    }
}
# JMH version: 1.33
# VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724

Benchmark                     Mode  Cnt          Score          Error  Units
EnumIteration.cacheEnums   thrpt   25  15623401.567 ± 2274962.772  ops/s
EnumIteration.enumSetEnum   thrpt   25   8597188.662 ±  610632.249  ops/s
EnumIteration.valuesEnum    thrpt   25  14713941.570 ±  728955.826  ops/s

Caching the enum array yields the best throughput; EnumSet traversal is the slowest because it relies on a hash‑based structure.

Use Enum Instead of String Constants

Replacing String constants with Enums provides type safety and better performance. When used as map keys, EnumMap outperforms HashMap with String keys.

@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 5, time = 3)
public class EnumMapBenchmark {
    enum AnEnum { a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z; }
    static final int size = 10000;
    static final int seed = 99;

    @State(Scope.Benchmark)
    public static class EnumMapState {
        EnumMap<AnEnum, String> map;
        AnEnum[] values;
        @Setup(Level.Trial)
        public void setup() {
            map = new EnumMap<>(AnEnum.class);
            values = new AnEnum[size];
            AnEnum[] enumValues = AnEnum.values();
            SplittableRandom random = new SplittableRandom(seed);
            for (int i = 0; i < size; i++) {
                values[i] = enumValues[random.nextInt(0, enumValues.length)];
            }
            for (AnEnum v : enumValues) {
                map.put(v, UUID.randomUUID().toString());
            }
        }
    }

    @State(Scope.Benchmark)
    public static class HashMapState {
        HashMap<String, String> map;
        String[] values;
        @Setup(Level.Trial)
        public void setup() {
            map = new HashMap<>();
            values = new String[size];
            AnEnum[] enumValues = AnEnum.values();
            SplittableRandom random = new SplittableRandom(seed);
            for (int i = 0; i < size; i++) {
                values[i] = enumValues[random.nextInt(0, enumValues.length)].toString();
            }
            for (AnEnum v : enumValues) {
                map.put(v.toString(), UUID.randomUUID().toString());
            }
        }
    }

    @Benchmark
    public void enumMap(EnumMapState state, Blackhole bh) {
        for (AnEnum v : state.values) {
            bh.consume(state.map.get(v));
        }
    }

    @Benchmark
    public void hashMap(HashMapState state, Blackhole bh) {
        for (String v : state.values) {
            bh.consume(state.map.get(v));
        }
    }
}
# JMH version: 1.33
# VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724

Benchmark                     Mode  Cnt          Score          Error  Units
EnumMapBenchmark.enumMap   thrpt   25   22159.232 ± 1268.800  ops/s
EnumMapBenchmark.hashMap   thrpt   25   14528.555 ± 1323.610  ops/s

Using Enums as keys yields about 1.5× higher throughput than using Strings.

Use a Higher‑Version JDK

String handling has been optimized in newer JDK releases. Benchmarks compare Java 8 and Java 11/17 for converting between String and byte[].

@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 3)
@Measurement(iterations = 5, time = 3)
public class StringInJdk {
    @Param({"10000"})
    private int size;
    private String[] stringArray;
    private List<byte[]> byteList;
    @Setup(Level.Trial)
    public void setup() {
        byteList = new ArrayList<>(size);
        stringArray = new String[size];
        for (int i = 0; i < size; i++) {
            String uuid = UUID.randomUUID().toString();
            stringArray[i] = uuid;
            byteList.add(uuid.getBytes(StandardCharsets.UTF_8));
        }
    }
    @Benchmark
    public void byteToString(Blackhole bh) {
        for (byte[] b : byteList) {
            bh.consume(new String(b, StandardCharsets.UTF_8));
        }
    }
    @Benchmark
    public void stringToByte(Blackhole bh) {
        for (String s : stringArray) {
            bh.consume(s.getBytes(StandardCharsets.UTF_8));
        }
    }
}
# JMH version: 1.33
# VM version: JDK 1.8.0_151, Java HotSpot(TM) 64-Bit Server VM, 25.151-b12

Benchmark                 (size)  Mode  Cnt      Score      Error  Units
StringInJdk.byteToString      10000  thrpt   25   2396.713 ± 133.500  ops/s
StringInJdk.stringToByte      10000  thrpt   25   1745.060 ±  16.945  ops/s

# JMH version: 1.33
# VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724

Benchmark                 (size)  Mode  Cnt      Score      Error  Units
StringInJdk.byteToString      10000  thrpt   25   5711.954 ±  41.865  ops/s
StringInJdk.stringToByte      10000  thrpt   25   8595.895 ± 704.004  ops/s

On Java 17, converting byte[] → String is about 2.5× faster and String → byte[] is roughly 5× faster than on Java 8, highlighting the benefit of upgrading the JDK.

Tip: Do not optimize without a real performance problem; unnecessary tweaks can add complexity.
Performance comparison chart
Performance comparison chart
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaperformanceenumJDKHashMapBenchmark
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.