Solved ConcurrentModificationException error

Discussion in 'Plugin Development' started by Awesomebanana2002, Jul 25, 2015.

Thread Status:
Not open for further replies.
  1. Dear,
    I got an ConcurrentModificationException error in my loadChests() method, and I can't get it fixed. Here is my exact error:
    Code:
    [14:47:52 ERROR]: Error occurred while enabling SurvivalGames v1.0 (Is it up to
    date?)
    java.util.ConcurrentModificationException
            at java.util.ArrayList$Itr.checkForComodification(Unknown Source) ~[?:1.
    8.0_51]
            at java.util.ArrayList$Itr.next(Unknown Source) ~[?:1.8.0_51]
            at com.TheWGB.SG.arena.Arena.loadChests(Arena.java:426) ~[?:?]
            at com.TheWGB.SG.arena.Arena.<init>(Arena.java:62) ~[?:?]
            at com.TheWGB.SG.Utils.registerArenas(Utils.java:215) ~[?:?]
            at com.TheWGB.SG.Main.onEnable(Main.java:82) ~[?:?]
            at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:321) ~[S
    pigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader
    .java:335) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManage
    r.java:405) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.craftbukkit.v1_8_R1.CraftServer.loadPlugin(CraftServer.jav
    a:356) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.craftbukkit.v1_8_R1.CraftServer.enablePlugins(CraftServer.
    java:316) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.craftbukkit.v1_8_R1.CraftServer.reload(CraftServer.java:74
    6) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.Bukkit.reload(Bukkit.java:534) [Spigot18.jar:git-Spigot-4f
    af77a-17a3db7]
            at org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:
    25) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:14
    1) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.craftbukkit.v1_8_R1.CraftServer.dispatchCommand(CraftServe
    r.java:646) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at org.bukkit.craftbukkit.v1_8_R1.CraftServer.dispatchServerCommand(Craf
    tServer.java:632) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at net.minecraft.server.v1_8_R1.DedicatedServer.aM(DedicatedServer.java:
    353) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at net.minecraft.server.v1_8_R1.DedicatedServer.z(DedicatedServer.java:3
    17) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at net.minecraft.server.v1_8_R1.MinecraftServer.y(MinecraftServer.java:6
    34) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at net.minecraft.server.v1_8_R1.MinecraftServer.run(MinecraftServer.java
    :537) [Spigot18.jar:git-Spigot-4faf77a-17a3db7]
            at java.lang.Thread.run(Unknown Source) [?:1.8.0_51]
    And here is the method:
    Code:
        private void loadChests() {
            originalChests = new ArrayList<Chest>();
          
            List<String> chestsFormat = Arenas.get().getStringList(ID+".chests");
          
            for(String s : chestsFormat) {
                String[] parts = s.split(" ");
              
                int x = Integer.parseInt(parts[0]);
                int y = Integer.parseInt(parts[1]);
                int z = Integer.parseInt(parts[2]);
              
                Location loc = new Location(world, x, y, z);
                Block block = loc.getBlock();
                if(block.getType() != Material.CHEST) {
                    chestsFormat.remove(s);
                    continue;
                }
                Chest chest = (Chest) block.getState();
              
                originalChests.add(chest);
            }
          
            if(chestsFormat != Arenas.get().getStringList(ID+".chests")) {
                Arenas.get().set(ID+".chests", chestsFormat);
              
                Arenas.save();
            }
        }
    Thanks!
     
  2. You can't edit a list while iterating over it with a nested for-loop. Use something like this:
    for (int i = 0; i < list.size(); i++) {
    String str = list.get(i);

    }

    Or an iterator
     
  3. Firstly, you need to know what a ConcurrentModificationException is.
    Oracle provides a documentation for this class: http://docs.oracle.com/javase/7/docs/api/java/util/ConcurrentModificationException.html

    So, how do we fix this?

    1. The way FisheyLP suggested above (recommended).

    2. Iterate through a clone of that List. This way, you'll be modifying chestsFormat whilst the clone is being iterated, preventing a ConcurrentModificationException:
    Code:
           for (String s : new ArrayList<>(chestsFormat)) {
                String[] parts = s.split(" ");
             
                int x = Integer.parseInt(parts[0]);
                int y = Integer.parseInt(parts[1]);
                int z = Integer.parseInt(parts[2]);
             
                Location loc = new Location(world, x, y, z);
                Block block = loc.getBlock();
                if(block.getType() != Material.CHEST) {
                    chestsFormat.remove(s);
                    continue;
                }
                Chest chest = (Chest) block.getState();
             
                originalChests.add(chest);
            }
    
    3. Make another local List that contains all the Strings to remove.
    Code:
           List<String> chestFormatsToRemove = new ArrayList<>();
           for (String s : chestFormatsToRemove) {
                String[] parts = s.split(" ");
             
                int x = Integer.parseInt(parts[0]);
                int y = Integer.parseInt(parts[1]);
                int z = Integer.parseInt(parts[2]);
             
                Location loc = new Location(world, x, y, z);
                Block block = loc.getBlock();
                if(block.getType() != Material.CHEST) {
                    chestFormatsToRemove.add(s);
                    continue;
                }
                Chest chest = (Chest) block.getState();
             
                originalChests.add(chest);
            }
            for (String chestFormatToRemove : chestFormatsToRemove) chestFormats.remove(chestFormatToRemove);
    
    More information: http://www.javacodegeeks.com/2011/05/avoid-concurrentmodificationexception.html

    By the way, you should never use "!=" for any Object if you're checking for a difference in values.
    Here's why: http://perso.ensta-paristech.fr/~diam/java/online/notes-java/data/expressions/22compareobjects.html
    It should be: if (!chestsFormat.equals(Arenas.get().getStringList(ID + ".chests"))) {
    A faster way would just to have a boolean (local) called 'hasBeenModified', by default being false. If and when the List is modified, make 'hasBeenModified' true.
     
  4. Offline

    RainoBoy97

    Use an iterator :)
     
Thread Status:
Not open for further replies.

Share This Page