Why is this an issue?

Map is an object that maps keys to values. A map cannot contain duplicate keys, which means each key can map to at most one value.

When both the key and the value are needed, it is more efficient to iterate the entrySet(), which will give access to both instead of iterating over the keySet() and then getting the value.

If the entrySet() method is not iterated when both the key and value are needed, it can lead to unnecessary lookups. This is because each lookup requires two operations: one to retrieve the key and another to retrieve the value. By iterating the entrySet() method, the key-value pair can be retrieved in a single operation, which can improve performance.

Noncompliant code example

public void doSomethingWithMap(Map<String,Object> map) {
  for (String key : map.keySet()) {  // Noncompliant; for each key the value is retrieved
    Object value = map.get(key);
    // ...
  }
}

Compliant solution

public void doSomethingWithMap(Map<String,Object> map) {
  for (Map.Entry<String,Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
    // ...
  }
}

Resources

Documentation

Articles & blog posts

Benchmarks

Method size Runtime Average time Error margin

usingEntrySet

10

Temurin 21

27.48 ns/op

±6.22 ns/op

usingEntrySet

1000

Temurin 21

2480.26 ns/op

±899.05 ns/op

usingEntrySet

10000

Temurin 21

22745.78 ns/op

±10505.46 ns/op

usingKeySet

10

Temurin 21

49.70 ns/op

±3.78 ns/op

usingKeySet

1000

Temurin 21

5061.54 ns/op

±2056.60 ns/op

usingKeySet

10000

Temurin 21

46689.04 ns/op

±14509.97 ns/op

Benchmarking code

The results were generated by running the following snippet with JMH.

@BenchmarkMode({Mode.AverageTime})
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
public class S2864 {
  @Param({"10", "1000", "10000"})
  int size;

  Map<Integer,Integer> map;

  @Setup(Level.Trial)
  public void setup() {
    Random random = new Random();
    map = new HashMap<>();
    for (int i = 0; i < size; i++) {
      map.put(i, random.nextInt());
    }
  }

  @Benchmark
  public int usingKeySet() {
    int sumKeysValues = 0;
    for (Integer key : map.keySet()) {
      sumKeysValues += key + map.get(key);
    }
    return sumKeysValues;
  }

  @Benchmark
  public int usingEntrySet() {
    int sumKeysValues = 0;
    for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
      sumKeysValues += entry.getKey() + entry.getValue();
    }
    return sumKeysValues;
  }
}