Java8 Lambdas与匿名类

Ami*_*leb 103 java lambda anonymous-class java-8

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

我一直在研究这个问题,并找到了一些很酷的例子,说明Lambda表达式将如何系统地替换这些类,例如Collection的sort方法,它用于获取Comparator的Anonymous实例来执行排序:

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

现在可以使用Lambdas完成:

Collections.sort(personList, (Person p1, Person p2) -> p1.firstName.compareTo(p2.firstName));
Run Code Online (Sandbox Code Playgroud)

而且看起来非常简洁.所以我的问题是,有没有理由继续在Java8中使用这些类而不是Lambdas?

编辑

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

Stu*_*rks 97

匿名内部类(AIC)可用于创建抽象类或具体类的子类.AIC还可以提供接口的具体实现,包括添加状态(字段).可以this在其方法体中引用AIC的实例,因此可以在其上调用其他方法,其状态可以随时间变化,等等.这些都不适用于lambdas.

我猜测AIC的大部分用途是提供单个函数的无状态实现,因此可以用lambda表达式替换,但是还有其他用途的AIC不能使用lambda.AIC将留在这里.

UPDATE

AIC和lambda表达式之间的另一个区别是AIC引入了一个新的范围.也就是说,名称是从AIC的超类和接口中解析出来的,并且可以影响在词汇封闭环境中出现的名称.对于lambdas,所有名称都是词法解析的.

  • Lambda 可以有状态。在这方面,我认为 Lambda 和 AIC 没有区别。 (3认同)
  • @nosid AIC 与任何类的实例一样,可以在字段中保存状态,并且该状态可由类的任何方法访问(并且可能是可变的)。这种状态一直存在,直到对象被 GC 为止,即,它具有不确定的范围,因此它可以在方法调用之间持续存在。lambda 具有不定范围的唯一状态是在遇到 lambda 时捕获的;这种状态是不可变的。lambda 中的局部变量是可变的,但它们仅在 lambda 调用正在进行时才存在。 (2认同)
  • AIC将创建一个像这样的文件,`A $ 1.class`但是Lambda不会.我可以在差异中添加这个吗? (2认同)
  • @UnKnown 这主要是一个实现问题;它不会影响一个程序如何使用 AIC 与 lambdas,这就是这个问题的主要内容。请注意,lambda 表达式确实会生成一个名称类似于“LambdaClass$$Lambda$1/1078694789”的类。但是,这个类是由 lambda 元工厂即时生成的,而不是由 `javac` 生成的,因此没有相应的 `.class` 文件。然而,这又是一个实现问题。 (2认同)

Roh*_*ain 58

Lambda虽然是一个很棒的功能,但只适用于SAM类型.也就是说,只有一个抽象方法的接口.只要您的界面包含多个抽象方法,它就会失败.这就是匿名类有用的地方.

所以,不,我们不能只忽略匿名类.而就通知你,你的sort()方法可以更简化,通过跳过类型声明p1p2:

Collections.sort(personList, (p1, p2) -> p1.firstName.compareTo(p2.firstName));
Run Code Online (Sandbox Code Playgroud)

您也可以在此处使用方法参考.要么compareByFirstName()Person类中添加方法,请使用:

Collections.sort(personList, Person::compareByFirstName);
Run Code Online (Sandbox Code Playgroud)

或者,为firstNameget 方法添加一个getter ,直接获取Comparatorfrom Comparator.comparing()方法:

Collections.sort(personList, Comparator.comparing(Person::getFirstName));
Run Code Online (Sandbox Code Playgroud)

  • 我知道,但在可读性方面我更喜欢长篇,因为否则找出这些变量的来源可能会让人感到困惑. (4认同)

小智 31

使用匿名类进行Lambda性能

启动应用程序时,必须加载并验证每个类文件.

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

Lambda与字节码生成不同,它们更有效,使用JDK7附带的invokedynamic指令.

对于Lambdas,此指令用于延迟在字节码中直接转换lambda表达式,直到运行时.(仅在第一次调用指令)

因此,Lambda表达式将成为静态方法(在运行时创建).(与stateles和statefull情况有一点不同,它们是通过生成的方法参数解决的)

  • @AndreiTomashpolskiy 1.请礼貌.2.阅读编译工程师的评论:https://habrahabr.ru/post/313350/comments/#comment_9885460 (3认同)

ato*_*217 12

有以下差异:

1)语法

与匿名内部类(AIC)相比,Lambda表达式看起来很整洁

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();
}
Run Code Online (Sandbox Code Playgroud)

2)范围

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

然而,lambda表达式不是它自己的范围,而是封闭范围的一部分.

当在匿名内部类和lambda表达式中使用时,类似的规则适用于superthis关键字.在匿名内部类的情况下,此关键字引用本地范围,而超级关键字引用匿名类的超类.在lambda表达式的情况下,此关键字引用封闭类型的对象,而super将引用封闭类的超类.

//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();
    }
Run Code Online (Sandbox Code Playgroud)

3)表现

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

**我确实意识到这一点并不完全正确.有关详情,请参阅以下问题. Lambda vs匿名内部类性能:减少ClassLoader的负载?