当前位置: 代码迷 >> java >> 多个lambda方法引用
  详细解决方案

多个lambda方法引用

热度:26   发布时间:2023-07-16 17:34:07.0

可以链接/连接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;
});

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

要提供该信息,您必须转换声明:

  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
}

不,你不能像你建议的那样使用方法引用。 方法引用实际上只是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.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);
  相关解决方案