Минимальный код
List<String> test = new ArrayList<>(Arrays.asList("java-8", "subList", "bug")).subList(0, 2);
Stream<String> stream = test.stream();
test.add("java-9");
stream.forEach(System.out::println); // any terminal operation
Java-8 [Bug]
Приведенный выше код, выполняемый с Java-8, генерирует CME.Согласно javadoc из ArrayList
Итераторы, возвращаемые методами итератора этого класса и listIterator, являются fail-fast : если список структурно измененв любое время после создания итератора, любым способом, кроме как через собственные методы удаления или добавления итератора, итератор выдаст ConcurrentModificationException
.
Таким образом, перед одновременной модификацией итератор быстро и чисто дает сбой, вместо того, чтобы рисковать произвольным недетерминированным поведением в неопределенное время в будущем.
Вывод :
java-8
subList
Exception in thread "main" java.util.ConcurrentModificationException
Вопрос
Согласно аналогичным правилам, , изменяющее коллекцию во время ее повторения, считаетсяошибка программирования и, следовательно, выбрасывание ConcurrentModificationException
выполняется на основе «наилучшего возможного».
Но тогда вопрос заключался в том, что в приведенном выше коде мы фактически закончили изменять коллекцию во время ее итерацииа точнее до этого?
не должен ли поток быть ленивым?
При дальнейшем поиске такого ожидаемого поведения обнаружил что-то похожее, о котором сообщалось, и исправил как ошибку - ArrayList.subList (). Spliterator () не имеет позднего связывания , и это было исправлено в Java-9.
Еще одна ошибка, связанная с этим - ArrayList.subList (). Iterator (). ForEachRemaining () off-by-one-error
Java-11 [Исправлено]
Хотя исправлено в Java-9 в соответствии с отчетом об ошибке, реальный тест, который я выполнял, был на версии LTS, и код, как указано выше, работает без каких-либо исключений.
Вывод :
java-8
subList
java-9