性能分析
  Lambda表达式主要的优势表现在性能方面,虽然使用它很轻松的将很多行代码缩减成一句,但是其内部实现却不这么简单。下面对内部实现的每一步进行性能分析。
  第一步是连接,对应的是我们上面提到的Lambda工厂。这一步相当于匿名内部类的类加载过程。来自Oracle的Sergey Kuksenko发布过相关的性能报告,并且他也在2013 JVM语言大会该话题做过分享。报告表明,Lambda工厂的预热准备需要消耗时间,并且这个过程比较慢。伴随着更多的调用点连接,代码被频繁调用后(比如被JIT编译优化)性能会提升。另一方面如果连接处于不频繁调用的情况,那么Lambda工厂方式也会比匿名内部类加载要快,高可达100倍。
  第二步是捕获变量。正如我们前面提到的,如果是不进行捕获变量,这一步会自动进行优化,避免在基于Lambda工厂实现下额外创建对象。对于匿名内部类而言,这一步对应的是创建外部类的实例,为了优化内部类这一步的问题,我们需要手动的修改代码,如创建一个对象,并将它设置给一个静态的属性。如下述代码:
  // Hoisted Functionpublic static final Function parseInt = new Function()
  {
  public Integer apply(String arg)
  {
  return Integer.parseInt(arg);
  }}; // Usage:int result = parseInt.apply(“123”);
  第三部是真实方法的调用。在这一步中匿名内部类和Lambda表达式执行的操作相同,因此没有性能上的差别。不进行捕获的Lambda表达式要比进行static优化过的匿名内部类较优。进行变量捕获的Lambda表达式和匿名内部类表达式性能大致相同。
  在这一节中,我们明显可以看到Lambda表达式的实现表现良好,匿名内部类通常需要我们手动的进行优化来避免额外对象生成,而对于不进行变量捕获的Lambda表达式,JVM已经为我们做好了优化。
  实践中的性能分析
  理解了Lambda的性能模型很是重要,但是实际应用中的总体性能如何呢?我们在使用Java 8 编写了一些软件项目,一般都取得了很好的效果。非变量捕获的Lambda表达式给我们带来了很大的帮助。这里有一个很特殊的例子描述了关于优化方向的一些有趣的问题。
  这个例子的场景是代码需要运行在一个要求GC暂定时间越少越好的系统上。因而我们需要避免创建大量的对象。在这个工程中,我们使用了大量的Lambda表达式来实现回调处理。然而在这些使用Lambda实现的回调中很多并没有捕获局部变量,而是需要引用当前类的变量或者调用当前类的方法。然而目前仍需要对象分配。下面是我们提到的例子的代码:
public MessageProcessor() {} public int processMessages()
{
return queue.read(obj ->
{
if (obj instanceof NewClient)
{
this.processNewClient((NewClient) obj);
}         ...
});
}
  有一个简单的办法解决这个问题,我们将Lambda表达式的代码提前到构造方法中,并将其赋值给一个成员属性。在调用点我们直接引用这个属性即可。下面是修改后的代码:
  Java
private final Consumer handler; public MessageProcessor()
{
handler = obj ->
{if (obj instanceof NewClient)
{
this.processNewClient((NewClient) obj);
}        ...
};
}
public int processMessages()
{
return queue.read(handler);
}
  然而上面的修改后代码给却给整个工程带来了一个严重的问题:性能分析表明,这种修改产生很大的对象申请,其产生的内存申请在总应用的60%以上。
  类似这种无关上下文的优化可能带来其他问题。
  纯粹为了优化的目的,使用了非惯用的代码写法,可读性会稍差一???。
  内存分配方面的问题,示例中为MessageProcessor增加了一个成员属性,使得MessageProcessor对象需要申请更大的内存空间。Lambda表达式的创建和捕获位于构造方式中,使得MessageProcessor的构造方法调用缓慢一些。
  我们遇到这种情况,需要进行内存分析,结合合理的业务用例来进行优化。有些情况下,我们使用成员属性确保为经常调用的Lambda表达式只申请一个对象,这样的缓存策略大有裨益。任何性能调优的科学的方法都可以进行尝试。
  上述的方法也是其他程序员对Lambda表达式进行优化应该使用的。书写整洁,简单,函数式的代码永远是第一步。任何优化,如上面的提前代码作为成员属性,都必须结合真实的具体问题进行处理。变量捕获并申请对象的Lambda表达式并非不好,像我们我们写出new Foo()代码并非一无是处一样。
  除此之外,我们想要写出优的Lambda表达式,常规书写很重要。如果一个Lambda表达式用来表示一个简单的方法,并且没有必要对上下文进行捕获,大多数情况下,一切以简单可读即可。
  总结
  在这片文章中,我们研究了Lambda表达式不是简单的匿名内部类的语法糖,为什么匿名内部类不是Lambda表达式的内部实现机制以及Lambda表达式的具体实现机制。对于大多数情况来说,Lambda表达式要比匿名内部类性能更优。然而现状并非完美,基于测量驱动优化,我们仍然有很大的提升空间。
  Lambda表达式的这种实现形式并非Java 8 所有。Scala曾经通过生成匿名内部类的形式支持Lambda表达式。在Scala 2.12版本,Lambda的实现形式替换为Java 8中的Lambda 工厂机制。后续其他可以在JVM上运行的语言也可能支持Lambda的这种机制。