Lambda在经典的Operation enum例子中

正如你们许多人所知,有一个典型的Operation enum例子(现在使用Java 8标准接口),如下所示:

 enum Operation implements DoubleBinaryOperator { PLUS("+") { @Override public double applyAsDouble(final double left, final double right) { return left + right; } }, MINUS("-") { @Override public double applyAsDouble(final double left, final double right) { return left - right; } }, MULTIPLY("*") { @Override public double applyAsDouble(final double left, final double right) { return left * right; } }, DIVIDE("/") { @Override public double applyAsDouble(final double left, final double right) { return left / right; } }; private final String symbol; private Operation(final String symbol) { this.symbol = symbol; } public String getSymbol() { return symbol; } } 

经测试:

 Arrays.stream(Operation.values()) .forEach(op -> System.out.println("Performing operation " + op.getSymbol() + " on 2 and 4: " + op.applyAsDouble(2, 4))); 

它提供:

在2和4:6.0上执行操作+
执行操作 – 在2和4:-2.0
在2和4:8.0上执行操作*
执行操作/在2和4:0.5

但我觉得我们可以用Java 8做得更好,因此我实现了以下内容:

 enum Operation implements DoubleBinaryOperator { PLUS ("+", (l, r) -> l + r), MINUS ("-", (l, r) -> l - r), MULTIPLY("*", (l, r) -> l * r), DIVIDE ("/", (l, r) -> l / r); private final String symbol; private final DoubleBinaryOperator binaryOperator; private Operation(final String symbol, final DoubleBinaryOperator binaryOperator) { this.symbol = symbol; this.binaryOperator = binaryOperator; } public String getSymbol() { return symbol; } @Override public double applyAsDouble(final double left, final double right) { return binaryOperator.applyAsDouble(left, right); } } 

在function上它是等价的,但是两个实现仍然相似,或者是否有一些隐藏的细节使新版本与旧版本相比更糟糕?

最后,lambda方式是Java 8的首选方式吗?

显然,lambda版本更具可读性。 它不仅更短,而且允许读者在构造函数中第一眼看到实现操作符。 想象一下,你想扩展enum以支持int计算……

从性能的角度来看,您正在通过生成的lambda类交换匿名enum内部类。 lambda版本增加了另一级别的委派,但这对HotSpot优化器没有任何挑战。 不太可能看到有关执行性能的任何差异。

但是,在应用lambda模式时,您可能会获得使用该类启动应用程序的速度。 原因是对于传统的专用enum方法,Java编译器必须为每个案例生成一个内部类,它位于文件系统或Jar文件中(可能是zip压缩)。 在运行中生成lambda类(具有非常简单的结构)的字节代码通常比加载类更快。 也许有助于生成的lambda类没有访问检查。

总结一下:

  • lambda方法更容易阅读,其代码更易于维护(重点)
  • 执行性能大致相同
  • lambda方法的启动时间可能更短

所以这对lambda来说是一个巨大的胜利。 是的,我认为lambda方式是Java 8的首选方式。

这取决于你如何更好地定义。

在你的情况下,在我看来,lambdas是纯粹的胜利。 您甚至可以重用一些现有的JDK函数,例如:

 enum Operation implements DoubleBinaryOperator { PLUS ("+", Double::sum), ... } 

这简短易读。 对于没有对代码进行基准测试的性能,我认为没有任何合理的说法。

Lambda用invokeDynamic实现,以动态地将调用站点链接到要执行的实际代码; 没有匿名的内部阶级。

定义更糟糕,很可能它使用更多字节代码并且稍微慢一些。

除非这些对您很重要,否则我会使用您认为更清晰,更简单的方法。

我很惊讶没有人提到这一点,但实施多种方法时lambda方法会变得毛茸茸。 将一堆无名lambda传递给构造函数将更简洁,但不一定更具可读性。

此外,随着函数大小的增加,使用lambda的好处也会减少。 如果你的lambda长度超过几行,那么覆盖可能同样容易阅读,如果不容易的话。