使用方法引用替换链式方法调用

时间:2014-04-18 14:48:08

标签: java lambda java-8

" Java 8 Lambdas:实用的功能编程"有一个在peek API中使用Stream方法的示例。这段代码打印的艺术家国籍名称以"":

开头
Set<Nationality> nationalities = album.getMusician()
                                 .filter(artist -> artist.getName().startsWith("The"))
                                 .map(artist -> artist.getNationality())
                                 .peek(nation -> System.out.println(nation))
                                 .collect(Collectors.toList());

我想用方法引用重写此代码:

Set<Nationality> nationalities = album.getMusician()
                                 .filter(artist -> artist.getName().startsWith("The"))
                                 .map(Artist::getNationality)
                                 .peek(System.out::println)
                                 .collect(Collectors.toList());

是否有任何重写filter(artist -> artist.getName().startsWith("The"))的解决方案?

3 个答案:

答案 0 :(得分:6)

您需要创建一个单独的方法,该方法接受一个Artist并返回一个布尔值:

private boolean nameStartsWithThe(Artist a) {
    return a.getName().startsWith("The");
}

Set<Nationality> nationalities = album.getMusician()
                                 .filter(this::nameStartsWithThe)

或使用静态方法:

private static boolean nameStartsWithThe(Artist a) {
    return a.getName().startsWith("The");
}

Set<Nationality> nationalities = album.getMusician()
                                 .filter(MyClass::nameStartsWithThe)

答案 1 :(得分:2)

您需要构成这两种方法的东西。有一些组合方法的方法(IntUnaryOperatorcomposeandThen方法,可以将两个IntUnaryOperator组成一个新的IntUnaryOperator)。但我发现的那些似乎都专门用于某些类型的功能接口;为每一对可能的功能接口类型定义compose方法会过于笨拙。

我确实得到了一些可以构成FunctionPredicate以获得新Predicate的内容:

static <T,U> Predicate<T> functionPredicate(Function<T,U> func, Predicate<U> pred) {
    return obj -> pred.test(func.apply(obj));
}

也就是说,它可以构成一个谓词,该谓词对T的函数进行操作,该函数使用T并返回U,以及对U进行操作的谓词。除了startsWith需要另一个参数之外,这将几乎对您的示例起作用。但这确实有效:

static boolean startsWithThe(String s) {
    return s.startsWith("The");
}

Predicate<Artist> pred = functionPredicate(Artist::getName, ThisClass::startsWithThe);

其中ThisClass是包含startsWithThe的任何类。这有效。如果你想避免编写一个新方法(比如startsWithThe),你可能会写一个参数化的谓词&#34;通用方法,以便您编写类似

的内容
Predicate<Artist> pred = functionPredicate(Artist::getName, parameterizedPredicate(String::startsWith, "The"));

但我还没试过。

因此,似乎可以提出某些,它可以让你使用方法引用而不是lambdas。我怀疑它是否值得。对我来说,方法参考只是某些种类的lambda的简写;除非你能用一个简单的方法参考做你想做的事情,我认为使用lambda足够简洁明了,而且你不需要添加像我functionPredicate这样的额外装备。方法。我已经看到了几个问题,例如&#34;我如何使用方法参考而不是lambda?&#34;,老实说,我不明白为什么。

答案 2 :(得分:0)

无法用方法参考替换该行。


方法引用的工作原理是整个lambda表达式中只使用了一个对象,编译器可以使用目标类型推断它(引用无关紧要,类型可以推断)。

所以,

artist -> artist.getNationality()

替换为

Artist::getNationality

此处Artist::getNationality方法与目标类型匹配,无需任何进一步的信息。


artist -> artist.getName().startsWith("The")的情况下,lambda表达式中有两个方法调用。订单,参数很重要,必须指定。

看起来好像应该推断artist引用,但是编译器不知道应该调用startsWith("The")方法的对象。

希望这有帮助。