Java 8允许您在不同的上下文中使用相同的lambda表达式。请考虑以下代码来演示:
public class LambdasTypeCheck {
public static void main(String []args) {
//Same lambda expression can be used in different contexts.
Predicate<List<String>> predicate = (l) -> l.add("1");
Consumer<List<String>> consumer = (l) -> l.add("1");
}
}
lambda表达式(l) -> l.add("1");
在两个地方重复。我怎样才能避免这种重复?我可以重用这个lambda表达式的一种方法是,如果有一些接口/类是所有lambda表达式的父类,那么我可以将任何lambda表达式赋给这样的接口/类的引用。
答案 0 :(得分:4)
您没有定义您担心的“重复”。
如果是困扰你的代码重复(或者说,对有意应该相同的表达之间可能存在的不一致的担心),你可以使用
Predicate<List<String>> predicate = (l) -> l.add("1");
Consumer<List<String>> consumer = predicate::test;
避免它。
如果您希望lambda表达式真正由同一个实例表示,您可以创建一个组合interface
:
interface PredicateAndConsumer<T> extends Predicate<T>, Consumer<T> {
public default void accept(T t) { test(t); }
}
PredicateAndConsumer<List<String>> pAndC = (l) -> l.add("1");
Predicate<List<String>> predicate = pAndC;
Consumer<List<String>> consumer = pAndC;
因此,正如您所看到的,您可以在需要pAndC
或Predicate<List<String>>
的两种情境中使用Consumer<List<String>>
。
然而,这样做没什么好处。在这种特殊情况下,我们可以安全地假设对于大多数JRE而言,引入另一个interface
的开销高于通过一个lambda表达式实现它的节省。
您也可以考虑“Is method reference caching a good idea in Java 8?”的答案。总而言之,您的示例表达式不捕获值,因此将在Oracle的参考实现中实现为单例(并且可能在所有替代实现中也是如此)。所以这里我们讨论的是在运行时环境中是否创建了一个或两个不可变常量...
答案 1 :(得分:2)
使用相同代码在同一方法中实现两个不同接口的机会是,让我们面对它,几乎为零。但是,即使这样,当遇到重复的代码时,你也可以做你可能经常做的事情:创建一个新的方法/类。
public class LambdasTypeCheck {
public static void main(String []args) {
Predicate<List<String>> predicate = LambdasTypeCheck::addOne;
Consumer<List<String>> consumer = LambdasTypeCheck::addOne;
}
public static boolean addOne(List<String> list) {
return list.add("1");
}
}
当你想捕捉价值时,这并不起作用:
String one = "1";
Predicate<List<String>> predicate = (l) -> l.add(one);
Consumer<List<String>> consumer = (l) -> l.add(one);
在这里你必须使用lambda表达式,你只能使用@Holger建议的解决方案。但话说回来:这个(方法中的代码重复)是一个非常非常不可能的场景:)