JavaFX ConcurrentModificationException没有(明知)实现的线程

时间:2015-07-13 16:29:18

标签: java listview javafx tableview changelistener

首先是我的对象:

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();
...}

基本上,一个组包含两个IDevices列表,它们可以是源或目标,也可以是包含其中一个和两种模式之一的映射列表(枚举)。

IDevice列表显示在一个自己的列表视图中,它们之间有一个表,表示映射(包含第一列中的一列,第二列中的一列和模式列)。

我已经通过setItems添加了它们,这是ListViews的CellFactory

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);

我为每个列表视图添加了两个按钮来添加和删除新项目。

当然,如果我删除源设备或目标设备,我希望删除所有映射,所以我将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,因为我还没有在我的应用程序中使用任何线程。它似乎每次都没有触发,我明白如果我要使用线程,我可以很幸运。虽然结果是正确的

有人知道吗?

提前致谢

2 个答案:

答案 0 :(得分: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)));
            }
        }
    };
}

答案 1 :(得分:1)

在同一个循环中,如果您尝试迭代同一个集合并尝试修改同一个集合,Java会抛出此并发异常。

如果您想修改该系列,请保留另一个系列以进行添加或修改。一旦它出现在循环中,请调用Collection.addAll()或Collection.removeAll()接口。