我已经升级了Eclipse Photon 4.8(http://download.eclipse.org/eclipse/downloads/drops4/S-4.9M2-201808012000/)以支持JDK 11(https://marketplace.eclipse.org/content/java-11-support-eclipse-photon-49)。似乎工作正常(版本:4.9 内部版本号:I20180801-2000)。
在JDK 11中,Java.util.Collection中有一个方法toArray()
的新覆盖:
default <T> T[] toArray(IntFunction<T[]> generator) {
return toArray(generator.apply(0));
}
这是默认方法,但不会被覆盖。它所做的只是将提供的生成器函数返回的值(使用硬编码参数0)传递到toArray()
的另一个替代项,该替代项随后将Collection的内容作为数组返回。
如该方法的Javadoc中所述,可以这样调用:
String[] y = x.toArray(String[]::new);
这很好,然后返回一个与Collection<String>
相对应的适当长度的String数组。
Javadoc还声明“ 默认实现以零调用生成器函数,然后将结果数组传递给toArray(T [])”。
如果我提供了自己的生成器函数,则确实会调用它(如println()
控制台输出所示),但是其apply()
方法的返回值似乎被忽略了。就像我调用toArray(String[]::new)
一样,无论生成器函数返回的数组内容如何。
这是MCVE:
package pkg;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.function.IntFunction;
public class App {
public static void main(String[] args) {
IntFunction<String[]> intFunc = (int sz) -> {
System.out.println("intFunc: sz: " + sz);
if (sz == 0) {
sz = 3;
}
String[] array = new String[sz];
for (int i = 0; i < sz; i++) {
array[i] = Character.toString('A' + i);
}
System.out.println("intFunc: array to be returned: " + Arrays.toString(array));
return array;
};
Collection<String> coll = List.of("This", "is", "a", "list", "of", "strings");
// Correctly returns the collection as an array, as described in JDK11 Javadoc.
String[] array1 = coll.toArray(String[]::new);
System.out.println("array1: " + Arrays.toString(array1) + '\n');
// Use generator function to return a different collection as an array - doesn't work.
String[] array2 = coll.toArray(intFunc);
System.out.println("array2: " + Arrays.toString(array2) + '\n');
// Use generator function to return a different collection as an array - doesn't work.
String[] array3 = coll.toArray(intFunc.apply(coll.size()-2));
System.out.println("array3: " + Arrays.toString(array3));
}
}
这是通过运行MCVE产生的控制台输出:
array1:[这是一个字符串列表]
intFunc:sz:0
intFunc:要返回的数组:[A,B,C]
array2:[这是一个字符串列表]
intFunc:sz:4
intFunc:要返回的数组:[A,B,C,D]
array3:[这是一个字符串列表]
输出显示我的生成器函数做什么无关紧要-不使用它返回的数组。
我的问题是我该如何使用toArray()
的新实现来使用生成器函数返回的数组,或者我正在尝试某些不可能的事情?
根据评论和Nicolai的回答进行更新:
我的示例代码的问题不在于生成器,而在于我的测试用例。它们碰巧使生成器返回的元素数组少于集合的数组,因此分配了一个新数组,以精确存储集合中元素的数量。
一个返回比集合大的数组的测试用例可以正常工作。例如此代码:
String[] array4 = coll.toArray(intFunc.apply(coll.size() + 3));
System.out.println("array4: " + Arrays.toString(array4));
提供以下控制台输出:
intFunc:sz:9
intFunc:要返回的数组:[A,B,C,D,E,F,G,H,I]
array4:[这是一个字符串列表,为null,H,I]
SO问题Collections emptyList/singleton/singletonList/List/Set toArray解释了为什么返回的数组中存在空值。
答案 0 :(得分:3)
正如您所指出的,toArray(IntFunction<T[]>)
是a default method,它只是转发到toArray(T[])
(在使用给定函数创建数组之后)。如果您仔细研究一下该方法,就会发现问题的答案-从the JDK 10 Javadoc(重点是我的):
返回包含此集合中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。 如果集合适合指定的数组,则将其返回。否则,将使用指定数组的运行时类型和该集合的大小分配新的数组。
要使用要创建的数组,该数组必须足够长以容纳集合的元素,例如:
public static void main(String[] args) {
var createdArray = new AtomicReference<String[]>();
var usedArray = List.of("A", "B", "C").toArray(__ -> {
createdArray.set(new String[5]);
return createdArray.get();
});
var message = String.format(
"%s (length: %d; identical with created array: %s)",
Arrays.toString(usedArray), usedArray.length, usedArray == createdArray.get());
System.out.println(message);
}
答案 1 :(得分:2)
生成器函数返回的数组不会被忽略。使用返回数组的组件类型。假设您有一个字符串集合,例如您的示例:
jshell> Collection<String> coll = List.of("This", "is", "a", "list", "of", "strings")
coll ==> [This, is, a, list, of, strings]
您的生成器函数是这样的:
jshell> IntFunction<CharSequence[]> g = x -> {
...> var a = new CharSequence[x];
...> System.out.println(a);
...> return a;
...> }
g ==> $Lambda$28/0x00000008000d8040@17d677df
(请注意,这会打印出数组的默认表示形式,其中包括其标识哈希码,而不是数组的内容。数组的内容符合预期。)
然后,您可以将集合中的字符串复制到CharSequence数组中:
jshell> System.out.println(coll.toArray(g))
[Ljava.lang.CharSequence;@7d70d1b1
[Ljava.lang.CharSequence;@2a742aa2
现在假设源是一个空集合:
jshell> System.out.println(List.of().toArray(g))
[Ljava.lang.CharSequence;@3dfc5fb8
[Ljava.lang.CharSequence;@3dfc5fb8
您可以看到生成器返回的零大小数组具有足以包含零个元素的大小,因此只需返回即可。