5
import java.util.HashMap;
import java.util.HashSet;

public class ComputeIfAbsentWithHashSetNew {
    public static void main(String[] args) {
        var map = new HashMap<Integer, HashSet<Integer>>();
        var data = new int[][]{{305589003, 4136}, {305589004, 4139}};
        for (var entry : data) {
            int x = entry[0];
            int y = entry[1];
//            map.computeIfAbsent(x, _x -> new HashSet<>()).add(y); // ----- line 1
            var k = map.computeIfAbsent(x, HashSet::new);           // ----- line 2
            k.add(y);
        }
    }
}

Above code throws at jdk 17、 18、 19:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.base/java.util.HashMap.resize(HashMap.java:702)
    at java.base/java.util.HashMap.putVal(HashMap.java:627)
    at java.base/java.util.HashMap.put(HashMap.java:610)
    at java.base/java.util.HashSet.add(HashSet.java:221)
    at _explore.ComputeIfAbsentWithHashSetNew.main(ComputeIfAbsentWithHashSetNew.java:15)

When debug, I see the newCap in Hashmap::resize() is very large, I don't know why. I thought both the lines do same thing previously.

When I replace line 2 with line 1 in code, it runs successfully.

Petter Hesselberg
  • 5,062
  • 2
  • 24
  • 42
djy
  • 737
  • 6
  • 14
  • 3
    *"When I replace line 2 with line 1 in code, it runs successfully."* because they do completely different things. One creates an `HashSet` with default capacity, the other creates an `HashSet` with initial capacity `x`, which may very well be 305589003, which is rather big. – Federico klez Culloca Jan 20 '23 at 07:37
  • 1
    `computeIfAbsent` calls the 2nd parameter (a `Function`) with the key as argument, in this case `305589003`; the passed function `HashSet::new` is the `HashSet(int initialCapacity)` - as commented above, `305589003` as capacity is too big to be stored in the available memory (line 1 should be `k -> new HashSet<>(k)` to be the same as line 2, both wrong) – user16320675 Jan 20 '23 at 07:45

1 Answers1

5

HashSet::new is a method reference pointing to new HashSet(initialCapacity). See the java-doc of HashSet.

So, it creates a bigger HashSets than you expect, because it takes your x variable as parameter.

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
akop
  • 5,981
  • 6
  • 24
  • 51
  • 4
    a detail: `HashSet::new` is not a lambda but just a method reference (according JLS [15.27. Lambda Expressions](https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.27)) – user16320675 Jan 20 '23 at 07:53