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

Java 使用方法引用替换链式方法调用,java,lambda,java-8,Java,Lambda,Java 8,“Java8Lambdas:Practical Functional Programming”有一个例子,说明如何在StreamAPI中使用peek方法。这段代码打印出名称以“The”开头的艺术家国籍: Set nations=album.getMusiner() .filter(artist->artist.getName().startsWith(“The”)) .map(艺术家->艺术家.getNational()) .peek(国家->系统输出.println(国家)) .collect

“Java8Lambdas:Practical Functional Programming”有一个例子,说明如何在
Stream
API中使用
peek
方法。这段代码打印出名称以“The”开头的艺术家国籍:

Set nations=album.getMusiner()
.filter(artist->artist.getName().startsWith(“The”))
.map(艺术家->艺术家.getNational())
.peek(国家->系统输出.println(国家))
.collect(Collectors.toList());
我想用方法引用重写此代码:

Set<Nationality> nationalities = album.getMusician()
                                 .filter(artist -> artist.getName().startsWith("The"))
                                 .map(Artist::getNationality)
                                 .peek(System.out::println)
                                 .collect(Collectors.toList());
Set nations=album.getMusiner()
.filter(artist->artist.getName().startsWith(“The”))
.map(艺术家::GetNational)
.peek(System.out::println)
.collect(Collectors.toList());

是否有任何重写
过滤器(artist->artist.getName().startsWith(“The”))
的解决方案?

无法用方法引用替换该行


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

所以

被替换为

Artist::getNationality
这里的
Artist::getNational
方法与目标类型匹配,而不需要任何进一步的信息


对于
artist->artist.getName().startsWith(“The”)
,lambda表达式中有两个方法调用。顺序、参数很重要,必须指定

看起来好像应该推断
artist
引用,但是编译器不知道应该调用
startsWith(“the”)
方法的哪个对象


希望这有帮助。

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

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

Set<Nationality> nationalities = album.getMusician()
                                 .filter(this::nameStartsWithThe)
private boolean nameStartsWithThe(艺术家a){
返回a.getName().startsWith(“The”);
}
Set nations=album.getMusiner()
.filter(this::nameStartsWithThe)
或使用静态方法:

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

Set<Nationality> nationalities = album.getMusician()
                                 .filter(MyClass::nameStartsWithThe)
私有静态布尔名称开始(艺术家a){
返回a.getName().startsWith(“The”);
}
Set nations=album.getMusiner()
.filter(MyClass::nameStartsWithThe)

您需要一些东西来组合这两种方法。有一些方法可用于组合方法(
IntUnaryOperator
具有
compose
,然后
方法可将两个
IntUnaryOperator
组合成一个新的
IntUnaryOperator
)。但我发现的那些似乎都专门用于某些类型的功能接口;为每一对可能的函数接口类型定义
compose
方法太难了

我确实做了一些工作,将组成一个
函数
和一个
谓词
,以获得一个新的
谓词

static <T,U> Predicate<T> functionPredicate(Function<T,U> func, Predicate<U> pred) {
    return obj -> pred.test(func.apply(obj));
}
其中,
this类
是包含
的任何类,从
开始。这很有效。如果您想避免编写新方法(如
startsWithThe
),您可能可以编写一个“参数化谓词”泛型方法,这样您就可以编写

Predicate<Artist> pred = functionPredicate(Artist::getName, parameterizedPredicate(String::startsWith, "The"));
Predicate pred=functionPredicate(Artist::getName,parameteredPredicate(String::startsWith,“The”);
但我还没试过

因此,似乎有可能想出一些方法,让您使用方法引用而不是lambda。我怀疑这是否值得。对我来说,方法引用只是某些lambda的简写;除非你能用一个简单的方法引用做你想做的事情,否则我认为使用lambda足够简洁明了,你不需要像我的
functionPredicate
方法那样添加所有额外的繁琐。我看到过一些问题,比如“我如何使用方法引用来代替lambda?”,我真的不明白为什么

static <T,U> Predicate<T> functionPredicate(Function<T,U> func, Predicate<U> pred) {
    return obj -> pred.test(func.apply(obj));
}
static boolean startsWithThe(String s) {
    return s.startsWith("The");
}

Predicate<Artist> pred = functionPredicate(Artist::getName, ThisClass::startsWithThe);
Predicate<Artist> pred = functionPredicate(Artist::getName, parameterizedPredicate(String::startsWith, "The"));