【问题标题】:Is Java lazy when passing parameters to a method?将参数传递给方法时Java是懒惰的吗?
【发布时间】:2018-01-18 00:55:18
【问题描述】:

我正在使用此代码:

A a = aMap.contains(key) ? aMap.get(key) : createAExpensively(key);

我相信 Java 是惰性的,所以如果 aMap.contains(key)) 则永远不会调用 createAExpensively() 函数。

然后,我偶然发现了Map.getOrDefault() 方法。如果我们改为使用:

A a = aMap.getOrDefault(key, createAExpensively(key));

Java 还懒得调用createAExpensively() 函数吗?

Java 似乎会首先创建对象A 并将其作为方法参数传递,基于this question,但我并不完全确定。

如果 Java 在使用 Map.getOrDefault() 时并不懒惰,那么该方法的意义何在?

【问题讨论】:

    标签: java lazy-evaluation lazy-initialization short-circuiting


    【解决方案1】:

    Java 还懒得调用createAExpensively() 函数吗? [在.getOrDefault(key, createAExpensively(key))]

    函数参数在实际调用函数之前被评估(从左到右)。所以createAExpensively(key) 将在调用getOrDefault 之前进行评估。这种行为也称为applicative order evaluation strategy

    如果 Java 在使用 Map.getOrDefault() 时并不懒惰,那么该方法的意义何在?

    当默认值创建成本不高时很有用, 例如,当它是一个已经计算的值或常量时。 在这种情况下,Map.getOrDefault(...) 调用允许比三元运算符更紧凑的语法。

    如果默认值的计算成本很高, 如果你真的想把计算的值放在地图中, 然后从 Java 8 开始, 你可以使用computeIfAbsent:

    A a = aMap.computeIfAbsent(key, k -> createAExpensively(k));
    

    【讨论】:

    • computeIfAbsent 不是 getOrDefault 的惰性版本。如果键不存在,前者会改变地图;后者没有。
    • @HelderPereira 哎哟,好电话。谢谢,澄清了这一点。
    • 不幸的是,Map 接口中没有相应的方法。但是,我们仍然可以通过使用 Optionals: A a = Optional.ofNullable(aMap.get(key)).orElseGet(() -> createAExpensively(key)); 调用地图来解决这个问题。
    • @HelderPereira 是的,但我认为这不会是对三元的改进。
    • 取决于调用地图的成本。我有一张由 RocksDB 支持的地图。 :D
    【解决方案2】:

    Java 一点也不懒惰。您正在使用条件运算符来检查是否aMap.contains(key)。如果这是真的,它将永远不会调用createAExpensively(key),而是aMap.get(key)

    【讨论】:

      【解决方案3】:

      一点也不懒惰。

      这段代码

      A a = aMap.contains(key) ? aMap.get(key) : createAExpensively(key);

      评估为

      if (aMap.contains(key)) 
      {
        a = aMap.get(key);
      }
      else 
      {
        a = createAExpensively(key);
      }
      

      【讨论】:

        【解决方案4】:

        这被称为"short-circuit evaluation" 而不是惰性评估:JVM 不是推迟createExpensively() 的评估,而是完全避免如果没有必要,即如果条件成立。

        另请参阅 StackOverflow 上以下问题的答案:

        Java logical operator short-circuiting

        【讨论】:

          【解决方案5】:

          在那种情况下它并不懒惰。

          该方法的要点是,很多时候默认值是一个常量或您已经计算过的东西。例如,当您获得某种计数时,您可能会使用getOrDefault(key, 0),而缺少的键应计为零。

          【讨论】:

            猜你喜欢
            • 2013-10-04
            • 2018-01-28
            • 1970-01-01
            • 2011-03-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-12-11
            • 1970-01-01
            相关资源
            最近更新 更多