可以链接/连接lambda表达式中的元素所做的事情,如下所示:
list.forEach(s -> {
System.out.println(s.toLowerCase());
System.out.println(s.toUpperCase());
});
有没有办法用方法引用来做到这一点?像这样:
list.forEach({
System.out::println(String::toLowerCase);
System.out::println(String::toCase);
});
我知道我可以在四个单独的调用中执行此操作(这也会更多,这会改变值):
list.replaceAll(String::toLowerCase);
list.forEach(System.out::println);
list.replaceAll(String::toUpperCase);
list.forEach(System.out::println);
我甚至不能像这样轻松做事:
list.forEach({
System.out::println;
System.out::println;
});
答案 0 :(得分:9)
可以通过功能接口的默认方法进行链接。但是“问题”在于,当您返回合成表达式的右侧时,推理引擎没有足够的信息来确定左侧是相同的功能接口。
要提供该信息,您必须转换声明:
List<String> l = Collections.emptyList();
l.forEach(((Consumer<String>)System.out::println).andThen(System.out::println));
首先将其分配给变量:
Consumer<String> cons = System.out::println;
Collections.<String>emptyList().forEach(cons.andThen(System.out::println));
或者你也可以编写你想要的静态帮助方法
Collections.<String>emptyList().forEach(combine(System.out::println, System.out::println));
static <T> Consumer<T> combine(Consumer<T>... consumers) {
// exercise left to the reader
}
答案 1 :(得分:3)
不,你不能像你建议的那样使用方法引用。方法引用实际上只是lambda表达式的语法替代。所以,而不是:
text -> console.print(text)
您可以避免引入不必要的变量,而是使用
console::print
所以当你提到你不能做的事情如:
list.forEach({
System.out::println;
System.out::println;
});
这只是
的语法快捷方式list.forEach({
c -> System.out.println(c);
c -> System.out.println(c);
});
这真的没有意义。没有表示列表中项目的变量(必须在块之外),两个'语句'是lambda表达式,没有任何内容可以应用。
方法引用是一个非常简洁的快捷方式,可以避免使用不必要的变量,但它们只是一个更详细的lambda表达式的替代,不能用作块中的独立语句。
答案 2 :(得分:3)
转换
没有意义list.forEach(s -> {
System.out.println(s.toLowerCase());
System.out.println(s.toUpperCase());
});
到
list.forEach({
System.out::println(String::toLowerCase);
System.out::println(String::toUpperCase);
});
因为没有清晰的胜利,后者甚至包含比前者更多的字符,如果我们使用相同的缩进并插入你从第二个变体中留下的Upper
。那么我们为什么要有这样一种替代形式呢?
方法引用已被发明为允许单个方法委派的密集语法的功能,声明和引用参数确实可以产生影响。即使用s->System.out.println(s)
替换唯一System.out::println
也不是一个大赢家,但至少有一些。此外,在字节码级别对方法引用进行编码可以更紧凑,因为目标方法可以直接引用,就像保存lambda表达式代码的合成方法一样。对于复合方法参考,没有这种紧凑的形式。
由于您所需的操作包含不同类型的操作,因此您可以使用Stream
API来组合此类操作:
list.stream().flatMap(s->Stream.of(s.toLowerCase(), s.toUpperCase()))
.forEach(System.out::println);
如果您想不惜一切代价包含所有内容的方法参考,您可以通过以下方式进行:
list.stream()
.flatMap(s->Stream.<UnaryOperator<String>>of(String::toLowerCase, String::toUpperCase)
.map(f->f.apply(s)))
.forEach(System.out::println);