我有一个文件流,我想根据文件名的结尾进行过滤:
public Stream<File> getFiles(String ending) throws IOException {
return Files.walk(this.path)
.filter(Files::isRegularFile)
.map(Path::toFile)
.filter(file -> file.getName().endsWith(ending));
}
虽然最后一行中的lambda也不错,但我认为我也可以在那里使用方法引用,如下所示:
.filter(File::getName.endsWith(ending));
或者用括号括起来。但是,这会因The target type of this expression must be a functional interface
你能解释为什么这不起作用吗?
答案 0 :(得分:7)
你能解释为什么这不起作用吗?
方法引用是lambda表达式的语法糖。例如,方法参考File::getName
与(File f) -> f.getName()
相同。
Lambda表达式是用于定义功能接口实现的“方法文字”,例如Function
,Predicate
,Supplier
等。
为使编译器知道您正在实现的接口,lambda或方法引用必须具有目标类型:
// either assigned to a variable with =
Function<File, String> f = File::getName;
// or assigned to a method parameter by passing as an argument
// (the parameter to 'map' is a Function)
...stream().map(File::getName)...
或(异常)投射到某物:
((Function<File, String>) File::getName)
赋值上下文,方法调用上下文和强制转换上下文都可以为lambda或方法引用提供目标类型。 (在上述所有3种情况中,目标类型为Function<File, String>
。)
编译器告诉你的是你的方法引用没有目标类型,所以它不知道如何处理它。
答案 1 :(得分:3)
File::getName
是方法参考,String::endsWith
也是。然而,它们不能被链接在一起。您可以创建另一种方法来执行此操作
public static Predicate<File> fileEndsWith(final String ending) {
return file -> file.getName().endsWith(ending);
}
然后使用它
.filter(MyClass.fileEndsWith(ending))
如果你不重复使用它,这并不会给你带来太大的收益。
答案 2 :(得分:2)
一些帮助者可能会帮助提供一些你想要的外表。使用下面的帮助程序,您可以将lambda替换为包含方法引用的表达式,如下所示:
// since your predicate is on the result of a function call, use this to create a predicate on the result of a function
public static <A,B> Predicate<A> onResult(Function<A,B> extractor, Predicate<B> predicate){
return a -> predicate.test(extractor.apply(a));
}
// since your predicate involves an added parameter, use this to reduce the BiPredicate to a Predicate with one less parameter
public static <T,U> Predicate<T> withParam(BiPredicate<T,U> pred, U param){
return t -> pred.test(t,param);
}
public Stream<File> getFiles(String ending) throws IOException {
return Files.walk(Paths.get("."))
.filter(Files::isRegularFile)
.map(Path::toFile)
.filter(onResult(File::getName, withParam(String::endsWith, ending)));
}