当前位置: 首页 > 知识库问答 >
问题:

Java 8方法引用到lambda[复制]

籍兴文
2023-03-14

我有一段代码,试图将方法引用(“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)

共有3个答案

严欣怡
2023-03-14

字符串::长度的完整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())

它返回一个比较器

宰父深
2023-03-14

编辑为什么不推断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());

做你可能想要的。

邵璞
2023-03-14

与其使用匿名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还向我提供了错误