Java 使用(空)默认方法创建FunctionInterface
在Java8中,引入了接口的默认方法,用于在不破坏向后兼容性的情况下向现有接口添加方法 由于默认方法是非抽象的,因此可以使用它们与多个可重写方法建立Java 使用(空)默认方法创建FunctionInterface,java,interface,java-8,functional-interface,Java,Interface,Java 8,Functional Interface,在Java8中,引入了接口的默认方法,用于在不破坏向后兼容性的情况下向现有接口添加方法 由于默认方法是非抽象的,因此可以使用它们与多个可重写方法建立功能接口 比如说,StringTransformer接口有两种方法,transform,用于转换给定的String,以及end以释放资源: interface StringTransformer { String transform(String s); void end(); } 但是有些实现可能没有可用的资源,因此我们可以为e
功能接口
比如说,StringTransformer
接口有两种方法,transform
,用于转换给定的String
,以及end
以释放资源:
interface StringTransformer {
String transform(String s);
void end();
}
但是有些实现可能没有可用的资源,因此我们可以为end
提供空的默认方法,并为StringTransformer
使用lambda函数和方法参考:
interface StringTransformer {
String transform(String s);
default void end() {
}
}
StringTransformer x = String::trim;
StringTransformer y = (x -> x + x);
这是一种有效/最佳实践,还是一种反模式和滥用默认方法?从理论上讲,这没有什么错。您可以使用这种类型的接口。
我想从你需要这种构造的条件开始
向后能力
正如您所提到的,引入默认方法是为了维护向后功能,所以使用默认方法使接口向后兼容是合理的
可选实施
默认的空方法可用于使任何方法的实现成为可选的。但是,您可以使用默认实现为此类接口创建一个抽象适配器类。这种策略已经使用了很长时间,它优于接口中的默认方法,对于抽象类,我们可以定义复杂的默认实现。此外,我们可以在开始时使用一个简单的空方法,然后将其更改为具有复杂的默认实现,而在接口中使用默认方法的情况下,由于类的某些功能不可用,因此不可能实现
此外,Java8还引入了functionanterface
,将任何接口标记为功能接口。根据官方指南,如果接口只有一个方法,但没有使用功能接口注释,则应避免使用lambda和方法引用。我认为,将可作为数据类型引用的常规接口转换为功能接口不是一个好主意
如果您这样做,那么用户可以在实际需要该接口作为类型以及创建lambda的位置实现StringTransform。这降低了可读性和可维护性。如中所述,允许创建多个方法仍然是功能接口的接口,这是默认方法的目的之一。正如前面提到的,您将在JavaAPI本身中找到示例,例如,拥有default
方法并有意成为功能接口
无论默认实现是否什么都不做,更重要的问题是,这个默认实现有多自然。仅仅为了使lambdas成为可能,这感觉像是一个乱七八糟的问题吗?或者它确实是一些甚至大多数实现所使用的方式(不管它们是如何实现的)
不需要特殊的清理操作可能确实是一种常见情况,即使您遵循注释中的建议,让您的接口扩展并命名方法close
,而不是end
。请注意,同样地,Stream
实现了AutoCloseable
,其默认行为是在close()
上不执行任何操作。您甚至可以按照该模式将清理操作指定为单独的Runnable
,类似于:
分别
如果使用导入静态
。它还可以确保安全关闭,如果您链接多个操作,如
try(StringTransformer t = transformer(String::toUpperCase)
.onClose(()->System.out.println("close 1"))
.onClose(()->{ throw new IllegalStateException(); })) {
System.out.println(t.apply("some text"));
}
或
请注意,try(StringTransformer.this){r.run();}
是Java9语法。对于Java8,您需要try(StringTransformer toClose=StringTransformer.this){r.run();}
意见:这是对默认方法的滥用另外,如果您想要一个清理资源的方法,您应该实现和它的方法,允许调用者使用。小结:Lambda是函数,不是对象。@Andreas在我看来,它是默认方法的一个非常传统的用例。你可能会争辩说,将本质上是抽象类的东西实例化为lambda是不合适的,但即便如此,这与你的链接也有点不同。函数接口是一个常规接口。没有什么不规则的。“他们在哪里实际需要这个接口作为一个类型”是什么意思?
try(StringTransformer t =
StringTransformer.transformer(String::toUpperCase)
.onClose(()->System.out.println("close"))) {
System.out.println(t.apply("some text"));
}
try(StringTransformer t = transformer(String::toUpperCase)
.onClose(()->System.out.println("close 1"))) {
System.out.println(t.apply("some text"));
}
try(StringTransformer t = transformer(String::toUpperCase)
.onClose(()->System.out.println("close 1"))
.onClose(()->{ throw new IllegalStateException(); })) {
System.out.println(t.apply("some text"));
}
try(StringTransformer t = transformer(String::toUpperCase)
.onClose(()->{ throw new IllegalStateException("outer fail"); })
.onClose(()->{ throw new IllegalStateException("inner fail"); })){
System.out.println(t.apply("some text"));
}