-1

我想将数组转换double[]为不可变集合以用于值对象。但是,我正在处理一个非常大的数组,并且不断收到错误消息java.lang.OutOfMemoryError: Java heap space

我目前正在使用

Collections.unmodifiableList(DoubleStream.of(myArray).boxed().collect(Collectors.toList()));

我认为这是因为我的程序内存不足。有没有更便宜的方法可以将 double[] 转换为不可变列表?

4

2 回答 2

1

创建自己的List<Double>怎么样?如果您实现AbstractList<Double>,您只需要为不可修改的列表实现两种方法:

class MyDoubleList extends AbstractList<Double> implements RandomAccess {

    private double[] backingArray;

    public MyDoubleList(double[] backingArray) {
        this.backingArray = backingArray;
    }

    @Override
    public Double get(int index) {
        return backingArray[index];
    }

    @Override
    public int size() {
        return backingArray.length;
    }

    // adding other list methods should be trivial...
}

用法:

List<Double> list = new MyDoubleList(myBigDoubleArray);

请注意,如果更改后备数组,列表内容也会更改。为了防止这种情况,您通常会复制传入的数组,但是由于复制数组可能会导致内存不足异常,所以我没有这样做。


或者,如果您使用 Guava,请使用Doubles.asList(myBigDoubleArray),它的作用基本相同。感谢乔的建议!

于 2020-05-16T13:07:51.797 回答
0

流非常适合函数式编程和可读性,但当性能是主要问题时应避免使用。他们创建了不必要的额外对象。

同样令人惊讶的是,双原始类型的数组比它们的包装类双数组消耗更多的内存(参考:https ://www.baeldung.com/java-primitives-vs-objects )

使用Double对象数组而不是双原语,然后运行:

Collection<Double> l = Collections.unmodifiableCollection(Arrays.asList(myArray));

我比较了这两种方法

    public static void main(String[] args) {
        int len = 1000000;
        Double[] myArray = new Double[len];
        for (int i = 0; i < len; i++) {
            myArray[i] = Math.random();
        }
        Collection<Double> l = Collections.unmodifiableCollection(Arrays.asList(myArray));
        long totalMem = Runtime.getRuntime().totalMemory();
        long usedMem =  totalMem - Runtime.getRuntime().freeMemory();
        System.out.println("totalMem="+humanReadableByteCountBin(totalMem));
        System.out.println("usedMem=" + humanReadableByteCountBin(usedMem));
        System.out.println("l has " + l.size() + " items ");
    }

流方法使用 48Mb,而Arrays.asListDouble 使用 28Mb。

于 2020-05-16T13:23:25.780 回答