RFR: 8372946 - TreeMap sub-map entry spliterator is expensive [v4]
Chen Liang
liach at openjdk.org
Mon Feb 23 15:35:40 UTC 2026
On Mon, 23 Feb 2026 14:44:59 GMT, Oli Gillespie <ogillespie at openjdk.org> wrote:
>> Oh I understand now. The default Set spliterator is `Spliterator<T> spliterator(Collection<? extends T> c, int characteristics)`. It doesn't create an iterator until forEachRemaining is called, which in the test is *after* the .remove modification, so it doesn't observe a discrepancy. The new implementation uses creates the iterator up-front to pass to `spliteratorUnknownSize`, so in that case the iterator is created before the modification, hence CME.
>
> It ends up something like this:
>
>
> public static void main(String[] args) {
> List<String> strings = new LinkedList<>();
> strings.add("foo");
> strings.add("bar");
>
> Spliterator<String> s = Spliterators.spliterator(strings, Spliterator.DISTINCT); // Don't create iterator yet
> strings.remove(strings.iterator().next());
> s.forEachRemaining(System.out::println); // Spliterator creates iterator here, after the .remove call. No CME
>
> s = Spliterators.spliteratorUnknownSize(strings.iterator(), Spliterator.DISTINCT); // Eagerly create the iterator
> strings.remove(strings.iterator().next()); // Modifying after the iterator was created
> s.forEachRemaining(System.out::println); // ConcurrentModificationException
> }
>
>
> So it's just a side effect of `spliteratorUnknownSize` needing the iterator to be created already. I think the test skip is valid, then - it's true that this case is no longer lazy like it was.
Yes, seems you cannot create a spliterator with a lazy iterator. This is fine.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/28608#discussion_r2841502408
More information about the core-libs-dev
mailing list