Collections.emptyList().spliterator() is not ORDERED (original) (raw)

Tagir F. Valeev amaembo at gmail.com
Sun Oct 25 16:49:26 UTC 2015


Hello!

PS> In this case we should fix Stream.concat to check if a PS> spliterator reporting SIZED is empty, which will allow us to optimize the concatenation [1]. PS> [1] https://bugs.openjdk.java.net/browse/JDK-8022805

I tried to fix this issue, but stuck into subtle behavior change. My idea is quite straightforward:

public static Stream concat(Stream<? extends T> a, Stream<? extends T> b) { Objects.requireNonNull(a); Objects.requireNonNull(b);

@SuppressWarnings("unchecked")
Spliterator<T> asplit = (Spliterator<T>) a.spliterator(); 
@SuppressWarnings("unchecked")
Spliterator<T> bsplit = (Spliterator<T>) b.spliterator(); 
Spliterator<T> split;
if (asplit.getExactSizeIfKnown() == 0)
    split = bsplit;
else if (bsplit.getExactSizeIfKnown() == 0)
    split = asplit;
else
    split = new Streams.ConcatSpliterator.OfRef<>(asplit, bsplit);
Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
return stream.onClose(Streams.composedClose(a, b));

}

Similar for primitive streams. The difference occurs when the fail-fast source is modified after concat operation:

List l1 = Arrays.asList(1,2,3); List l2 = new ArrayList<>(); Stream s = Stream.concat(l1.stream(), l2.stream()); l2.add(4); s.forEach(System.out::println);

In current implementation concat binds the late-binding spliterators (by the way it's not documented and not very obvious that concat binds; probably documentation update should be considered). Thus currently this code produces

1 2 3 Exception in thread "main" java.util.ConcurrentModificationException ...

However after my change the exception disappears as the l2 spliterator is not traversed at all. So do you think such behavior change is acceptable or not?

Also some tests in tests/java/util/stream/ConcatTest.java which check whether the resulting spliterator is ordered should be updated as now concat may return ORDERED stream if one of the parties is UNORDERED, but SIZED and empty. Next, I'm not absolutely sure whether the case when both input streams are SIZED/empty should be handled separately (return stream on Spliterators.emptySpliterator()?) or current implementation (returning stream on second spliterator) is ok. Finally the documentation probably should mention about special handling of SIZED/empty stream. On the other hand currently it says:

The resulting stream is ordered if both of the input streams are ordered...

It does not say "if and only if", thus probably the update is unnecessary here.

So what do you think about this fix in general? Is it reasonable for me to continue working on it and prepare full-fledged patch? Is there any chance that this patch will be sponsored?

With best regards, Tagir Valeev.



More information about the core-libs-dev mailing list