gpt4 book ai didi

java - 根据 Collection.toArray(T[] array) 合约将 Java 流转换为数组

转载 作者:行者123 更新时间:2023-12-02 10:36:04 25 4
gpt4 key购买 nike

我知道Java Stream<>接口(interface)提供了多种将流转换为数组的方法。但是Collection.toArray(T[] array)方法有点不同。它有一些巧妙的(当时)要求,包括:

  • 如果你传递的数组足够大,则必须使用你传递的数组;否则必须创建一个新的。
  • 如果数组大于所需的大小,null必须添加在最后一个元素之后。

所以如果我的 Collection<T>实现从一些 Stream<FooBar> 检索其值(使用转换为 T 的转换器策略,如何从我的流转换为 Collection.toArray(T[] array) 所需的数组?

没有经过太多思考,我似乎必须这样做:

@Override
public <T> T[] toArray(T[] array) {
try (final Stream<FooBar> stream = getStream()) {
T[] result = stream.map(converter::toT).toArray(length ->
(T[])Array.newInstance(array.getClass(), length));
if(result.length <= array.length) {
System.arraycopy(result, 0, array, 0, result.length);
if(result.length < array.length) {
array[result.length] = null;
}
result = array;
}
}
return result;
}

但是有没有更简洁的方法来做到这一点?如果可能的话,有什么方法可以将流直接传输到给定的数组中吗? Stream<> 是否如此? API 已经提供了类似的功能:创建一个数组作为 Collection<>.toArray(T[] array) API 期望吗?

对可能重复的响应

我知道如何将流转换为数组。这个问题很具体:如何遵循Collection.toArray(T[] array)的合约。我不认为这是重复的,原因有两个:如果现有数组足够大,其他答案不会重复使用现有数组,并且它们不会用 null 标记元素。如果现有数组太大。

最佳答案

非常推荐阅读文章 Arrays of Wisdom of the Ancients .

简而言之,与直觉相反,将预先确定大小的数组传递给 Collections.toArray(T[])事实证明,该方法比传递零大小的数组效率低,后者仅用于确定结果类型,但让集合分配结果数组。

这就是 Java 11 推出新 default 的原因方法 <T> T[] toArray​(IntFunction<T[]> generator) 不使用该函数来分配集合大小的数组,而是分配一个零大小的数组以传递给 <T> T[] toArray​(T[] a) .

因此,值得重新考虑您是否真的想要为某个方法签订这样的契约(Contract),或者您真正想要优化哪些实际用例(因为您无法一次提供所有服务)。

例如考虑到传递零大小的数组是最有效的选择,您可以针对这种情况进行优化

@Override
public <T> T[] toArray(T[] array) {
T[] template = array.length == 0? array: Arrays.copyOf(array, 0);
try(Stream<FooBar> stream = getStream()) {
T[] result = stream.map(converter::toT)
.toArray(length -> Arrays.copyOf(template, length));
if(result.length > array.length) return result;
System.arraycopy(result, 0, array, 0, result.length);
if(result.length < array.length) array[result.length] = null;
return array;
}
}

请注意,当您必须实现该方法时,因为您正在实现 Collection ,JDK 中有很多有用的抽象基类,它们已经提供了实现。

当您没有实现集合时,您甚至可以使用这样的实现,例如

public <T> T[] toArray(T[] array) {
try(final Stream<FooBar> stream = getStream()) {
return new AbstractCollection<XYZ>() {
public Iterator<XYZ> iterator() {
return stream.map(converter::toT).iterator();
}
public int size() { return 0; } // don't know beforehand
}.toArray(array);
}
}

您必须替换XYZ返回类型为converter.toT(FooBar)方法。

这引出了一个更大的问题,如何 converter::toT应该转换为正确的类型,而实际上不知道什么 T是。

关于java - 根据 Collection.toArray(T[] array) 合约将 Java 流转换为数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53285724/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com