【问题标题】:Collection.toArray(IntFunction<T[]> generator) does not receive the collection sizeCollection.toArray(IntFunction<T[]> generator) 没有收到集合大小
【发布时间】:2021-01-04 17:40:00
【问题描述】:

为什么generateEmptyArrayBySize 方法接收0 作为输入,而不是3? 我期待收到列表大小。

public class CollectionToArrayTest {
    public static void main(String[] args) {
        var list = List.of(1, 2, 3);
        var array = list.toArray(CollectionToArrayTest::generateArrayBySize);
        out.println("array: " + Arrays.toString(array)); // array: [1, 2, 3]
    }

    private static Integer[] generateArrayBySize(int arraySize) {
        out.println("arraySize: " + arraySize); // arraySize: 0
        return new Integer[arraySize];
    }
}

【问题讨论】:

  • 只是为了指出使用 T[] 或 Supplier 作为参数的 toArray 方法的真正原因是因为在泛型类中我们无法创建泛型数组类型。 new T[]{} 无效。

标签: java lambda collections java-stream


【解决方案1】:

如果您查看Collection.toArray 方法的实现,您会看到:

return toArray(generator.apply(0));

另一方面,您拥有的IntFunction 的实现类似于:

new IntFunction<Integer[]>() {
    @Override
    public Integer[] apply(int arraySize) { // check the parameter here
        return generateArrayBySize(arraySize);
    }
}

因此传递给generateArrayBySize 的值与传递给IntFunctionapply 方法的值相同,即0。当然,将列表转换为数组的直接方法是:

var array = list.toArray(Integer[]::new);

【讨论】:

  • This Q&A 与 API 的构建方式具有一定的相关性。
  • 阅读文档:默认 T[] toArray​(IntFunction generator):默认实现以零调用生成器函数,然后将生成的数组传递给 toArray(T[ ]);然后 doc for T[] toArray​(T[] a): a - 这个集合的元素要存储到的数组,如果它足够大的话;否则,将为此目的分配相同运行时类型的新数组。在我看来,效率非常低,即使我们创建了一个花哨的 IntFunction 生成器,它也是没用的,我们将始终创建 2 个数组对象,其中第一个数组 '0' 为零是无用的
  • 有趣点:list.stream().toArray(EntityPermissionService::generateArrayBySize) 将正确的数组长度作为输入参数传递给数组生成器。所以可能是推荐的方式
  • @zeugor 它是not the recommended way[0].
  • @zeugor 该方法确实达到了它的目的,即使用它的开发人员不需要进一步考虑它:1)即使在并发集合上调用它时它也能正常工作而并发修改是正在进行中(尝试预先调整数组大小不会)2)它可以保护您免受天真的假设,即调整数组大小总是更有效(查看 Eugene 关于常用 HotSpot JVM 的链接)3)同时,如果它在特定环境中提供好处,它可以被特定集合覆盖。
【解决方案2】:

调用Collection#toArray方法时,由于实现,其内部参数,即数组大小为0

default <T> T[] toArray(IntFunction<T[]> generator) {
    return toArray(generator.apply(0));
}

但你可以显式地设置它大于实际大小:

public static void main(String[] args) {
    var list = List.of(1, 2, 3);
    var array = list.toArray(q -> {
        System.out.println("arraySize: " + q); // arraySize: 0
        return generateArrayBySize(4);
    });
    System.out.println(Arrays.toString(array)); // [1, 2, 3, null]
}
private static Integer[] generateArrayBySize(int arraySize) {
    System.out.println("arraySize: " + arraySize); // arraySize: 4
    return new Integer[arraySize];
}

另见:Move null elements for each row in 2d array to the end of that row

【讨论】:

    猜你喜欢
    • 2022-11-15
    • 1970-01-01
    • 2019-04-16
    • 1970-01-01
    • 2013-03-27
    • 2011-03-09
    • 2019-12-26
    • 2012-09-03
    • 2014-04-21
    相关资源
    最近更新 更多