2015-07-13 2 views
0

Прежде всего мои объекты:JavaFX ConcurrentModificationException withouth (сознательно) implemtented темы

public class Group { 
    private final ObservableList<IDevice> sourceList; 
    private final ObservableList<IDevice> destinationList; 
    private final ObservableList<Mapping> mappingList; 
...} 

public class Mapping { 
    private final IDevice source; 
    private final IDevice destination; 
    private final MappingMode mode; 
    public final StringProperty sourceName = new SimpleStringProperty(); 
    public final StringProperty destinationName = new SimpleStringProperty(); 
    public final StringProperty modeName = new SimpleStringProperty(); 
...} 

В основном группа содержит два списка мобильным iУстройством, которые могут быть либо источника или назначения и список отображения, который содержит один из них и один двух режимов (перечисление).

Списки IDevice отображаются в собственном представлении списка с таблицей между ними, представляющей сопоставление (содержащий один столбец из первого, один из второго списка и столбец режима).

Я добавил их через setItems, это CellFactory для ListViews

private Callback<ListView<IDevice>, ListCell<IDevice>> getFullNameDisplay() { 
    return new Callback<ListView<IDevice>, ListCell<IDevice>>() { 
     @Override 
     public ListCell<IDevice> call(ListView<IDevice> p) { 
      ListCell<IDevice> cell = new ListCell<IDevice>() { 
       @Override 
       protected void updateItem(IDevice t, boolean bln) { 
        super.updateItem(t, bln); 
        if (t != null) { 
         setText(t.getFullName()); 
        } 
        else 
         setText(""); 
       } 
      }; 
      return cell; 
     } 
    }; 
} 

Колонки устанавливаются следующим образом:

sourceColumn.setCellValueFactory(cellData -> cellData.getValue().sourceName); 
destinationColumn.setCellValueFactory(cellData -> cellData.getValue().destinationName); 
modeColumn.setCellValueFactory(cellData -> cellData.getValue().modeName); 

я добавил две кнопки для каждого ListView для добавления и удаления новые предметы.

Конечно, если удалить источник или устройство назначения, я хочу, чтобы все его отображений удалены, так что я добавил ListChangeListener в двух списках:

private ListChangeListener<IDevice> getDeviceChangeListener() { 
    return (javafx.collections.ListChangeListener.Change<? extends IDevice> c) -> { 
     while (c.next()) { 
      if (c.wasRemoved()) { 
       c.getRemoved().stream().forEach((d) -> { 
        mappingList.stream().filter((map) -> (map.getSource().equals(d) || map.getDestination().equals(d))).forEach((map) -> { 
         mappingList.remove(map); 
        }); 
       }); 
      } 
     } 
    }; 
} 

Это также делает то, что я намеревался это сделать (и все рефакторинги, которые я пытался сделать), но я не могу понять, почему это вызывает (большую часть времени) ConcurrentModificationException, поскольку я еще не использовал потоковую передачу в своем приложении. Кажется, что он не запускается каждый раз, что я понимаю, может быть, повезло в планировании, если бы я использовал потоки. Результат правильный, хотя

Кто-нибудь подскажет?

Заранее спасибо

+0

'ConcurrentModificationException' не имеет ничего общего с многопоточностью: это просто означает, что вы изменили содержание списка, пока вы итерацию через него (что смущает итератор). –

ответ

2

Вы не можете изменять коллекцию при ее итерации через нее, если модификация не выполняется через итератор. В Java 8, Collection класс ввел removeIf(...) метод, который помогает в этом прецеденте:

private ListChangeListener<IDevice> getDeviceChangeListener() { 
    return (javafx.collections.ListChangeListener.Change<? extends IDevice> c) -> { 
     while (c.next()) { 
      if (c.wasRemoved()) { 
       c.getRemoved().forEach(d -> 
        mappingList.removeIf(map -> map.getDestination().equals(d) 
              || map.getSource().equals(d))); 
      } 
     } 
    }; 
} 
+0

Прежде чем я приму это, не могли бы вы сказать мне, почему это не всегда происходит? – Crumar

+0

Не имея полного примера для тестирования. Я предполагаю, что он всегда будет генерировать исключение, предполагая, что что-то было удалено. Может быть, нет, если удаленный элемент является последним в итерации (т. Е. Только если список изменен, а затем итератор пытается получить еще один элемент?). Но это просто догадывается ... –

+0

Ну, ваше решение сработало, надеюсь, что я запомню, что снова проверит старый путь завтра – Crumar

1

В том же цикле, если вы пытаетесь перебрать ту же коллекцию и пытаетесь изменить тот же набор, Java создает этот параллелизм исключение.

Если вы хотите изменить коллекцию, пожалуйста, заполните другую коллекцию для добавления или изменения. Как только он выходит из цикла, вызовите Collection.addAll() или Collection.removeAll().