当前位置: 首页 > 面试题库 >

具有非SAM接口的lambda的Java习惯用法

公冶嘉
2023-03-14
问题内容

在Java中,可以使用lambda而不是匿名类优雅地实现具有单个抽象方法的接口(即SAM类型或功能接口):

    // SAM ActionListener with anonymous implementation
    button.addActionListener(
        new ActionListener(){
            public void actionPerformed(Event e){
                System.out.println("button via anon!");
            }
        }
    );

可以替换为:

    // SAM ActionListener with lambda implementation
    button.addActionListener(
        e -> System.out.println("button via lambda!")
    );

但是对于具有多种抽象方法的接口,lambda无法直接应用。例如,java.awt.event.WindowListener有七个方法。但是通常一大段代码只对定义这七个方法之一感兴趣。

要使用匿名类重写来实现该行为,我们可以:

    // non-SAM with adapter implementation with override
    window.addWindowListener(
        new WindowAdapter() {
            @Override
            public void windowOpened(Event e){
                System.out.println("WindowAdapter opened via override!");
            }
        }
    );

但是lambdas是否有更优雅的方式?

@FunctionalInterface
public interface ActionListener {
    void actionPerformed(Event e);
}

public interface WindowListener {
    void windowOpened(Event e);

    void windowClosing(Event e);
}

public class WindowAdapter implements WindowListener {

    public void windowOpened(Event e){
        System.out.println("windowOpened in adapter!");
    }

    public void windowClosing(Event e){
        System.out.println("windowClosing in adapter!");
    }
}

注意 :@ maythesource.com提出了一个类似但更广泛的问题:“
如果某人想要在匿名类中实现多个方法,该如何处理MouseListener?
”最受支持和接受的答案是使用匿名实现。我的问题是有关非SAM类型的优雅lambda解决方案。


问题答案:

我发现的最优雅的方法是使用匿名桥:

    // SAM bridge with lambda implementation
    window.addWindowListener(
        WindowBridge.windowOpened(
            b -> System.out.println("opening via lambda!")
        )
    );

与SAM类型的情况类似,它比匿名适配器还干净:

    // non-SAM with adapter implementation with override
    window.addWindowListener(
        new WindowAdapter() {
            @Override
            public void windowOpened(Event e){
                System.out.println("WindowAdapter opened via override!");
            }
        }
    );

但是它确实需要带有静态工厂的桥,这有点尴尬:

import java.util.function.Consumer;

public interface WindowBridge {

    // SAM for this method
    public abstract class WindowOpened extends WindowAdapter {
        public abstract void windowOpened(Event e);
    }

    // factory bridge
    public static WindowOpened windowOpened(Consumer<Event> c) {
        return new WindowOpened() {
            public void windowOpened(Event e){
                c.accept(e);
            }
        };
    }

    // SAM for this method
    public abstract class WindowClosing extends WindowAdapter {
        public abstract void windowClosing(Event e);
    }

    // factory bridge
    public static WindowClosing windowClosing(Consumer<Event> c) {
        return new WindowClosing() {
            public void windowClosing(Event e){
                c.accept(e);
            }
        };
    }
}


 类似资料:
  • 在Java中,具有单个抽象方法的接口(即SAM类型或函数接口)可以用lambda而不是匿名类优雅地实现: 可替换为: 但对于具有多个抽象方法的接口,则不能直接应用lambda。例如,有七个方法。但通常一个块代码只对定义这七个方法中的一个感兴趣。 注意:@maythesource.com问了一个类似但更广泛的问题:“如果有人想在匿名类中实现多个方法,他们会如何处理MouseListener?”最受欢

  • 我已经为使用者接口尝试了类似这样的lambda表达式,它没有问题。其他一些lambda表达式不起作用,因为它们返回一些东西,如。 编译和执行没有问题。 所以我遇到的问题是,我认为像这样的lambda表达式总是等效于,所以我希望编译器会给我一个错误,因为您不能从使用者接口返回(或任何其他类型)。显然,编译器正在将lambda表达式转换为一个方法,如果没有return语句,并且调用方法而不实际返回值。

  • 问题内容: 我试图了解Java的行为。使用此接口: 我正在重载这样的方法: 当使用以下对象调用方法时: Java为什么使用: 代替 ? 谢谢 问题答案: 因为编译器只知道是的实例。在编译时根据所涉及表达式的编译时类型确定重载,并且is 的编译时类型为。 (将此与覆盖进行比较,在覆盖时,将根据所涉及的实际类型在 执行 时选择方法实现。)

  • 问题内容: 我正在学习如何使用JavaScript进行OOP。它具有接口概念(例如Java的接口)吗? 这样我就可以创建一个侦听器… 问题答案: 没有“此类必须具有这些功能”的概念(也就是说,本身没有接口),因为: JavaScript继承基于对象,而不是类。除非您意识到:这不是什么大不了的事情 JavaScript是一种 非常 动态的类型化语言-您可以使用适当的方法创建对象,这将使其符合接口,

  • 问题内容: 根据Hibernate文档的这一部分,我应该能够查询HQL中的任何Java类。 http://docs.jboss.org/hibernate/core/3.3/reference/en/html/queryhql.html#queryhql- polymorphism 不幸的是,当我运行此查询时… 我收到消息“未映射事务[[从事务trans,其中trans.envelopeId =:

  • 问题内容: 好的,这是我的问题: 我有一个包含interfaces的列表-和扩展该接口的接口的列表:。我要设置。我不希望使用任何东西或会花费更多内存的东西,因为我正在做的事情已经非常耗费成本。我确实需要能够说。我已经尝试过,但是后来我无法将接口添加到列表中,只能将SubInterfaces 添加到列表中。有什么建议? 我希望能够做这样的事情: RecordKeeper类是包含接口列表的类(NOT