Array Constructor References – Functional-Style Programming
Array Constructor References
Array constructor reference is specialization of the constructor reference for creating arrays. We can convert between an array constructor reference and a lambda expression using the following rule:
A lambda expression of the form
arg -> new ElementType[arg][]…[]
is semantically equivalent to the array constructor reference:
ElementType[][]…[]::new
The array type and the keyword new are separated by the double-colon (::) delimiter. The ElementType is designated with the necessary pairs of square brackets ([]) to indicate that it is an array type of a specific number of dimensions. Only the length of the first dimension of the array can be created using an array constructor reference. As one would expect, the elements are initialized to the default value for the element type.
The array constructor reference at (1) will create a simple array of element type int. The target type IntFunction<int[]> is compatible with the type of the array constructor reference (int -> int[]). The array of int created at (2) has length 4, where each element has the default value 0.
// int -> int[]
IntFunction<int[]> intArrConsLE = n -> new int[n];
IntFunction<int[]> intArrConsCR = int[]::new; // (1)
int[] intArr = intArrConsCR.apply(4); // (2)
// Creates an int array of length 4.
In the code below, we can define a lambda expression to create a two-dimensional array that takes two arguments. However, this is not possible using an array constructor reference, as only the length of the first dimension can be passed to an array constructor reference. The line at (3) will not compile, since the target type ((Integer, Integer) -> int[][]) is not compatible with the type of the array constructor reference (int -> int[][]).
// (int, int) -> int[][]
BiFunction<Integer, Integer, int[][]> twoDimArrConsLE1 = (n, m) -> new int[n][m];
// BiFunction<Integer, Integer, int[][]> twoDimArrConsCR1
// = int[][]:: new; // (3) Compile-time error!
It is only possible to define an array constructor reference to create the length of the first dimension of an array, regardless of how many dimensions it has. This is illustrated by the array constructor reference at (4), which creates a two-dimensional array where only the first dimension is constructed—keeping in mind that in Java, multidimensional arrays are implemented as arrays of arrays. The code at (5) returns an array with three rows, where each row is initialized to the null value. Individual arrays can be constructed and stored in the two-dimensional array, as shown at (6).
// int -> int[][]
IntFunction<int[][]> twoDimArrConsLE = n -> new int[n][];
IntFunction<int[][]> twoDimArrConsCR = int[][]::new; // (4)
int[][] twoDimIntArr1 = twoDimArrConsCR.apply(3); // (5)
// [null, null, null]
for (int i = 0; i < twoDimIntArr1.length; ++i)
twoDimIntArr1[i] = intArrConsCR.apply(i+1); // (6) Calls (1).
// [[0], [0, 0], [0, 0, 0]]
The example below illustrates constructing an array of objects. The procedure is no different from constructing arrays of primitive values, as explained above. The array returned by the code at (7) has five elements, where each element is initialized to the null value.
// int -> StringBuilder[]
IntFunction<StringBuilder[]> sbaConsLE = n -> new StringBuilder[n];
IntFunction<StringBuilder[]> sbaConsCR = StringBuilder[]::new;
StringBuilder[] sbArr2 = sbaConsCR.apply(5); // (7)
// [null, null, null, null, null]
Java does not allow creation of generic arrays, as demonstrated by the declaration statement at (8), where an attempt is made to construct an array of formal parameter type A (§11.13, p. 627). This can be overcome by using either a lambda expression or an array constructor reference whose target type is a parameterization of IntFunction<A[]>, and which is passed to the generic method createArray() below, together with the required array length, to create an array of a specific type.
public static <A> A[] createArray(int length, IntFunction<A[]> creator) {
//A[] arr = new A[length]; // (8) Cannot create generic array!
return creator.apply(length); // Lambda expression or
// array constructor reference executed.
}
The code below calls the generic method createArray() with a lambda expression and an array constructor reference at (9) and (10), respectively, to create a String array of length 5. The target type in both cases is parameterized functional interface IntFunction<String[]>.
// n -> String[]
String[] strArrLE = createArray(5, n -> new String[n]); // (9)
String[] strArrACE = createArray(5, String[]::new); // (10)