Здравствуйте кидает Exception ConcurrentModificationException
на этой строчке for (Transaction t : c.getTransactions())
(64 строчка) на 2 итерации. Саму суть ошибки понимаю - случается она тогда, когда в цикле происходит удаление элементов итератора. Пытался remove изменить на removeIF
, но ошибка та же.Это уникальный вопрос, потому что он возникает, когда все требования по его решению соблюдены.
private static void iteration() {
Integer n = 1;
Integer k = 1;
Double maxProfit;
Integer clusterInd;
while (k > 0) {
System.out.println("Итерация " + n);
n++;
k = 0;
for (int i=0;i<clusters.size();i++) {
Cluster c = clusters.get(i);
for (Transaction t : c.getTransactions()) {//ошибку кидает здесь на 2 итерации
maxProfit = profit();
clusterInd = -1;
c.deleteTransaction(t);
int j = 0;
for (Cluster cl : clusters) {
if (j != i) {
cl.addTransaction(t);
Double p = profit();
if (p > maxProfit) {
maxProfit = p;
clusterInd = j;
}
cl.deleteTransaction(t);
}
j++;
}
if (clusterInd == -1){
clusters.get(i).addTransaction(t);
}else {
k++;
clusters.get(clusterInd).addTransaction(t);
}
}
}
}
System.out.println(k);
}
Функция, в которой происходит удаление транзакции:
public void deleteTransaction(Transaction m) {
if (this.count > 0) {
String[] trans = m.getTrans();
for (String s : trans) {
this.square--;
if (freq.containsKey(s)) {
if (freq.get(s) > 0) {
this.freq.put(s, freq.get(s) - 1);
if (this.freq.get(s) == 0) {
this.width--;
freq.entrySet().removeIf(entry -> entry.getKey().equals(s));
}
}
}
}
this.count--;
if (this.count > 0) {
this.height = (double) this.square / this.width;
} else {
this.height = 0.0;
}
transactions.removeIf(m::equals);
}
}
Логи:
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:939)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:893)
at com.lab6.ClopeAlgorithm.iteration(ClopeAlgorithm.java:64)
at com.lab6.ClopeAlgorithm.main(ClopeAlgorithm.java:96)
Создадим небольшую мапу:
final HashMap<Object, Object> map = new HashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
Следующие выражения выбьют ошибку:
Java 8+:
map.entrySet().stream().filter((i) -> ("3".equals(i.getKey()))).forEachOrdered((i) -> {
map.remove(i.getKey());
});
Java < 8:
for (Entry<Object, Object> i : map.entrySet()) {
if ("2".equals(i.getKey())) {
map.remove(i.getKey());
}
}
Выражения, которые не выдадут ошибок:
Работает только на 1 удаление, если добавить еще один if
для удаления, выдаст ошибку NoSuchElementException
final Iterator<Entry<Object, Object>> i = map.entrySet().iterator();
while (i.hasNext()) {
if ("2".equals(i.next().getKey())) {
i.remove();
}
}
Если хотим удалить два и более элемента, можно использовать:
while (i.hasNext()) {
switch ((String) i.next().getKey()) {
case"2":
case"3":
i.remove();
break;
}
}
Для удаления, добавления, изменения, лучше использовать switch
:
final Map<Object, Object> map = new ConcurrentHashMap<>();
map.put("1", "1");
map.put("2", "2");
map.put("3", "3");
map.put("4", "5");
final Iterator<Entry<Object, Object>> i = map.entrySet().iterator();
while (i.hasNext()) {
switch ((String) i.next().getKey()) {
case "3":
i.remove();
map.put("5", "5");
final Iterator<Entry<Object, Object>> it = map.entrySet().iterator();
while (it.hasNext()) {
if ("2".equals((String) it.next().getKey())) {
it.remove();
map.put("5", "5");
map.put("6", "6");
map.remove(map.get("1"));
}
}
break;
}
}
System.out.println(map); // {4=5, 5=5, 6=6}
Но опять-же у этого всего есть побочные эффекты.
Если в хранилище залетел какой-то объект, во время:
while (i.hasNext()) {
switch((String)i.next().getKey()) {
//.....
}
}
Получим ConcurrentModificationException
.
В вашем случае можно использовать подобно mutex
.
synchronized(map) {
//....
}
Тогда можно будет не бояться, что залетает.
Вместо цикла foreach используйте явный итератор и его метод remove.
Подсказали решение:
Изменить for (Transaction t : c.getTransactions())
на
for (int i=0;i<clusters.size();i++) {
Cluster c = clusters.get(i);
List<Transaction> transactions = new ArrayList<>(c.getTransactions());
for (Transaction t : transactions) {
...
}
}
Foreach – это механизм для работы с элементами коллекции, а не с самой коллекцией. Использование foreach для модификации коллекции – это уже не правильно. А писать костыли и велосипеды, чтобы «расширить возможности» конструкции языка – и вовсе плохая затея. Этот подход сломает возможность заменить реализацию А на реализацию Б без танцев с бубном и переписывания всего кода, где коллекция модифицировалась в foreach.
Вот один из классических подходов работы с итераторами:
for (Iterator<Integer> it = set.iterator(); it.hasNext(); ) {
if (it.next() % 2 == 0) {
it.remove();
}
}
Взято отсюда:
https://habr.com/post/325426/#comment_10149968
Есть проект на JavaFX, для хранения данных нужно использовать сериализацию в JAXBДля этого нужно использовать XML
Несколько сбоев было но не могу понять изза чегоВзгляните:
Я в приложении для индефикации пользователя использую uuid девайсаНедавно начал использовать такую систему