Java8 Lambdas vs Anonymous 类

由于 Java8最近刚刚发布,它全新的 lambda 表达式看起来非常酷,我想知道这是否意味着我们已经习惯了的 Anonymous 类的消亡。

我对此做了一些研究,发现了一些很酷的例子,说明 Lambda 表达式将如何系统地替换这些类,比如 Collection 的 sort 方法,该方法用于获取一个 Compaator 的 Anonymous 实例来执行排序:

Collections.sort(personList, new Comparator<Person>(){
public int compare(Person p1, Person p2){
return p1.firstName.compareTo(p2.firstName);
}
});

Now can be done using Lambdas:

Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));

而且看起来惊人的简洁。所以我的问题是,有没有什么理由继续在 java8中而不是在 Lambdas 中使用这些类呢?

剪辑

同样的问题,但是在相反的方向上,使用 Lambdas 而不是 Anonymous 类有什么好处,因为 Lambdas 只能用于单个方法接口,这个新特性只是在少数情况下使用的一个快捷方式,还是它真的有用?

75810 次浏览

Lambdas 虽然是一个很棒的特性,但只能用于 SAM 类型。也就是说,只有一个抽象方法的接口。只要接口包含多于1个抽象方法,它就会失败。这就是匿名类的用武之地。

所以,我们不能忽略匿名类。仅供参考,通过跳过 p1p2的类型声明,您的 sort()方法可以更加简化:

Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));

你也可以在这里使用方法引用。你可以在 Person类中添加一个 compareByFirstName()方法,然后使用:

Collections.sort(personList, Person::compareByFirstName);

或者,为 firstName添加一个 getter,直接从 Comparator.comparing()方法得到 Comparator:

Collections.sort(personList, Comparator.comparing(Person::getFirstName));

匿名内部类(AIC)可用于创建抽象类或具体类的子类。AIC 还可以提供接口的具体实现,包括添加状态(字段)。AIC 的一个实例可以在它的方法体中使用 this来引用,因此可以对它调用进一步的方法,它的状态可以随着时间的推移而变化,等等。这些都不适用于 Lambdas。

I'd guess that the majority of uses of AICs were to provide stateless implementations of single functions and so can be replaced with lambda expressions, but there are other uses of AICs for which lambdas cannot be used. AICs are here to stay.

更新

Another difference between AICs and lambda expressions is that AICs introduce a new scope. That is, names are resolved from the AIC's superclasses and interfaces and can shadow names that occur in the lexically enclosing environment. For lambdas, all names are resolved lexically.

Java 8中的 Lambda 是为函数式编程而引入的。可以避免样板代码的地方。我看到一篇关于 Lambda 的有趣文章。

Http://radar.oreilly.com/2014/04/whats-new-in-java-8-lambdas.html

对于简单的逻辑,建议使用 lambda 函数。如果使用 lambdas 实现复杂的逻辑,那么在出现问题时调试代码将会带来额外的开销。

匿名类的 Lambda 性能

When application is launched each class file must be loaded and verified.

编译器将匿名类作为给定类或接口的新子类型进行处理,因此将为每个类生成一个新的类文件。

Lambdas 在字节码生成方面有所不同,它们更有效,使用了 JDK7附带的 invokedDynamic 指令。

对于 Lambdas,此指令用于将字节码中的 lambda 表达式转换延迟到运行时。(指令将仅首次调用)

因此,Lambda 表达式将成为一个静态方法(在运行时创建)。 (与状态和状态完整的情况有一点小区别,它们是通过生成的方法参数来解析的)

存在以下差异:

1)语法

Lambda expressions looks neat as compared to Anonymous Inner Class (AIC)

public static void main(String[] args) {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("in run");
}
};


Thread t = new Thread(r);
t.start();
}


//syntax of lambda expression
public static void main(String[] args) {
Runnable r = ()->{System.out.println("in run");};
Thread t = new Thread(r);
t.start();
}

2)范围

匿名内部类是一个类,这意味着它具有内部类中定义的变量的作用域。

Lambda 表达式不是它自己的作用域,而是封闭作用域的一部分。

Similar rule applies for 好极了 and this keyword when using inside anonymous inner class and lambda expression. In case of anonymous inner class this keyword refers to local scope and super keyword refers to the anonymous class’s super class. While in case of lambda expression this keyword refers to the object of the enclosing type and super will refer to the enclosing class’s super class.

//AIC
public static void main(String[] args) {
final int cnt = 0;
Runnable r = new Runnable() {
@Override
public void run() {
int cnt = 5;
System.out.println("in run" + cnt);
}
};


Thread t = new Thread(r);
t.start();
}


//Lambda
public static void main(String[] args) {
final int cnt = 0;
Runnable r = ()->{
int cnt = 5; //compilation error
System.out.println("in run"+cnt);};
Thread t = new Thread(r);
t.start();
}

3) Performance

在运行时匿名内部类需要类加载、内存分配和对象初始化以及非静态方法的调用,而 lambda 表达式是纯粹的编译时活动,在运行时不会产生额外的成本。因此,与匿名内部类相比,lambda 表达式的性能更好。**

* * 我确实认识到这一点并不完全正确。请参考以下问题了解详情

  • Lambda 语法不需要编写 java 可以推断出的明显代码。
  • 通过使用 invoke dynamicLambda 不会转换回匿名类在编译时(Java 不需要通过创建对象,只需要关心方法的签名,就可以绑定到方法而不需要创建对象
  • Lambda 更强调我们想要做什么,而不是我们必须做什么才能做到

匿名类仍然存在,因为 lambda 适用于具有单个抽象方法的函数,但对于其他情况,匿名内部类是您的救星。

+----------------------------------+----------------------------------------------------------+---------------------------------------------+
|                                  |                                       Lambdas            |              Anonymous classes              |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Definition                       | An anonymous method that can be created without belonging| An inner class without a name.              |
|                                  | to any class                                             |                                             |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Scope of variables of main class | Available                                                | Not available                               |
| (this and super keywords also)   |                                                          |                                             |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Lines of codes                   | Reduced the lines of code. It’s a short form of          | Have more lines of code compared to lambdas |
|                                  | anonymous class.                                         |                                             |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Criteria for creating            | Needs to be Functional Interface, ie interface with      | Can use interfaces(including Functional     |
|                                  | only one abstract method. Example : Runnable Interface   | interfaces) and abstract classes to create. |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+
| Example:                         | Runnable r = ()->{System.out.println("Hello World");};   | Runnable r = new Runnable() {               |
|                                  |                                                          |         @Override                           |
|                                  |                                                          |         public void run() {                 |
|                                  |                                                          |          System.out.println("Hello World"); |
|                                  |                                                          |                                        }    |
|                                  |                                                          |     };                                      |
+----------------------------------+----------------------------------------------------------+---------------------------------------------+

Lambdas 表达式只包含匿名内部类的一个非常特殊的情况。您可以认为 Anonymous Inside 类是 Lambdas Expression 的超集

Lambdas Expression ⊂ Anonymous Inner classes

在某些场景中,Anno.inner 类可以被 Lambda Expression 替换:

  1. 如果要实现的内部类是函数式接口(只有一个抽象方法)

例如:

Interface A{
public void m1();
public void m2();
}


Interface B{
public void m();
}


Class Temp{
public static void main(String[] args){
// Anonymous inner class implementation
A a = new A()
{
public void m1(){
//
}
public void m2(){
//
}
};
a.m1(); or a.m2();
 

// Here B is a functional Interface so we can replace the anonymous class to Lambda Expression
B b = () => { ... }
b.m();
  

}
}

除此之外,两者的编译风格也存在一些差异。对于 Lambda 表达式编译器不生成任何其他类,但它为 Anon 生成。内心世界