【问题标题】:Using method reference instead of multi argument lambda使用方法引用而不是多参数 lambda
【发布时间】:2019-02-22 09:38:46
【问题描述】:

我对“引用特定类型的任意对象的实例方法”背后的概念感到困惑。 Oracle documentation 有一个例子:

String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

我看到的这种方法参考的大多数例子都是这样的:如果 lambda 是这样的:x -> x.func(),那么你可以写成ClassOfX::func。文档中的示例说:

方法引用的等效 lambda 表达式 String::compareToIgnoreCase 将具有形式参数列表 (String a, String b),其中 a 和 b 是用于更好的任意名称 描述这个例子。方法引用将调用该方法 a.compareToIgnoreCase(b)。

问题是:对于任何两个参数 lambda,如 (a, b) -> a.func(b)func 方法必须是第一个参数的实例方法,而 lambda 的第二个参数将作为参数传递给该方法?如果我们有多个参数 lambda,那么 func 方法必须是 lambda 的第一个参数的实例方法,而 lambda 的其他参数将按照出现在 lambda 中的顺序传递给 func?我的意思是我们可以写ClassOfA::func而不是(a, b, c) -> a.func(b, c)

对不起我的英语。我希望我把问题说清楚了。

【问题讨论】:

    标签: java lambda java-8


    【解决方案1】:

    SomeClass::func 有两种含义,具体取决于func 是静态方法还是实例方法。

    (1) 如果func 是一个静态方法,那么SomeClass::func 是一个lambda,它只是将所有参数传递给该方法:

    (a, b, c) -> SomeClass.func(a, b, c);
    

    (2) 如果func是一个实例方法,那么SomeClass::func是一个使用第一个参数作为实例的lambda,正如你所想的那样:

    (a, b, c) -> a.func(b, c);
    

    a 的类型为 SomeClass

    编辑: Sotirios 的回答展示了另一种方法引用:example::method 其中example 是引用变量(而不是类名)。这意味着和

    (a, b) -> example.method(a, b);
    

    或许更准确

    (a, b) -> __someFinalTemporary.method(a, b);
    

    其中__someFinalTemporary 在评估方法引用时被分配给example,因此如果example 稍后更改,仍会使用example 的早期值调用该方法。

    [第四种是SomeClass::new,它将参数传递给构造函数。我想这就是全部。]

    【讨论】:

      【解决方案2】:

      这是一个演示实例方法引用行为的小示例。

      public class Example {  
          public static void main(String[] args) throws Exception {
              List<String> strings = new ArrayList<String>();
              Example example = new Example();
              Functional methodRef = example::method;
              methodRef.funct("a string", strings);
              System.out.println("List now contains: " + strings);
      
              Functional lambda = (String s, List<String> l) -> {
                  example.method(s, l);
              };
              lambda.funct("another string", strings);
              System.out.println("List now contains: " + strings);
          }
      
          interface Functional {
              void funct(String value, List<String> list);
          }
      
          void method(String value, List<String> toAddTo) {
              System.out.println("adding");
              toAddTo.add(value);
          }
      }
      

      打印出来

      adding
      List now contains: [a string]
      adding
      List now contains: [a string, another string]
      

      两者或多或少是等价的。在 lambda 的情况下,调用该方法的变量需要有效地为 final

      【讨论】:

      • 它看起来有点像魔术。如果示例没有实现功能,为什么Functional methodRef = example::method; 工作?它确实有效,我只是不太明白如何。
      • @PauloGuedes 它的方法引用被转换为实现Functional 的东西。在这种情况下,func 的两个参数将传播到 method,在示例中调用。
      【解决方案3】:

      我的意思是代替 (a, b, c) -> a.func(b, c) 我们可以写 ClassOfA::func

      是的,没错。

      【讨论】:

        【解决方案4】:

        根据 Joshua Bloch 在他的“Effective Java”(第 3 版)中的说法,方法参考有 5 种类型的用例。

        【讨论】:

          猜你喜欢
          • 2016-09-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-26
          • 1970-01-01
          • 2019-11-05
          • 1970-01-01
          • 2013-06-21
          相关资源
          最近更新 更多