【问题标题】:Method references to multidimensional arrays in Java 8Java 8 中对多维数组的方法引用
【发布时间】:2017-03-26 12:03:27
【问题描述】:

在 Java 中,我们可以从一维数组构造函数引用创建 IntFunction<String[]>

    // both do the same thing
    IntFunction<String[]> createArrayL = size -> new String[size];
    IntFunction<String[]> createArrayMR = String[]::new;

现在我想知道为什么我们不能用二维数组来做到这一点:

    BiFunction<Integer, Integer, String[][]> createArray2DL = 
            (rows, cols) -> new String[rows][cols];

    // error:
    BiFunction<Integer, Integer, String[][]> createArray2DMR =
            String[][]::new;

当然我们可以写:

    IntFunction<String[][]> createArray2DInvalidL = String[][]::new;
    System.out.println(createArray2DInvalidL.apply(3)[0]); // prints null

但这将与以下行为不同:

    new String[3][3]

因为行数组不会被初始化。

所以我的问题是:为什么 String[][]::new 不适用于 2D 数组(对我来说,这看起来像是语言设计的不一致)?

【问题讨论】:

    标签: java lambda java-8 language-lawyer method-reference


    【解决方案1】:

    确实是一个很有趣的案例。

    问题在于String[][]::new 是一个元数为 1 的函数(它是数组数组的构造函数),不能被视为 BiFunction(元数 2),而您的示例 new String[3][3] 有两个参数而不是一个。

    在这种情况下, createArray2DInvalidL.apply(3) 等于调用new String[3][];

    您可能正在寻找的是:

    IntFunction&lt;String[][]&gt; createArray2D = n -&gt; new String[n][n];

    维度不需要具有相等的长度,这听起来是一个非常合理的假设。

    http://4comprehension.com/multidimensional-arrays-vs-method-references/

    【讨论】:

    • 以及为什么BiFunction&lt;Integer, Integer, String[][]&gt; createArray2DL = (a,b) -&gt; String[][]::new; 会产生错误??
    • @user43968 因为在您的 lambda 表达式中,您正在返回另一个函数 BiFunction&lt;Integer, Integer, IntFunction&lt;String[][]&gt;&gt; createArray2DL = (a, b) -&gt; String[][]::new;
    【解决方案2】:

    这里没有矛盾。如果你写一个像

    这样的语句
    IntFunction<ElementType[]> f = ElementType[]::new;
    

    您创建一个函数,其评估将返回一个新数组,其中每个条目都能够保存ElementType 的引用,初始化为null。当您将String[] 用于ElementType 时,这不会改变。

    但它也已在The Java Language Specification, §15.13.3. Run-Time Evaluation of Method References 中明确解决:

    如果形式是Type[]k :: new (k ≥ 1),那么调用方法的主体有与 new Type [ size ] []k-1 形式的数组创建表达式的效果相同,其中 size 是调用方法的单个参数. (符号 []k 表示一系列 k 括号对。)

    不支持矩形多维数组创建方法参考,很可能是因为没有作为驱动力的实际用例。一维数组创建表达式可以与Stream.toArray(…)一起使用,允许比等效的lambda表达式更简洁的语法,尽管底层架构没有特殊支持,即int[]::new产生与@完全相同的编译代码987654329@。没有类似的用于创建二维(甚至更多)维数组的用例,因此对于使用两个或更多 int 值并产生引用类型结果的函数,甚至没有类似的函数接口。

    【讨论】:

    • 我的意思是,因为在 Java 中,您可以通过 new Element[5][6]new Element[5][] 创建二维数组(当然在第一种情况下编译器也会为我分配行)那么 Java 应该允许相同带有构造函数参考。我很困惑,因为如果编译器可以在 new X[a][b] 表达式中分配行,那么为什么不能在 X[][]::new 中分配行 - 如果这意味着生成合成 lambda 表达式。
    • 没有人说不可能编写出能够生成此类代码的编译器。但是语言设计者并没有为它添加语法。一维数组创建方法引用的语法表现一致,即使元素类型是数组本身。假设的矩形多维数组创建方法参考语法必须与此不同,因为如果 X[][]::new 有时创建子数组而有时不创建子数组,这是不可接受的。与等效的 lambda 表达式相比,附加语法不会有太大优势。
    猜你喜欢
    • 1970-01-01
    • 2019-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    • 2014-01-13
    相关资源
    最近更新 更多