2017-07-20 13 views
5

AbstractSpliterator実装を使用すると私はjava.lang.OutOfMemoryError: Java heap spaceを得ました。これは未知のサイズを報告します。Abstract未知のサイズを持つスプリッタの実装はOutOfMemoryErrorをスローします:Javaヒープ領域

この場合、AbstractSpliteratorに拡張されたクラスStreamCollapseを定義し、tryAdvance()の実装で隣り合った要素のシリーズをマージします。そのコンストラクタは、スーパーコンストラクタをsuper(Long.MAX_VALUE, source.characteristics())と呼びます。

API documentationについては、Long.MAX_VALUEを使用するとサイズが不明であることが予想されました。しかし、代わりにそのサイズのメモリを割り当てようとしているようです。

なぜそのスペースを割り当てようとしていますか?見積もりサイズにはどのような価値がありますか?

ここでは、例のテストです:

Stream<Integer> nrs = Stream.of(3, 3, 5, 5, 3, 3, 3, 4, 4, 4 ,5 , 5); 
Integer [] expected = {3, 5, 3, 4, 5}; 
Object[] actual = collapse(nrs).toArray(); 
assertEquals(actual, expected); 

そしてcollapse()メソッドの実装:

static <T> Stream<T> collapse(Stream<T> source) { 
    return StreamSupport.stream(
      new StreamCollapse<T>(source.spliterator()), false); 
} 

class StreamCollapse<T> extends AbstractSpliterator<T> implements Consumer<T> { 

    private final Spliterator<T> source; 
    private T curr = null; 

    StreamCollapse(Spliterator<T> source) { 
     super(Long.MAX_VALUE, source.characteristics()); 
     this.source = source; 
    } 

    @Override 
    public boolean tryAdvance(Consumer<? super T> action) { 
     T prev = curr; 
     boolean hasNext; 
     while ((hasNext = source.tryAdvance(this)) && curr.equals(prev)) { } 
     if(hasNext) action.accept(curr); 
     return hasNext; 
    } 

    @Override 
    public void accept(T item) { 
     curr = item; 
    } 
} 

答えて

7

あなたは、たとえば、あなたの合成spliteratorから特性を削除する必要があります。

// an unknown spliterator shouldn't having SIZED | SUBSIZED characteristics 
//            v 
super(Long.MAX_VALUE, source.characteristics() & (~(SIZED | SUBSIZED))); 

いつかスプリトアートまたはSIZED Spliteartorの場合、Spliterator#getExactSizeIfKnownはストリームを使用して配列を作成します。並行して

Characteristic value signifying that the value returned from estimateSize() prior to traversal or splitting represents a finite size that, in the absence of structural source modification, represents an exact count of the number of elements that would be encountered by a complete traversal.

IFストリームの実行がStream#toArray意志がestimateSize> = Long.MAX_VALUE - 8場合IllegalArgumentExceptionをスローします。ストリームが順次ストリームである IF Stream#toArray意志がestimateSizeに内部アレイ容量を成長

+3

これは正解です。スプライテータ*は、 'SIZED'と' SUBSIZED'特性をクリアする必要があります。さらに、ソーススプライテータの 'estimateSize()'をフィルタスプライテータの推定サイズとして使用することは良いアプローチになります。結局のところ、実際のサイズは0とそのソースサイズの間のどこかになります。これは 'filter'のやり方であり、現在の実装では完全に未知のサイズよりもはるかに優れています。 – Holger

+0

@Holger監査のために私の答えをありがとう。私もあなたの提案を得る。 –

関連する問題