Я продолжаю получать исключение java.util.concurrentmodification .. Как это исправить? - PullRequest
2 голосов
/ 03 января 2012

Я работал над этим фрагментом кода. Вот псевдокод того, что я хочу, чтобы произошло:

a.check, если размер разделов (который является списком) равен 0.
b.Если размер секции равен 0, то автоматически записываете ученика в секцию, вызывая section.add (newSection)
в противном случае, если размер разделов не равен нулю, проверьте наличие конфликтов с расписанием
d.Если конфликтов нет, зарегистрируйте студента в секцию, вызвав section.add (newSection)
e.else ничего не делать

Java продолжает выдавать ошибку «java.util.concurrentmodificationexception». Я знаю, я не должен изменять размер ArrayList при обходе списка, потому что он изменит итератор. Есть ли другой способ решить эту проблему? : D

Большое спасибо. Ваша помощь высоко ценится. :)

 public String enrollsTo(Section newSection){


        StringBuffer result = new StringBuffer();

        String resultNegative = "Failed to enroll in this section.";
        String resultPositive = "Successfully enrolled in section: " + newSection.getSectionName() + ".";

        int previousSectionSize = sections.size();

        if(this.sections.isEmpty()){
            this.sections.add(newSection);
            result.append(resultPositive);
        }else{
            for(Iterator<Section> iterator = sections.iterator(); iterator.hasNext() ; ){
                Section thisSection = iterator.next();

                if(thisSection.conflictsDayWith(newSection)==false &&
                    thisSection.conflictsTimeWith(newSection)==false){
                    this.sections.add(newSection);  //<-- i believe the problem lies here.
                    result.append(resultPositive);
                }
            }
        }
//      if(this.sections.size() == previousSectionSize){
//          result.append(resultNegative);
//      }
        return result.toString();
    }

Ответы [ 6 ]

1 голос
/ 03 января 2012

Не делайте sections.add(newSection) внутри цикла for, так как это модификация коллекции, с которой вы сейчас перебираете.

Кроме того, вы не хотите проверять все разделы, прежде чем решить,добавить newSection или нет?Может быть, что-то вроде этого:

boolean conflict = false;
for (...) {
  if (/* check for conflict */) {
    conflict = true;
    break;
  }
}
if (!conflict) {
  sections.add(newSection);
}
0 голосов
/ 03 января 2012

Я согласен с @sudocode, что вы не хотите добавлять newSection каждый раз, когда обнаруживаете раздел, который не конфликтует.Я бы подумал, что когда вы шагаете по коду в вашем отладчике, это будет очевидно.;)

Кстати, еще один (более неясный) способ сделать это без флага -

CHECK: {
  for (...) {
    if (/* check for conflict */) 
      break CHECK;
  }

  sections.add(newSection);
}
0 голосов
/ 03 января 2012

ConcurrentModificationException Исключения часто возникают, когда вы изменяете коллекцию, когда вы перебираете ее элементы.Прочитайте этот учебник для получения более подробной информации и этого старого сообщения SO Почему it.next () выбрасывает java.util.ConcurrentModificationException?

0 голосов
/ 03 января 2012

Вы правы в своем предположении,

 this.sections.add(newSection);  

определенно является источником вашей проблемы.

Самое простое решение: имейте логическое значение, представляющее доступность раздела.Начните, предполагая, что это доступно.Если в вашем итераторе есть конфликт, установите для него значение false.После итератора добавьте раздел, если раздел доступен (логическое значение true).

0 голосов
/ 03 января 2012

Во время итерации коллекции вы не можете изменить ее. Строка this.sections.add(newSection); выдает исключение. Вам может понадобиться использовать некоторый логический маркер, чтобы проверить состояние

if(thisSection.conflictsDayWith(newSection)==false &&
                    thisSection.conflictsTimeWith(newSection)==false)

После цикла for, если ваш логический маркер верен, вы можете написать

 this.sections.add(newSection);  
                    result.append(resultPositive);
0 голосов
/ 03 января 2012

Из Javadoc для ConcurrentModificationException (мой акцент):

Это исключение может быть вызвано методами, обнаружившими одновременное модификация объекта, когда такая модификация недопустима.

Например, изменение одного потока, как правило, недопустимо Коллекция, в то время как другой поток перебирает ее. В общем, результаты итерации при этих обстоятельствах не определены. Некоторые реализации Iterator (включая те из всех общих реализации целевого сбора, предоставленные JRE) может выбрать бросить это исключение, если это поведение обнаружено. Итераторы, которые делают они известны как итераторы с быстрым отказом, так как они быстро и чисто, скорее, рискуя произвольным, недетерминированным поведением в неопределенное время в будущем.

Обратите внимание, что это исключение не всегда означает, что объект имеет был одновременно изменен другим потоком. Если один поток выдает последовательность вызовов методов, которая нарушает контракт объект, объект может вызвать это исключение. Например, если поток изменяет коллекцию напрямую, пока он выполняет итерацию коллекция с отказоустойчивым итератором, итератор сгенерирует это исключение.

Обратите внимание, что отказоустойчивое поведение не может быть гарантировано как обычно говоря, невозможно сделать какие-либо жесткие гарантии в присутствии несинхронизированная одновременная модификация. Отказоустойчивые операции броска ConcurrentModificationException на основе максимальных усилий. Следовательно, это было бы неправильно писать программу, которая зависела от этого исключения для его правильность: следует использовать только ConcurrentModificationException обнаруживать ошибки.

Потенциальное решение: вместо добавления непосредственно в итерируемый список, добавьте его во временный список, а затем по окончании итерации выполните addAll().

...