【问题标题】:Clarifying syntax on Lambda Expression阐明 Lambda 表达式的语法
【发布时间】:2021-07-09 18:15:23
【问题描述】:

我正在使用下面的代码按列对二维数组进行排序,它在第二个参数中采用 lambda 表达式。我不太明白 (a,b) 是如何定义的,以及 a[0] 和 b[0] 如何在比较器中工作。此代码排序正确,但我想了解语法。谢谢。

   Arrays.sort(myArray, (a, b) -> Integer.compare(a[0], b[0]))

【问题讨论】:

    标签: java sorting multidimensional-array lambda comparator


    【解决方案1】:

    Arrays.sort(T[] a, Comparator<? super T> c) 将Comparator<T> 作为第二个参数,它声明了方法int compare(T o1, T o2)。

    这意味着 lambda 表达式必须实现该方法,并且 myArray 是 Integer[][] 或 int[][],这意味着 T 是 Integer[] 或 int[],所以 a 和b 是 Integer[] 或 int[]。

    因此,该语句将按第一列对二维数组进行排序。

    【讨论】:

      【解决方案2】:

      按列排列的二维数组

      Java 没有二维数组。它有数组数组和一些语法糖,让您可以声明一个数组数组并立即通过创建新数组和填充槽来初始化外部数组。

      int[][] grid = new int[10][5];
      

      是语法糖:

      int[][] grid = new int[10][];
      for (int i = 0; i < 10; i++) grid[i] = new int[5];
      

      Arrays.sort(myArray, (a, b) -&gt; Integer.compare(a[0], b[0]))

      myArray 的类型是int[][]。换句话说,int[] 的数组。因此,要对此进行排序,您需要提供一个预言机:该预言机需要能够对以下问题给出一致的答案:“给定 2 个组件(在这种情况下,组件是 int[]),告诉我第一个组件是否对第二个“之后”或第二个“之前”进行排序,或平均排序。通过返回一个负数来表示第一个是“之前”,一个正数表示第一个是“之后”,以及 0 到表明它们在相同级别上是相等的或至少在排序上是相同的。

      通常,您可以通过创建 Comparator&lt;int[]&gt; 接口的实现、创建 this 的实例并传递它来做到这一点:

      class MySorter implements Comparator<int[]> {
          @Override public int compare(int[] a, int[] b) {
              return Integer.compare(a[0], b[0]);
          }
      }
      
      MySorter mySorter = new MySorter();
      Arrays.sort(myArray, mySorter);
      

      上面的代码运行良好——你可以编译并运行它。

      Lambdas 与上面发生的事情并没有太大的不同。在 Arrays 上只有一个相关的 sort 方法,它确实需要 2 个参数:T 的数组和可以比较 T 的 Comparator,T 是你喜欢的任何东西(这里,T 是int[])。那么为什么你可以在那里传递一个 lambda 呢?

      因为编译器是由外而内工作的。它最初只是看到:

      Arrays.sort(myArray, someLambdaExpressionIHaveNotLookedAtYet)
      

      并且会停在那里,并尝试找出预期的方法。它会发现只有一种方法“有效”:public static &lt;T&gt; sort (T[] array, Comparator&lt;T&gt; comparator)。

      只有这样 javac 才会继续:首先,它检查 Comparator 是否是所谓的“单一抽象方法”类型(SAM 类型):它是; Comparator 是一个只定义了一个方法的接口*,这意味着它是一个 SAM 类型,这意味着您可以快捷地创建一个 implements 这个接口的类,以及创建这个类的一个新实例。 -班轮。

      现在,因为 java 已经知道 lambda 应该代表什么(即,Comparator&lt;int[]&gt; 的实现,并且它知道您尝试实现的方法只有一种(即, public int compare(int[] a, int[] b)), java 已经知道变量类型。你实现的方法必须是int[] a, int[] b。

      这就是您不必指定它的原因。您可以只写(a, b) - java 为您填写int[]。你可以写出来:试一试,写Arrays.sort(myArray, (int[] a, int b[]) -&gt; Integer.compare(a[0], b[0]),你会发现它的工作方式完全一样。

      剩下的就很简单了:-&gt; 只是 lambda 语法,而且因为您不会在之后立即编写 {,所以 -> 后面的单个表达式只是作为返回值插入。

      因此,

      (a, b) -&gt; Integer.compare(a[0], b[0])

      100% 等同于:

      public class A implements B {
          public C {
              return D;
          }
      }
      A a = new A();
      

      地点:

      • A = 随机选择的不相关名称,
      • B = 预期的类型
      • C = B 中定义的一种方法的副本(如果没有一种方法,则不能使用此语法),
      • D = 你在 -> 之后写的任何内容。

      *) 已经在 java.lang.Object 中定义的方法不计算在内,具有默认 impl 的方法也不计算在内。

      【讨论】:

      • @user15358848 感谢您的提醒。我应该记住'语法完全不正确,因为原因',然后我不会再搞砸了:)
      猜你喜欢
      • 2011-07-12
      • 2010-12-05
      • 2021-03-07
      • 1970-01-01
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多