andbi
andbi

Reputation: 4454

Java lambda expressions and memory allocation

Let's say we have three methods like these. They all do the same, but how different they are in terms of memory allocation and efficiency? Method one will create instances of Function during each call, but will the second method do the same? Should one always use the third version or either version is safe and the JIT compiler will take care of the memory optimization?

class Test {
    Map<String, Set<String>> mapOfSets = new HashMap<>();
    static final Function<String, Set<String>> FUNCTION = s -> new HashSet<>();

    void method1(String key, String value) {
        Function<String, Set<String>> func = s -> new HashSet<>();
        mapOfSets.computeIfAbsent(key, func).add(value);
    }

    void method2(String key, String value) {
        mapOfSets.computeIfAbsent(key, s -> new HashSet<>()).add(value);
    }

    void method3(String key, String value) {
        mapOfSets.computeIfAbsent(key, FUNCTION).add(value);
    }
}

Upvotes: 5

Views: 4750

Answers (2)

Stephen C
Stephen C

Reputation: 719259

There are two ways to answer this:

The Java Language Specification section that describes the evaluation of a lambda expression is written to give compilers / implementations flexibility in whether or not a new object is created. Your question boils down to whether or not the lambda objects are reused ... in the three versions of the code. According to the JLS, the answer is implementation dependent. The only way to be 100% sure is to dump out the native code produced by the JIT compiler1. However according to @Holger's answers to other questions2, current OpenJDK-based Java runtimes do cache and reuse non-capturing lambdas.

Given that the behavior and therefore the performance will depend on the Java implementation, it is debatable whether one should pick one form over the other:

  • On the one hand, the third form may be faster.
  • On the other hand, the second and (maybe) first forms are more readable.
  • Should one write applications to be a bit faster at the expense of readability? (Q1)
  • Should one do that, in the face of an expectation that the next version of the compiler may make the hand optimization redundant? (Q2)

This is a matter of opinion, but my opinion is that the answers to Q1 & Q2 is "No" under most circumstances. Leave it to the JIT compiler to deal with optimization unless profiling tells you that the optimization is significant to your application's overall performance, and your application's overall performance really matters.


1 - See How to see JIT-compiled code in JVM?.
2 - See https://stackoverflow.com/a/27524543/139985 and https://stackoverflow.com/a/23991339/139985.

Upvotes: 5

puhlen
puhlen

Reputation: 8529

As comments have mentioned, this can change depending on what Java implementation you use.

For the hotspot jvm (the normal/default java implementation) you can expect all 3 options to be identical in terms of performance. You may think at first that 3 might be better since 1 and 2 might need to create a new Function object each time they are called. However, your assumption that a new object needs to be created each time for method1 (and 2) is false since a non-capturing lambda will be cached at the call site, so the same instance will be reused for each call just like with method3 and you would not see any difference.

this answer is and excellent overview of the topic goes into more detail

So you can use any of the three without worry in this case so use whichever is the most clear for your situation.

Upvotes: 7

Related Questions