Ответ 1
ConcurrentModificationException
не имеет отношения к concurrency и синхронизации. Доступ к изменчивому List
одновременно может привести к его повреждению и/или выбросить исключение (быть готовым ко всем 3 возможностям). Вы не можете выполнить этот код, но при многопоточности он тоже не работает:
- Без синхронизации и без
foos
будетvolatile
, нет гарантии, что другой поток когда-либо увидит сделанные вами изменения. - Даже при
volatile
может случиться, что некоторые изменения теряются, например, когда два потока добавляют элемент вfoos
, оба из них могут начинаться с исходного значения, а затем записывать последние победы (и только его элемент добавляется).
Код, который вы пытаетесь избежать, нечего избегать.
- "Мне нужно создавать лишние промежуточные коллекции" - да, но нет бесплатного обеда:
- заранее определить размер результата, что означает дополнительную итерацию по всему списку
- или выделите достаточно большой массив и скопируйте необходимый диапазон в результирующий список
- или выделите достаточно большой массив и используйте только его часть (экономя время и теряя память)
- или создать неизменяемое представление (сохранение как времени, так и памяти, но, возможно, потеря времени)
- Ответ AFAIK Frank реализует первую возможность, что прекрасно, если предикат работает быстро.
- "Мне нужно смешать java.util Коллекции с guava ImmutableCollections, хотя я бы хотел придерживаться одной парадигмы". - да, но для мутирования коллекции необходима изменчивая коллекция.
ImmutableList.Builder
охватывает только самые распространенные случаи, позволяющие обрабатывать их компактным способом.
Возможно, вам стоит взглянуть на постоянные коллекции, которые оптимизированы для таких операций. Однако вы не должны ожидать, например. постоянный список должен быть таким же быстрым, как ArrayList
или ImmutableList
.