多个 lambda 方法引用
Multiple lambda method references
可以chain/concatenate像这样对 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;
});
不,您不能按照您的建议使用方法引用。方法引用实际上只是 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);
});
这真没道理。没有代表列表中项目的变量(必须在块之外)并且两个 'statements' 是 lambda 表达式,没有任何应用。
方法引用是避免不必要变量的一种非常巧妙的捷径,但它们只是更冗长的 lambda 表达式的替代品,不能用作块中的独立语句。
可以通过功能接口的默认方法进行链接。但是 "problem" 是当您返回合成表达式的右侧时,推理引擎没有足够的信息来确定左侧是相同的功能接口。
要提供该信息,您必须执行以下语句:
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
}
转换没有意义
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
,则第二个变体就被忽略了。那么我们为什么要有这样一种替代形式呢?
方法引用是作为一种允许单一方法委托的密集语法的特性而发明的,声明和引用参数确实会有所作为。即使用 System.out::println
替换唯一的 s->System.out.println(s)
也不是什么大胜利,但至少有一些。此外,在字节码级别对方法引用进行编码可以更加紧凑,因为可以直接引用目标方法,就像持有 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);
可以chain/concatenate像这样对 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;
});
不,您不能按照您的建议使用方法引用。方法引用实际上只是 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);
});
这真没道理。没有代表列表中项目的变量(必须在块之外)并且两个 'statements' 是 lambda 表达式,没有任何应用。
方法引用是避免不必要变量的一种非常巧妙的捷径,但它们只是更冗长的 lambda 表达式的替代品,不能用作块中的独立语句。
可以通过功能接口的默认方法进行链接。但是 "problem" 是当您返回合成表达式的右侧时,推理引擎没有足够的信息来确定左侧是相同的功能接口。
要提供该信息,您必须执行以下语句:
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
}
转换没有意义
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
,则第二个变体就被忽略了。那么我们为什么要有这样一种替代形式呢?
方法引用是作为一种允许单一方法委托的密集语法的特性而发明的,声明和引用参数确实会有所作为。即使用 System.out::println
替换唯一的 s->System.out.println(s)
也不是什么大胜利,但至少有一些。此外,在字节码级别对方法引用进行编码可以更加紧凑,因为可以直接引用目标方法,就像持有 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);