Java 8中多维数组的方法引用

9
在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不能用于二维数组(对我来说,这看起来像是语言设计上的不一致)?

2个回答

9
相当有趣的案例。
问题在于String [] [] :: new是一个参数数量为1的函数(它是数组的构造函数) ,不能被视为一个双函数(参数数量为2),而你的示例new String [3] [3] 有两个参数,而不是一个。
在这种情况下,createArray2DInvalidL.apply(3)等同于调用new String [3] []; 你可能正在寻找的是: IntFunction<String [] []> createArray2D = n -> new String [n] [n]; 维度不需要具有相等的长度,这听起来是一个相当合理的假设。 http://4comprehension.com/multidimensional-arrays-vs-method-references/

2
为什么 BiFunction<Integer, Integer, String[][]> createArray2DL = (a,b) -> String[][]::new; 会产生错误? - user43968
@user43968,因为在你的lambda表达式中,你返回了另一个函数。 BiFunction<Integer, Integer, IntFunction<String[][]>> createArray2DL = (a, b) -> String[][]::new; - Grzegorz Piwowarek

1
这里并没有不一致之处。如果您编写像以下语句一样的声明:
IntFunction<ElementType[]> f = ElementType[]::new;

你需要创建一个函数,其评估将返回一个新的数组,每个条目都能够容纳一个对 ElementType 的引用,初始化为 null 。当你使用 String [] 作为 ElementType 时,这不会改变。
但它也已经在Java语言规范,§15.13.3方法引用的运行时评估中明确解决了:

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

没有支持创建矩形多维数组的方法引用,最可能是因为没有实际使用案例作为推动力。一维数组创建表达式可以与Stream.toArray(…)一起使用,使语法比等效的lambda表达式更加简洁,尽管在底层架构中没有特殊的支持,即int[]::new产生的编译代码与intArg -> new int[intArg]完全相同。对于二维(甚至更高维)数组的创建也没有类似的用例,因此甚至没有类似的函数接口来消耗两个或更多int值并生成引用类型结果。


我的观点是,由于在Java中您可以通过new Element [5] [6]new Element [5] []创建2d数组(当然,在第一种情况下,编译器也会为我分配行),因此Java应该允许使用构造函数引用。 我感到困惑,因为如果编译器可以在new X [a] [b]表达式中分配行,那么为什么不能在X [] [] :: new中分配行 - 即使这意味着生成合成lambda表达式。 - csharpfolk
没有人说不可能编写一个能够生成这种代码的编译器。但是语言设计者没有为此添加语法。一维数组创建方法引用的语法是一致的,即使元素类型本身是一个数组。假设存在一个矩形多维数组创建方法引用的语法,其语法必须与之不同,因为如果X [] [] :: new有时创建子数组,有时则不可接受。相比于等效的lambda表达式,附加语法的优势不大。 - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接