使现有Java接口功能化是否存在危险?

使现有Java接口功能化是否存在危险?,java,lambda,functional-interface,Java,Lambda,Functional Interface,通常,在大型项目的环境中,将现有的、普遍使用的接口转换为功能接口是否安全 例如,给定一个现有接口和类: public interface Interface { public double calculateSomething(double x); public void doSomething(); } 这是由 class InterfaceImplementer implements Interface { public double calculateSome

通常,在大型项目的环境中,将现有的、普遍使用的接口转换为功能接口是否安全

例如,给定一个现有接口和类:

public interface Interface {
    public double calculateSomething(double x);
    public void doSomething();
}
这是由

class InterfaceImplementer implements Interface {

     public double calculateSomething(double x) {
          return 2 * x;
     }

     public void doSomething() {
         // insert specific behavior here
     } 
}
通过将除一个方法外的所有方法定义为默认方法,我是否可以安全地更改接口:

public interface Interface {
    public double calculateSomething(double x);

    default void doSomething() {
         // insert some default behavior here
    }
}
这样我就可以从将对象定义为

Interface object = new InterfaceImplementer() {

    @Override
    public double calculateSomething(double x) {
        return 2 * x;
    }
};

同时仍然能够以旧的、乏味的方式定义对象

据我所知,这不存在打乱任何现有代码的风险,而且我已经对一个大型项目进行了这样的更改,并且没有运行时或编译错误。但我想确认一下这是否符合常识和最佳实践。

各州:

但是,无论接口声明中是否存在FunctionInterface注释,编译器都会将满足函数接口定义的任何接口视为函数接口


因此,添加该注释是没有风险的。

在java代码级别上,我可以想到一个问题:由于该接口在过去的某个时候已经包含了2个方法,以后可能需要向其添加另一个方法。您将无法向功能接口添加其他方法,因为它必须保持功能接口,以便您可以将其用作功能接口。您必须创建一个继承自此接口的接口。这就引出了重点


以前在一个接口中包含这两个方法可能是合乎逻辑的,但现在真的合乎逻辑吗重构代码,分离接口;要么使一个接口扩展另一个接口,要么使用从两个接口继承的接口,即调用。如果要将接口用作功能接口,请使其功能化。它会干净的。这是可以理解的。将来,您可以向其中一个接口添加方法,而无需进一步重构。

根据定义,只有一个非默认方法(一个类中只需实现一个方法)的任何接口都是功能接口。这是一条好规则


但是,
@functionalterface
注释的优点是强制执行“功能接口的接口中只有一个方法”规则。所以,如果您将它添加到原始的两个方法接口中,您将得到一个编译器错误。因此,通过明确添加
@Functional interface
您可以声明您的意图,并让未来的维护人员更清楚地了解您的代码。

好吧,可能会破坏任何东西的不是
@Functional
,但添加默认实现可能会导致实现的抽象类或扩展多个接口的接口的编译错误,这些接口声明具有覆盖等效签名的方法:

以下内容很好:

interface I {
    void a();
}

interface J {
    void a();
}

interface K extends I, J {}
但这并不是:

interface I {
    default void a() {}
}

interface J {
    void a();
}

interface K extends I, J {}
从I继承的默认方法a()与从J继承的另一个方法冲突


因此,如果您在库中执行此操作,使用此方法的代码在更改后可能无法编译。

默认方法不算在内,@Dariusz(“仅一个抽象方法”)。您不是唯一错过这一点的人,我的问题并不是暗示这就是我所做的更改。我会解决这个问题。我也看到了你的观点,并且去掉了
doAThing()
我认为没有理由
doSomething
在默认情况下什么都不做。将接口方法标记为public是不必要的,因为所有方法都是隐式公共的。啊,为了清晰起见,我在其中添加了注释,但这不是我想要的。初始接口不起作用,因为它有多个非默认方法。我要问的是将界面中定义的
doSomething()
public
更改为
default
,并将其定义为
doAThing()
。这说明问题了吗?@FrankHarris你在评论中所写的内容与你在上述问题中所写的内容不同。如果你想在将来添加一个方法,你不能将其设为默认值吗?@FrankHarris是真的,但同样,这些观点不是“有风险的”,你对问题的措辞听起来像是在问这是否可能是一个“突破性的改变”这就是问题所在,是的。两个主要的限制是,我没有资源进行大型重构,而这种小型重构不能破坏任何东西。我的理解是这样的;如果它在更改之前工作,那么它必须在更改之后工作,但是它允许我在将来更有效地使用接口,而不必对现有代码进行任何其他更改。关于不能添加更多的方法,如果将来不作为功能接口是有意义的,那么我可以进行更大的重构?以前,它有很多非默认方法。我所做的更改是将默认行为添加到除一个之外的所有对象中(实际上,对于实现者类的每个实例,都会覆盖一个方法,因此它非常适合使其功能化)。因此,我不需要对实现者进行任何更改,但在大多数情况下,我可以避免使用实现者。问题是将这些非默认方法转换为默认方法是否存在任何风险。同样,我认为答案是非常明确的“不”,但我想确保我没有忽视什么。风险?在我看来,你最终可能会得到一个抽象类,它被简单地伪装成一个接口(这在很多方面都是有意义的,但根据我的经验,过度使用默认值并不是一个好主意——这些默认值是为了能够向现有接口添加额外的代码,而不是为了用它来构建类)。我会考虑重构以使意图更加清晰。
interface I {
    default void a() {}
}

interface J {
    void a();
}

interface K extends I, J {}