java 8方法引用到lambda [duplicate]
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java 8方法引用到lambda [duplicate]相关的知识,希望对你有一定的参考价值。
这个问题在这里已有答案:
我有这个代码,我尝试将方法引用(“String :: length”)转换为等效的lambda表达式。
Stream<String> s = Stream.of("hello", "your name", "welcome", "z");
List<String> list = s.sorted((a, b) -> Comparator.comparingInt(String::length).compare(a, b)).collect(toList());
// List<String> list = s.sorted((a, b) -> Comparator.comparingInt( p -> {return ((String)p).length();}).compare(a, b)).collect(toList());
它的唯一工作方式在注释行中列出。我需要抛出参数“p”。
似乎在编译时,如果我使用lambda表达式并且需要显式转换,它将参数“p”的类型指定为Object。见下文:
<Object> Comparator<Object> java.util.Comparator.comparingInt(ToIntFunction<? super Object> keyExtractor)
当我使用String :: length方法引用时,在编译时隐式参数被正确理解为String实例。在这种情况下有什么特别之处?见下文。
<String> Comparator<String> java.util.Comparator.comparingInt(ToIntFunction<? super String> keyExtractor)
String::length
的完整lambda是:
(String p) -> p.length()
它也可以使用块编写,但使用上面更简单的表达式更为常见:
(String p) -> { return p.length(); }
如果编译器可以推断出类型,您可以省略它:
p -> p.length()
但你正在使用这个:
Comparator.comparingInt(p -> p.length())
这是所有编译器在需要推断p
类型时所看到的。那么,什么是p
?编者说,不知道。所以你必须明确指定类型:
// Explicit type in parameter list
Comparator.comparingInt((String p) -> p.length())
// Explicit type on generic type parameter
Comparator.<String>comparingInt(p -> p.length())
// You can do both, but why would you?
Comparator.<String>comparingInt((String s) -> s.length())
// Explicit type of referenced method
Comparator.comparingInt(String::length)
请注意,没有任何代码使用强制转换。上面的内容都是类型安全的,与您使用强制转换编写的代码不同。不要使用演员!
上面的所有4个调用返回一个Comparator<String>
。该比较器可用于例如对List<String>
进行排序,但如果您尝试对任何其他类型的列表进行排序,则会出现编译错误。
当你像这样投射:
Comparator.comparingInt(p -> ((String) p).length())
它返回一个Comparator<Object>
,这意味着你可以在尝试对任何类型的列表进行排序时给出该比较器,例如:一个List<Integer>
。它将编译,但在运行时失败。使用强制转换使代码不是类型安全的。正如我所说,不要这样做。
而不是使用实现功能Comparator
接口的匿名lambda,只需使用一个直接的比较器:
List<String> list =
s.sorted(Comparator.comparingInt(String::length)).collect(toList());
编辑关于为什么不推断p
的类型。
p
的类型不会自动推断为String
,原因与以下示例中未推断出的原因非常相似:
String a = "a";
String b = "b";
Comparator.comparingInt(p -> p.length).compare(a, b);
在这里,它失败了Object
没有方法length
的消息。要了解原因,请考虑此表达式的抽象语法树(非常粗略近似):
Apply
/
/
/
/
_______________ / \__
/
/
/
MemberSelection ArgumentList(2)
/ \______ /
/ /
Apply compare a: String b: String
_____/ \______
/
/
MemberSelection Lambda
/ | |
/ | |
Comparator comparingInt Variable MemberSelection
| /
p p length
如您所见,有关String
的类型信息完全位于AST的右侧,而变量binder p
和整个闭包位于AST的左侧分支。
恰好是类型推断算法总是以自上而下的方式在本地工作。一旦它下降到左子树并且无法推断p
的类型,它将不会向上走回树并在右子树中搜索其他提示。这实现起来太复杂了,类型检查器越远离有问题的绑定器p
,关于失败类型推断的错误消息就越不清楚。类型推断算法不会尝试全局地检查整个程序。
你根本不需要(a, b) -> ...
部分,Comparator.compare(...)
已经产生了一个比较器:
List<String> list = s.
sorted(Comparator.comparingInt(String::length)).
collect(toList());
做你想要的。
以上是关于java 8方法引用到lambda [duplicate]的主要内容,如果未能解决你的问题,请参考以下文章
JAVA 8 方法引用 - Method References
Java 学习总结(188)—— Java 8 方法引用使用总结
Effective Java 第三版——43.方法引用优于lambda表达式