为什么不能将@FunctionalInterface应用于SAM抽象基类 [英] Why can't @FunctionalInterface be applied to a SAM abstract base class

查看:121
本文介绍了为什么不能将@FunctionalInterface应用于SAM抽象基类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始学习Camel,我看到的第一件事是

I'm just starting to learn Camel and the first thing I see is

    context.addRoutes(new RouteBuilder() {
        public void configure() {
            from("file:data/inbox?noop=true").to("file:data/outbox");
        }
    });

我(合理地恕我直言)试图替换为

which I (reasonably IMHO) try to replace with

    context.addRoutes(()->from("file:data/inbox?noop=true").to("file:data/outbox"));

但这是无效的。

在我挖掘时,我发现lambdas适用于功能接口(如果接口符合条件,则暗示)但@FunctionalInterface注释只能应用于接口(足够公平)并且据我所知,没有抽象类的等效注释。当然,RouteBuilder是一个抽象类。

As I dig, I discover that lambdas apply to functional interfaces (which is be implied, if the interface qualifies) but that the @FunctionalInterface annotation can only be applied to interfaces (fair enough) and there is, as far as I can tell, no equivalent annotation for abstract classes. RouteBuilder is, of course, an abstract class.

为什么lambdas仅限于接口?

Why are lambdas restricted to interfaces?

什么是接口和类之间的本质区别使得功能类不安全/不可预测/不合理?

What is the essential difference between an interface and a class that makes a "functional class" unsafe/unpredictable/unreasonable?

我能理解是否存在某些限定符,例如抽象方法必须是公开的,但我无法解释为什么以上是不合理的。

I could understand if there was some qualifier, such as the abstract method had to be public, but I am at a loss to explain why the above is unreasonable.

推荐答案

这是其中一个JSR-335专家组中的艰难和广泛辩论的决定。一方面,单抽象方法抽象类可能是lambdas的合理转换目标似乎是完全合理的。并且,如果你的心理模型是lambdas只是紧凑的匿名类,那么这将是一个完全合理的想法。

This was one of the most difficult and extensively debated decisions in the JSR-335 Expert Group. On the one hand, it seems entirely reasonable that a single-abstract-method abstract class could be a reasonable conversion target for lambdas. And, if your mental model is "lambdas are just compact anonymous classes", then this would have been a totally reasonable idea.

但是,如果你拉上这个字符串有一段时间,你意识到它会拖累你很多的复杂性和限制 - 为了少数用例。

However, if you pull on this string for a while, you realize it drags with you a lot of complexity and constraints -- for the sake of a minority use case.

其中最糟糕的事情之一是lambda体内名称的含义,作为一种特殊情况,的含义此。在内部类的主体内,有一个非常复杂的查找规则(梳理查找),因为内部类中的名称可以引用超类型的成员从词汇环境中捕获。 (例如,许多错误和益智游戏围绕在内部类体中使用 this ,而不是 Outer.this 。如果我们允许lambda转换来抽象SAM类,我们有两个糟糕的选择;使用内部类的可怕名称查找复杂性来污染所有lambda,或允许转换为抽象类目标但限制访问,使得lambda主体无法引用基类的成员(这会导致它自己的混淆。)得到的规则我们得到的非常干净:除了lambda参数形式之外,lambda体内的名称(包括这个,这只是一个名字)正好意味着它们在外面的意思lambda身体。

One of the worst thing that this drags with it is the meaning of names inside a lambda body, and as a special case, the meaning of this. Within the body of an inner class, there is a terribly complicated lookup rule ("comb lookup") because names inside an inner class could refer to members of a supertype or could be captured from the lexical environment. (For example, many bugs and puzzlers revolve around using this, rather than Outer.this, in inner class bodies.) If we allowed lambda conversion to abstract SAM classes, we'd have two bad choices; pollute all of lambdas with the terrible name lookup complexity of inner classes, or allow conversion to abstract class targets but restrict access such that the lambda body could not refer to members of the base class (which would cause its own sort of confusion.) The resulting rule we get is very clean: apart from the lambda parameter formals, names (including this, which is just a name) inside the lambda body mean exactly what they mean immediately outside the lambda body.

将lambda转换为内部类的另一个问题是对象标识,以及随之而来的VM优化丢失。内部类创建表达式(例如, new Foo(){} )保证具有唯一的对象标识。通过不对lambdas的对象标识做出如此强烈的承诺,我们释放VM以进行许多有用的优化,否则它们无法做到。 (因此,lambda链接和捕获已经比匿名类快 - 并且我们还没有应用优化的深层管道。)

Another problem converting lambdas to inner classes drags with it is object identity, and the attendant loss of VM optimizations. An inner class creation expression (e.g., new Foo() { }) is guaranteed to have a unique object identity. By not committing so strongly to object identity for lambdas, we free the VM to make a lot of useful optimizations that it could otherwise not make. (As a result, lambda linkage and capture is already faster than for anonymous classes -- and there's still a deep pipeline of optimizations we have yet to apply.)

此外,如果你有一个单抽象方法抽象类,并希望能够使用lambdas来创建它们,那么有一个简单的路径来实现它 - 定义一个以函数接口作为参数的工厂方法。 (我们在Java 8中为 ThreadLocal 添加了一个工厂方法来执行此操作。)

Further, if you have a single-abstract-method abstract class and want to be able to use lambdas to create them, there's an easy path to enabling this -- define a factory method that takes a functional interface as an argument. (We added a factory method for ThreadLocal in Java 8 that does this.)

棺材中的最后钉子在我们对现有代码库及其对单抽象方法接口和抽象类的使用进行分析之后,对于lambdas只是对象的方便语法来看世界。我们发现只有很小的百分比基于抽象类。对于所有lambda来说,给一个方法的复杂性和性能问题带来负担似乎很愚蠢,这种方法只能使用不到1%的用途。所以我们做出了勇敢的决定来削减这个用例,以便获得其他99 +%的优势。

The final nail in the coffin for the "lambdas are just convenient syntax for objects" view of the world came after we did an analysis of existing codebases and their use of single-abstract-method interfaces and abstract classes. We found that only a very small percentage were based on abstract classes. It seemed silly to burden all lambdas with the complexity and performance problems of an approach that was only going to benefit less than 1% of the uses. So we made the "brave" decision to cut loose this use case in order to reap the benefits that this enabled for the other 99+%.

这篇关于为什么不能将@FunctionalInterface应用于SAM抽象基类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆