我已升级 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 构建 ID:I20180801-2000)。
在 JDK 11 中有一个新的方法覆盖 toArray()
在 Java.util.Collection 中:
default <T> T[] toArray(IntFunction<T[]> generator) {
return toArray(generator.apply(0));
}
这是默认方法,但未被覆盖。它所做的只是将提供的生成器函数返回的值(使用零的硬编码参数)传递给 toArray()
的另一个重写。然后将 Collection 的内容作为数组返回。
正如该方法的 Javadoc 中所述,它可以这样调用:
String[] y = x.toArray(String[]::new);
这很好,一个适当长度的字符串数组,对应于Collection<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: [This, is, a, list, of, strings]
intFunc: sz: 0
intFunc: array to be returned: [A, B, C]
array2: [This, is, a, list, of, strings]
intFunc: sz: 4
intFunc: array to be returned: [A, B, C, D]
array3: [This, is, a, list, of, strings]
输出显示我的生成器函数做什么并不重要——它返回的数组未被使用。
我的问题是如何获得 toArray()
的新实现使用我的生成器函数返回的数组,还是我在尝试一些不可能的事情?
根据评论和 Nicolai 的回答更新:
我的示例代码的问题不在于生成器,而在于我的测试用例。它们碰巧导致生成器返回一个元素少于集合的数组,因此分配了一个新数组,以准确保存集合中元素的数量。
返回大于集合的数组的测试用例按预期工作。例如这段代码:
String[] array4 = coll.toArray(intFunc.apply(coll.size() + 3));
System.out.println("array4: " + Arrays.toString(array4));
给出以下控制台输出:
intFunc: sz: 9
intFunc: array to be returned: [A, B, C, D, E, F, G, H, I]
array4: [This, is, a, list, of, strings, null, H, I]
SO 问题 Collections emptyList/singleton/singletonList/List/Set toArray解释了为什么返回的数组中有空值。
最佳答案
正如您所指出的,toArray(IntFunction<T[]>)
是a default method简单地转发到toArray(T[])
(在使用给定函数创建数组之后)。如果您仔细研究该方法,您会找到问题的答案 - 来自 the JDK 10 Javadoc (强调我的):
Returns an array containing all of the elements in this collection; the runtime type of the returned array is that of the specified array. If the collection fits in the specified array, it is returned therein. Otherwise, a new array is allocated with the runtime type of the specified array and the size of this collection.
要使用您创建的数组,它必须足够长以容纳集合的元素,例如:
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);
}
关于java - 如何使用 JDK 11 为 Collection.toArray() 提供生成器函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52051255/