Java Lambda表达式和内存分配

时间:2018-12-22 03:43:14

标签: java

假设我们有三种这样的方法。它们都相同,但是在内存分配和效率方面有何不同?方法一将在每次调用期间创建Function的实例,但是第二个方法会做同样的事情吗?应该一直使用第三个版本,还是应该使用第三个版本,JIT编译器将负责内存优化?

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);
    }
}

2 个答案:

答案 0 :(得分:3)

有两种方法可以解决这个问题:

“ Java语言规范”部分描述了lambda表达式的计算,旨在为编译器/实现提供是否创建新对象的灵活性。您的问题归结为是否在代码的三个版本中重用了lambda对象。根据JLS,答案取决于实现。确保的唯一方法是转储由JIT编译器生成的本机代码。

鉴于行为及其性能将取决于Java实现,因此有争议的是应该选择一种形式而不是另一种形式:

  • 一方面,第三种形式 可能会更快。
  • 另一方面,第二种形式(也许是第一种形式)更具可读性。
  • 一个写应用程序应该以可读性为代价快一点吗?
  • 面对一个期望编译器的下一版本可能使手工优化变得多余的做法,应该这样做吗?

这是一个见解,但我的观点是,上一个问题的答案通常是否。将其交给编译器作者处理优化除非

  • 分析告诉您优化对应用程序的整体性能至关重要,
  • 整体表现很重要。

答案 1 :(得分:1)

正如评论所提到的,这可以根据您使用的Java实现而改变。

对于热点jvm(常规/默认Java实现),您可以期望所有3个选项在性能方面都相同。您可能首先认为3可能更好,因为每次调用1和2时都需要创建一个新的Function对象。但是,您的假设每次都要为method1(和2)创建一个新对象是错误的,因为未捕获的lambda将被缓存在调用站点中,因此,与method3一样,每个调用都将重用相同的实例并且您不会看到任何区别。

this answer是,并且对该主题的出色概述更加详细

因此,在这种情况下,您可以使用这三种方法中的任何一种而不必担心,因此请使用最适合您情况的方法。