我有一段代码,试图将方法引用(“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> Comparator<Object> java.util.Comparator.comparingInt(ToIntFunction<? super Object> keyExtractor)
当我使用String::长度方法引用时,那么在编译时,隐式参数被正确理解为String实例。在这种情况下有什么特别的?见下文。
<String> Comparator<String> java.util.Comparator.comparingInt(ToIntFunction<? super String> keyExtractor)
字符串::长度的完整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.comparingInt(p -> ((String) p).length())
它返回一个比较器
编辑为什么不推断p的类型。
p
的类型不会自动推断为String
,原因与以下示例中未推断的原因非常相同:
String a = "a";
String b = "b";
Comparator.comparingInt(p -> p.length).compare(a, b);
在这里,它失败了,因为Object
没有方法长度
。要了解原因,请考虑此表达式的抽象语法树(非常粗略的近似):
Apply
/ \
/ \
/ \
/ \
_______________ / \__
/ \
/ \
/ \
MemberSelection ArgumentList(2)
/ \______ / \
/ \ / \
Apply compare a: String b: String
_____/ \______
/ \
/ \
MemberSelection Lambda
/ | | \
/ | | \
Comparator comparingInt Variable MemberSelection
| / \
p p length
如您所见,有关字符串的类型信息完全位于AST的右侧,而变量binder和整个闭包位于AST的左侧分支上。
碰巧的是,类型推理算法总是以自顶向下的方式在本地工作。一旦它下降到左子树中并且无法推断p的类型,它将不会返回树并在右子树中搜索其他提示。这太复杂了,无法实现,类型检查器越是远离有问题的活页夹,关于失败类型推断的错误消息就越不清楚。类型推断算法不会对整个程序进行全局类型检查。
您不需要代码(a、b)-
List<String> list = s.
sorted(Comparator.comparingInt(String::length)).
collect(toList());
做你可能想要的。
与其使用匿名lambda来实现功能性比较器接口,不如使用一个直接的比较器:
List<String> list =
s.sorted(Comparator.comparingInt(String::length)).collect(toList());
主要内容:1 Java8 方法引用的介绍,2 Java8 方法引用的分类,3 Java8 方法引用:引用静态方法,4 Java8 方法引用:引用实例方法,5 Java8 方法引用:引用构造方法1 Java8 方法引用的介绍 Java提供了一个新功能,称为Java 8中的方法引用。方法引用用于引用功能接口的方法。它是lambda表达式的紧凑和简单形式。每次使用lambda表达式仅引用方法时,都可以将lambda表达式替换为方法引用。在本教程中,我们将详细解释方法参考概念。 2 Java8 方法引用
我正在通过一个例子,它从与方法引用相关的当前目录中提取一个隐藏文件数组,如下所述 使用匿名内部类实现 使用方法参考实现 我的问题是接口只有一个抽象方法(),而实现accept-method-using-method-reference在类中使用的有效性如何。我了解到,只有当参数与抽象方法匹配时,我们才能应用方法引用,但是这里method有一个类型的参数,但是没有参数。你能解释一下它的有效性吗。
本文向大家介绍使用Java8中的方法引用来引用实例方法,包括了使用Java8中的方法引用来引用实例方法的使用技巧和注意事项,需要的朋友参考一下 Java中的Lambda表达式使您可以将功能作为参数传递给方法。您也可以使用lambda表达式调用现有方法。 方法引用是简单,易于阅读的lambda表达式,可通过lambda表达式中的名称来调用/引用和现有方法。 语法 以下是在Java中引用实例方法的语法
本文向大家介绍Java8使用lambda表达式调用静态方法,包括了Java8使用lambda表达式调用静态方法的使用技巧和注意事项,需要的朋友参考一下 Java中的Lambda表达式允许您将功能作为参数传递给方法。您还可以使用lambda表达式调用现有的方法。 方法引用是简单的、易于阅读的lambda表达式,可以通过lambda表达式中的名称调用/引用现有的方法。可以使用方法引用引用类中定义的静态
IntelliJ一直建议我用方法引用替换我的lambda表达式。 两者之间有什么客观差异吗?
我正在和Java8一起做项目,发现了一个我无法理解的情况。 我有这样的代码: 这段代码运行良好,但我可以使用方法引用重写它: 而这段代码没有编译,在方法引用中给出了不兼容的抛出类型*SomeException*。 IDEA还向我提供了错误