Предлагаю вам также взглянуть на Symmetricds . это библиотека репликации SQLite, доступная для систем Android. вы можете использовать его для синхронизации своей клиентской и серверной базы данных, я также предлагаю иметь отдельные базы данных на сервере для каждого клиента. Попытка хранить данные всех пользователей в одной базе данных mysql не всегда лучшая идея. Особенно, если пользовательские данные будут быстро расти.
Iterator.remove()
безопасен, вы можете использовать его следующим образом:
List<String> list = new ArrayList<>();
// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
// Iterator<String> iterator = list.iterator();
// while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
// Remove the current element from the iterator and the list.
iterator.remove();
}
}
Обратите внимание, что Iterator.remove()
является единственным безопасным способом изменять коллекцию во время итерации; поведение не определено, если базовая коллекция модифицируется каким-либо другим способом, пока выполняется итерация.
Источник: docs.oracle> Интерфейс коллекции
Аналогичным образом, если у вас есть ListIterator
и вы хотите добавить элементы, вы можете использовать ListIterator#add
, по той же причине вы можете использовать [f6 & mdash;] & NBSP; он предназначен для этого.
это может быть не лучшим образом, но для большинства небольших случаев это должно быть приемлемым:
"создать второй пустой массив и добавить только те, которые вы хотите keep "
blockquote>Я не помню, где я это читал ... для справедливости я сделаю эту вики в надежде, что кто-то найдет ее или просто не заработает репутацию Я не заслуживаю.
С помощью Java 8 вы можете использовать новый removeIf
метод . Применимо к вашему примеру:
Collection<Integer> coll = new ArrayList<Integer>();
//populate
coll.removeIf(i -> i.intValue() == 5);
removeIf
использует петли Iterator
и while
. Вы можете увидеть его в java 8 java.util.Collection.java
– omerhakanbilici
31 October 2016 в 15:10
ArrayList
, переопределяют его по соображениям производительности. Тот, о котором вы говорите, является только реализацией по умолчанию.
– Didier L
31 March 2017 в 08:33
Collection<Integer> l = new ArrayList<Integer>();//Do the collection thing...
l.removeIf(i -> i == 5); //iterates through the collection and removes every occurence of 5
Лямбда-выражения и методы сбора в Jdk 8 входят в Handy и добавляют некоторый синтаксический сахар
С Коллекции Eclipse (ранее коллекции GS ) будет работать метод removeIf
, определенный на MutableCollection :
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
С синтаксисом Java 8 Lambda это можно записать следующим образом:
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
Необходим вызов Predicates.cast()
, потому что по умолчанию removeIf
метод был добавлен на интерфейс java.util.Collection
в Java 8.
Примечание: я являюсь коммиттером для коллекций Eclipse .
Это работает:
Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
if (iter.next().intValue() == 5) {
iter.remove();
}
}
Я предположил, что поскольку цикл foreach является синтаксическим сахаром для итерации, использование итератора не помогло бы ... но оно дает вам эту функциональность .remove()
.
В дополнение к @assylias
answer вы также можете использовать новый поток api, если вы используете Java 8:
List<Integer> l = Arrays.asList(4, 5, 6);
static boolean condition(Integer i) {
return i == 5;
}
static Predicate<Integer> predicate = YourClassName::condition;
l.stream()
.filter(predicate.negate())
.forEach(System.out::println);
Если вы инвертируете условие, решение становится еще более кратким, поскольку вам не нужно negate()
предикат, что позволяет использовать только ссылку на метод:
List<Integer> l = Arrays.asList(4, 5, 6);
static boolean condition(Integer i) {
return i != 5; // <-- condition has been negated
}
l.stream()
.filter(YourClassName::condition)
.forEach(System.out::println);
Один из красотой этого является то, что поток лениво оценивается, т. е. операция filter()
фактически не оценивается до тех пор, пока она не будет использована терминальной операцией, такой как forEach()
. Подробнее об этом можно найти в учебнике для Oracle .
List<String> strings=new ArrayList<String>(){};
while(strings.size() > 0) {
String str = strings.remove(0);
}
Поскольку вопрос уже ответил, то лучший способ - использовать метод удаления объекта итератора, я хотел бы перейти к особенностям места, где была выбрана ошибка "java.util.ConcurrentModificationException"
.
Каждый класс коллекции имеет частный класс, который реализует интерфейс Iterator и предоставляет такие методы, как next()
, remove()
и hasNext()
.
Следующий код выглядит примерно так:
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
Здесь метод checkForComodification
реализован как
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
Итак, как вы можете видеть, если вы явно попытаетесь удалить элемент из коллекции. Это приводит к тому, что modCount
отличается от expectedModCount
, что приводит к исключению ConcurrentModificationException
.
Лучшим способом (рекомендуется) является использование пакета java.util.Concurrent. Используя этот пакет, вы можете легко избежать этого исключения. см. Модифицированный код
blockquote>public static void main(String[] args) { Collection<Integer> l = new CopyOnWriteArrayList<Integer>(); for (int i=0; i < 10; ++i) { l.add(new Integer(4)); l.add(new Integer(5)); l.add(new Integer(6)); } for (Integer i : l) { if (i.intValue() == 5) { l.remove(i); } } System.out.println(l); }
A ListIterator
позволяет добавлять или удалять элементы в списке. Предположим, у вас есть список объектов Car
:
List<Car> cars = ArrayList<>();
// add cars here...
for (ListIterator<Car> carIterator = cars.listIterator(); carIterator.hasNext(); )
{
if (<some-condition>)
{
carIterator().remove()
}
else if (<some-other-condition>)
{
carIterator().add(aNewCar);
}
}
Люди утверждают, что нельзя удалить из коллекции, которая повторяется в цикле foreach. Я просто хотел указать, что это технически неверно и точно описывает (я знаю, что вопрос OP настолько продвинут, чтобы избежать этого, чтобы понять это) код, лежащий в основе этого предположения:
for (TouchableObj obj : untouchedSet) { // <--- This is where ConcurrentModificationException strikes
if (obj.isTouched()) {
untouchedSet.remove(obj);
touchedSt.add(obj);
break; // this is key to avoiding returning to the foreach
}
}
Не исключено, что вы не сможете удалить из итерированного Colletion
, а затем продолжить, после чего продолжить. Следовательно, break
в коде выше.
Извиняется, если этот ответ является несколько специализированным прецедентом и более подходит для исходного потока , из которого я пришел сюда, отмеченный как дубликат (несмотря на то, что этот поток выглядит более нюансированным) этого и заблокирован.
В таких случаях общий трюк (был?) для возврата назад:
for(int i = l.size() - 1; i >= 0; i --) {
if (l.get(i) == 5) {
l.remove(i);
}
}
Тем не менее, я более чем счастлив, что у вас есть лучшие способы в Java 8, например. removeIf
или filter
в потоках.
ArrayList
s или подобных коллекций.
– Landei
30 August 2014 в 16:47
for(int i = l.size(); i-->0;) {
?
– John
27 April 2018 в 20:20
С традиционным для цикла
ArrayList<String> myArray = new ArrayList<>();
for (int i = 0; i < myArray.size(); ) {
String text = myArray.get(i);
if (someCondition(text))
myArray.remove(i);
else
i++;
}
Вы можете перебирать список, используя for-loop, и вам нужно вызвать list.remove (0). Вам нужно с жестким кодом индексировать индексный параметр remove с нулем. См. Также этот ответ :
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
int list_size = list.size();
for (int i = 0; i < list_size; i++) {
list.remove(0);
}
В случае ArrayList: remove (int index) - если (индекс - позиция последнего элемента), он избегает без System.arraycopy()
и не занимает времени для этого.
Время arraycopy увеличивается, если (индекс уменьшается), кстати, элементы списка также уменьшаются!
лучший эффективный способ удаления - удаление его элементов в порядке убывания: while(list.size()>0)list.remove(list.size()-1);
// принимает O (1) while(list.size()>0)list.remove(0);
// принимает O (факториал ( n))
//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
Integer integer = rdm.nextInt();
ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion
// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++)
if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion
// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--)
if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion
// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
Сделать копию существующего списка и перебрать новую копию.
for (String str : new ArrayList<String>(listOfStr))
{
listOfStr.remove(/* object reference or index */);
}
Вы можете либо использовать итератор прямо так, как вы упомянули, либо сохранить вторую коллекцию и добавить каждый элемент, который хотите удалить, в новую коллекцию, а затем удалитьAll в конце. Это позволяет вам использовать безопасность типа для каждого цикла за счет увеличения использования памяти и времени процессора (не должно быть огромной проблемой, если у вас нет действительно больших списков или действительно старого компьютера)
public static void main(String[] args)
{
Collection<Integer> l = new ArrayList<Integer>();
Collection<Integer> itemsToRemove = new ArrayList<Integer>();
for (int i=0; i < 10; ++i) {
l.add(new Integer(4));
l.add(new Integer(5));
l.add(new Integer(6));
}
for (Integer i : l)
{
if (i.intValue() == 5)
itemsToRemove.add(i);
}
l.removeAll(itemsToRemove);
System.out.println(l);
}
for (Integer i : l)
{
if (i.intValue() == 5){
itemsToRemove.add(i);
break;
}
}
Ловушка - это удаление элемента из списка, если вы пропустите внутренний вызов iterator.next (). он все еще работает! Хотя я и не предлагаю писать такой код, он помогает понять концепцию: -)
Cheers!
У меня есть предложение по указанной выше проблеме. Нет необходимости в дополнительном списке или дополнительном времени. Пожалуйста, найдите пример, который будет делать одни и те же вещи, но по-другому.
//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
Object r = list.get(index);
if( state ) {
list.remove(index);
index = 0;
continue;
}
index += 1;
}
Это позволит избежать исключения параллелизма.
ArrayList
и, следовательно, не может полагаться на get()
. В противном случае, вероятно, хороший подход.
– kaskelotti
13 April 2014 в 12:09
ConcurrentHashMap или ConcurrentLinkedQueue или ConcurrentSkipListMap может быть другой опцией, потому что они никогда не будут бросать любое ConcurrentModificationException, даже если вы удалите или добавите элемент.
iterator.next()
в цикл for? Если нет, может кто-нибудь объяснить, почему? – Blake 12 April 2016 в 13:22