Java 多个lambda方法引用

Java 多个lambda方法引用,java,lambda,java-8,method-reference,Java,Lambda,Java 8,Method Reference,可以链接/连接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); });

可以链接/连接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.forEach({
    System.out::println;
    System.out::println;
});
有没有一种方法也可以通过方法引用来实现这一点?大概是这样的:

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.forEach({
    System.out::println;
    System.out::println;
});
我知道我可以在四个单独的调用中实现这一点(这也可以做得更多,即改变值):

我甚至不能做像这样简单的事情:

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.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);
});
这真的毫无意义。列表中没有表示项的变量(必须在块之外),这两个“语句”是lambda表达式,没有任何应用


方法引用是一个非常简洁的快捷方式,可以避免不必要的变量,但它们只是更详细的lambda表达式的替代品,不能用作块中的独立语句。

通过函数接口的默认方法可以链接。但“问题”在于,当您返回合成表达式的右侧时,推理机没有足够的信息来确定左侧是同一个函数接口

要提供该信息,您必须使用以下语句:

  List<String> l = Collections.emptyList();
  l.forEach(((Consumer<String>)System.out::println).andThen(System.out::println));
List l=Collections.emptyList();
l、 forEach(((Consumer)System.out::println.)和(System.out::println));
或者先将其分配给变量:

  Consumer<String> cons = System.out::println;
  Collections.<String>emptyList().forEach(cons.andThen(System.out::println));
cons=System.out::println;
Collections.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
}
forEach(combine(System.out::println,System.out::println)); 静态用户联合收割机(用户…用户){ //留给读者的练习 }
转换没有意义

list.forEach(s -> {
    System.out.println(s.toLowerCase());
    System.out.println(s.toUpperCase());
});

由于在清晰性方面没有胜算,如果我们使用相同的缩进并插入
上部
,后者甚至比前者包含更多的字符,那么您就省去了第二个变体。那么,我们为什么要有这样一种替代形式呢

方法引用作为一种特性被发明出来,它允许对单个方法委托使用密集的语法,如果声明和引用参数真的会有所不同的话。即使用
System.out::println
替换一个单独的
s->System.out.println
,也不是什么大赢家,但至少有一些。此外,在字节码级别编码方法引用可以更紧凑,因为目标方法可以直接引用,就像保存lambda表达式代码的合成方法一样。对于复合方法引用,没有这样的紧凑形式


由于所需的操作由不同类型的操作组成,因此可以使用
API,该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);
list.stream()
.flatMap->Stream.of(String::toLowerCase,String::toUpperCase)
.map(f->f.apply(s)))
.forEach(System.out::println);

方法引用是一个表达式,它生成一个引用类型的值,并且没有副作用。显然,试图在块中使用这样一个表达式作为语句是没有意义的。老实说,我不知道你为什么想要这样——你只是喜欢在代码中看到一个双冒号而不是一个单点吗?这不都是关于糖的吗;)甲骨文MOOC中说要尽可能多地使用方法引用。但考虑到这带来的复杂性,我不会——只是它使代码更具可读性。这一个不起作用:
list.forEach(((Consumer)String::toUpperCase)。然后(System.out::println))我的机器上的打字检查o,有什么建议如何解决它并使它工作吗?我回答的是如何链接,而不是如何解决给定的精确示例。查看
函数
界面了解其他链接方法。