Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method references to multidimensional arrays in Java 8

In Java we may create IntFunction<String[]> from 1D array constructor reference:

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

Now I wonder why we cannot do this with a 2D array:

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

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

Of course we may write:

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

but this will behave differently than:

    new String[3][3]

because row arrays will not be initialized.

So my question is: why String[][]::new doesn't work for 2D arrays (for me it looks like an inconsistency in language design)?

like image 534
csharpfolk Avatar asked Nov 12 '16 10:11

csharpfolk


2 Answers

Quite an interesting case indeed.

The problem is that String[][]::new is a function with an arity of 1(it's a constructor of an array of arrays) and can't be treated as a BiFunction(arity of 2) and your example new String[3][3] has two parameters instead of one.

In this case, createArray2DInvalidL.apply(3) is equal to calling new String[3][];

What you might be looking for is:

IntFunction<String[][]> createArray2D = n -> new String[n][n];

Dimensions don't need to have equal lengths and it sounds like a pretty reasonable assumption.

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

like image 109
Grzegorz Piwowarek Avatar answered Nov 16 '22 00:11

Grzegorz Piwowarek


There is no inconsistency here. If you write a statement like

IntFunction<ElementType[]> f = ElementType[]::new;

you create a function whose evaluation will return a new array with each entry being capable of holding a reference of ElementType, initialized to null. This doesn’t change, when you use String[] for ElementType.

But it also has been addressed explicitly in The Java Language Specification, §15.13.3. Run-Time Evaluation of Method References:

If the form is Type[]k :: new (k ≥ 1), then the body of the invocation method has the same effect as an array creation expression of the form new Type [ size ] []k-1, where size is the invocation method’s single parameter. (The notation []k indicates a sequence of k bracket pairs.)

There is no support for a rectangular multi-dimensional array creation method reference, most likely, because there is no actual use case that acted as a driving force. The one-dimensional array creation expression can be used together with Stream.toArray(…), allowing a more concise syntax than the equivalent lambda expression, despite there is no special support in the underlying architecture, i.e. int[]::new produces exactly the same compiled code as intArg -> new int[intArg]. There is no similar use case for a two (or even more) dimensional array creation, so there isn’t even a similar functional interface for a function consuming two or more int value and producing a reference type result.

like image 37
Holger Avatar answered Nov 16 '22 00:11

Holger