【问题标题】:Lambda Expressions for Abstract Classes抽象类的 Lambda 表达式
【发布时间】:2015-12-22 21:05:23
【问题描述】:

我有一个带有一个抽象方法的抽象类。如何使用 lambda 表达式来实例化它。它不能成为接口,因为它扩展了一个类。

public class Concrete<T> {
    // Has a bunch of predefined methods.
}


public abstract class Abstract<T> extends Concrete<T> {
    public T getSomething();
    // Uses inherited methods from Concrete class
}

public class Driver {
    public static void main(String[] args) {
        System.out.println(new Abstract<String>() {
            public String getSomething() {
                // Returns something using inherited methods from Abstract              
                // Class and Concrete Class
            }
        });
    }
}

【问题讨论】:

  • 在这种情况下,包含一个 MCVE 会很有帮助,其中您有一些超类、抽象类和一个您希望简化为 lambda 表达式的实例化
  • 为什么不能为 getSomething() 创建一个接口并让抽象类扩展 Concrete 并实现接口?

标签: java lambda


【解决方案1】:

正如 Sleiman Jneidi 在他的回答中指出的那样,您不能直接将 lambda 表达式作为抽象类的目标。但是,您可以使用一种解决方法:

public class AbstractLambda<T> extends Abstract<T>
{
    private final Supplier<? extends T> supplier;
    public AbstractLambda(Supplier<? extends T> supplier)
    {
        this.supplier = supplier;
    }

    @Override
    public T getSomething()
    {
        return this.supplier.get();
    }
}

这可以与 lambda 表达式一起使用:

Abstract<String> a = new AbstractLambda<>(() -> "Hello World");
System.out.println(a.getSomething()); // prints 'Hello World'

如果您的getSomething(...) 方法有参数,请使用java.util.function.Functionjava.util.function 包中的适当接口,而不是java.util.function.Supplier


这也是java.lang.Thread 让您使用Runnable lambda 而不必继承类的方式:

Thread t = new Thread(() -> System.out.println("Hello World"));
t.start();

【讨论】:

  • 我不同意 Thread 以类似的方式定义。 Runnable 作为 Thread 的构造函数参数是自然且 Runnable 简单的 FunctionalInterface。它看起来与此解决方法不同。
  • @snap 它们是相似的。唯一的区别是 Thread 不是抽象的,但除此之外它是相同的模式:扩展 Thread 并覆盖 run() 或将 Runnable 传递给 Thread 构造函数。
【解决方案2】:

不,你不能这样做。 Lambda 必须针对接口上的单个抽象方法 (SAM),并且它们不适用于抽象类上的单个抽象方法。就是这样,你必须接受它,

尽管拥有它们是有意义的,但语言设计者认为通过在 SAM 抽象类上允许 lambdas 引入的复杂性是不值得的。

As a reference, thats Brian Goetz 关于在 SAM 抽象类上允许 lambda 的说法。

Brian 邮件中的主要要点:

  • 只有 3% 的 lambda 候选者 内部类实例以抽象类为目标

  • 使模型复杂化 为了几个百分比的用例似乎是一个糟糕的交易

【讨论】:

  • “就是这样,你必须接受它”。不,我不会接受的。我无法接受。
【解决方案3】:

与此同时,我们现在在接口中有默认实现。我处于类似情况,尝试使用抽象类。切换到具有 2 种方法的接口,其中一种具有默认实现。 Java 将接口标识为具有单个抽象方法,我可以使用 lambda 语法将接口的实现作为参数传递。

缺点是如果他们真的坚持,有人可以通过在某些(匿名或非匿名)类中显式实现接口来覆盖具有默认实现的方法。而且您不能限制这一点,因为在接口上所有方法都是公共的。根据您的情况,这可能没什么大不了的。

【讨论】:

    猜你喜欢
    • 2011-05-05
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 2014-07-12
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多