【问题标题】:Is there a way to turn an existing interface into a functional interface?有没有办法将现有接口变成功能接口?
【发布时间】:2014-04-25 04:51:22
【问题描述】:

我使用的界面看起来像这样:

public interface ObjectListener {
    public void objectAdded(Object o);
    public void objectRemoved(Object o);
}

而且我目前正在使用匿名类来实现接口,但我不关心这两种方法中的一种。类似这样的东西:

someObject.addListener(new ObjectListener() {

    @Override
    public void objectAdded(Object o) {
        doSomething(o);
    }

    @Override
    public void objectRemoved(Object o) {}
});

现在,我一直在尽可能使用 Java 8 中的新 lambda 表达式,并且我想在这种情况下使用增加的简单性。毕竟我只实现了其中一种方法,但是由于接口中有两种方法,所以不能在lambda表达式中使用。

我有办法绕过这个限制吗?

【问题讨论】:

标签: java lambda java-8 functional-interface


【解决方案1】:

为了在 lambda 表达式中重用不是函数式接口的现有接口,您还必须使用新的 Java8 特性、默认方法。

在这种情况下,如果您想使用 lambda 表达式代替匿名类,则必须执行以下操作。

首先,你需要将 ObjectListener 重新定义为一个新的接口:

public interface ObjectAddedListener extends ObjectListener {
    @Override
    default public void objectRemoved(Object o) {}
}

我们只是简单地为我们不关心的方法添加一个空的默认实现,这使得 objectAdded() 方法成为接口中唯一的抽象方法。

然后您可以使用新类型代替任何 ObjectListener,并且由于新接口中只有一个方法没有实现,因此您可以在 lambda 表达式中使用它,如下所示:

ObjectAddedListener listener = o -> doSomething(o);
someObject.addListener(listener);

请注意,如果您想直接在 addListener() 方法中使用此新类型,您首先需要将 lambda 表达式转换为新定义的类型,如下所示:

someObject.addListener((ObjectAddedListener) o -> doSomething(o));

【讨论】:

  • 或者,如果您可以编辑ObjectListener 代码,您可以简单地将{} 添加为objectRemoved() 的主体,即:) 无需继承和类型转换。
  • 在这种情况下,ObjectListener 不是我的代码,因此需要扩展接口。
  • 此解决方案仅适用于内部代码,这些代码永远不会成为导出的公共 API 的一部分,并且将由相同的程序员维护。原因是接口中的默认方法不会在尝试实现接口但没有实现所有方法的客户端代码中导致编译时错误。对于客户端将要访问的代码,最好将方法分离到它们自己的接口定义中。
【解决方案2】:

重构不是单个抽象方法 (SAM) 接口的现有接口以支持与 Java 8 lambda 表达式一起使用的另一种方法是将方法分离为它们自己的类型。如果接口中的大多数方法都可以与 lambda 一起使用,则这是最合适的。

例如,考虑一个允许通过字段名称以编程方式访问数据模型对象的接口。该接口包含一个读取字段的方法和另一个修改字段的方法:

interface Accessible {
    Object acc(String fieldName);
    void mut(String fieldName, Object val);
}

似乎有可能,甚至可能,这两种方法都可以与 lambda 一起使用,以获得更好的表现力和简单性。为了实现这一点,可以通过这种方式重构接口(仅作为示例;有几种方法可以做到这一点):

class Accessors {

    private Accessors() { throw new AssertionError(); }

    interface Accessor {
         Object acc(String fieldName);
    }

    interface Mutator {
         void mut(String fieldName, Object val);
    }
}

提供对数据模型对象的读写访问的类现在需要同时实现Accessors.AccessorAccessors.Mutator。但重要的是,这些接口(现在都是函数式接口)可以用作在代码中使用 Java 8 lambda 表达式的策略。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-14
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多