【问题标题】:Any easy way to deal with ConcurrentModificationException in this java game?在这个 java 游戏中处理 ConcurrentModificationException 的任何简单方法?
【发布时间】:2015-02-06 07:52:14
【问题描述】:

我试图用 Java 构建一个简单的 Rock-Paper-Scissors 游戏。基本上,这个想法是当玩家做出错误的举动时会被淘汰。剩下的最后一名玩家是获胜者。 我比较缺乏经验,也不太了解。我在运行时遇到了这个 ConcurrentModification 异常。我试着谷歌了一下,但没有得到任何简单的解决方法。有一些关于迭代器之类的讨论,我不太了解/理解。

我试过如下-

GameStarter 类:

public class GameStarter
{
    public static void main(String[] args)
    {

    RPS g = new RPS();
    g.play();
    }
}

RPS 类:

import java.util.ArrayList;
public class RPS
{
   Player p1 = new Player(" A ");
   Player p2 = new Player(" B ");
   Player p3 = new Player(" C ");
   Player p4 = new Player(" D ");
   Player p5 = new Player(" E ");
   ArrayList<Integer> hold =new ArrayList<Integer>();
   ArrayList<Player> active = new ArrayList<Player>();
   {
    active.add(p1);
    active.add(p2);
    active.add(p3);
    active.add(p4);
    active.add(p5);
        }
   public void play()
   {
    int i,j;
    while(active.size()>1)
    {

     for(Player p:active)
    {
    System.out.print("\n Currently active players are: "+p.name+" , ");
    }   
    System.out.println("\n\n");
    for(Player p:active)
    {
    p.rpsThrow();
    hold.add(p.cur);
    }

    if(hold.contains(1) && hold.contains(2) && !hold.contains(3))
    {
    for(Player p: active)
    {
        if(p.cur==1)
        {
        active.remove(p);
        System.out.println("Player "+p.name+" eliminated ");
        }
    }

    }
    if(hold.contains(1) && !hold.contains(2) && hold.contains(3))
    {
    for(Player p: active)
    {
    if(p.cur==3)
        {
        active.remove(p);
        System.out.println("Player "+p.name+" eliminated ");
        }        
    }

    }
    if(!hold.contains(1) && hold.contains(2) && hold.contains(3))
    {
    for(Player p: active)
    {
        if(p.cur==2)
        {
        active.remove(p);
        System.out.println("Player "+p.name+" eliminated ");
        }
    }

    }

    hold.clear();
    try
    {
    Thread.sleep(3500);
    }
    catch(Exception ex)
    {

    }
}
if(active.size()==1)
{
for(Player p:active)
{
System.out.println("\n\n The winner is : \n"+p.name);
}
}


    }
}

和播放器类:

public class Player
{
  String name;
  Integer cur;

  public Player(String n)
  {
    name=n;
   }
   public int rpsThrow()
   {
    int t;
    t=(int)((Math.random()*3)+1);
    cur=t;
    if(t==1)
    {
        System.out.println("\n"+name+" throws : rock");
    }
    else if(t==2)
    {
        System.out.println("\n"+name+" throws : paper");
    }
    else
    {
        System.out.println("\n"+name+" throws : scissors");
    }
    return t;    
    }
}

没有任何简单的方法可以解决这个 CMException 吗?请随时修改我的代码来解决它。

【问题讨论】:

  • 你能发布错误吗?堆栈跟踪?
  • 如何发布堆栈跟踪?

标签: java arraylist bluej concurrentmodification


【解决方案1】:

基本上,一旦您开始在 Collection 上使用迭代器(并且这种类型的 for 循环使用迭代器),在完成迭代器之前,您无法修改底层集合,否则您将获得 CME。如果要从集合中删除项目,则需要使用显式迭代器并使用其 remove() 方法,如下所示:

public static void main(String[] args) throws Exception {
    List<String> vals = new ArrayList<>();
    vals.add("1"); vals.add("2"); vals.add("3");

    // This throws a CME
    for(String s: vals) {
        if("1".equals(s)) {
            vals.remove(s);
        }
    }

    // This would work
    for(Iterator i = vals.iterator(); i.hasNext(); ) {
        if("1".equals(i.next())) {
            i.remove();
        }
    }
}

【讨论】:

  • 我明白了。 “(并且这种类型的 for 循环使用迭代器)”。如果我将其更改为正常的 for 循环,它会起作用吗?
  • 您可以将其更改为“for(int i = 0; i
【解决方案2】:

我把 RPS 类改成了这个(正常的):

package RockPaperScissors;
import java.util.ArrayList;
public class RPS
{
   Player p1 = new Player(" A ");
   Player p2 = new Player(" B ");
   Player p3 = new Player(" C ");
   Player p4 = new Player(" D ");
   Player p5 = new Player(" E ");
   ArrayList<Integer> hold =new ArrayList<Integer>();
   ArrayList<Player> active = new ArrayList<Player>();
   {
    active.add(p1);
    active.add(p2);
    active.add(p3);
    active.add(p4);
    active.add(p5);
        }
   public void play()
   {
    int i,j;
    Player p;
    while(active.size()>1)
    {

     for(i=0;i<active.size();i++)
    {
      p=  active.get(i);
    System.out.print("\n Currently active players are: "+p.name+" , ");
    }   
    System.out.println("\n\n");
    for(i=0;i<active.size();i++)
    {
      p=  active.get(i);  
    p.rpsThrow();
    hold.add(p.cur);
    }

    if(hold.contains(1) && hold.contains(2) && !hold.contains(3))
    {
    for(i=0;i<active.size();i++)
    {
        p=  active.get(i);  
        if(p.cur==1)
        {
        active.remove(p);
        System.out.println("Player "+p.name+" eliminated ");
        }
    }

    }
    if(hold.contains(1) && !hold.contains(2) && hold.contains(3))
    {
    for(i=0;i<active.size();i++)
    {
        p=  active.get(i);  
    if(p.cur==3)
        {
        active.remove(p);
        System.out.println("Player "+p.name+" eliminated ");
        }        
    }

    }
    if(!hold.contains(1) && hold.contains(2) && hold.contains(3))
    {
     for(i=0;i<active.size();i++)
    {
        p=  active.get(i);  
        if(p.cur==2)
        {
        active.remove(p);
        System.out.println("Player "+p.name+" eliminated ");
        }
    }

    }

    hold.clear();
    try
    {
    Thread.sleep(3500);
    }
    catch(Exception ex)
    {

    }
}
if(active.size()==1)
{
for(i=0;i<active.size();i++)
{
p=  active.get(i);  
System.out.println("\n\n The winner is : \n"+p.name);
}
}


    }
}

RPE 不再存在。虽然我必须说它的行为并不像我期望的那样。 我还将尝试研究和研究迭代器。感谢你的帮助。 编辑:更改了正常的索引。现在它可以像我想要的那样工作了。

package RockPaperScissors;
import java.util.ArrayList;
public class RPS
{
   Player p1 = new Player(" A ");
   Player p2 = new Player(" B ");
   Player p3 = new Player(" C ");
   Player p4 = new Player(" D ");
   Player p5 = new Player(" E ");
   ArrayList<Integer> hold =new ArrayList<Integer>();
   ArrayList<Player> active = new ArrayList<Player>();
   {
    active.add(p1);
    active.add(p2);
    active.add(p3);
    active.add(p4);
    active.add(p5);
        }
   public void play()
   {
    int i,j;
    Player p;
    while(active.size()>1)
    {

     for(i=0;i<active.size();i++)
    {
      p=  active.get(i);
    System.out.print("\n Currently active players are: "+p.name+" , ");
    }   
    System.out.println("\n\n");
    for(i=0;i<active.size();i++)
    {
      p=  active.get(i);  
    p.rpsThrow();
    hold.add(p.cur);
    }

    if(hold.contains(1) && hold.contains(2) && !hold.contains(3))
    {
    for(i=0;i<active.size();i++)
    {
        p=  active.get(i);  
        if(p.cur==1)
        {
        active.remove(p);
        **i=i-1;**
        System.out.println("Player "+p.name+" eliminated ");
        }
    }

    }
    if(hold.contains(1) && !hold.contains(2) && hold.contains(3))
    {
    for(i=0;i<active.size();i++)
    {
        p=  active.get(i);  
    if(p.cur==3)
        {
        active.remove(p);
        i=i-1;
        System.out.println("Player "+p.name+" eliminated ");
        }        
    }

    }
    if(!hold.contains(1) && hold.contains(2) && hold.contains(3))
    {
     for(i=0;i<active.size();i++)
    {
        p=  active.get(i);  
        if(p.cur==2)
        {
        active.remove(p);
        i=i-1;
        System.out.println("Player "+p.name+" eliminated ");
        }
    }

    }

    hold.clear();
    try
    {
    Thread.sleep(3500);
    }
    catch(Exception ex)
    {

    }
}
if(active.size()==1)
{
for(i=0;i<active.size();i++)
{
p=  active.get(i);  
System.out.println("\n\n The winner is : \n"+p.name);
}
}


    }
}

【讨论】:

    【解决方案3】:

    将循环的活跃玩家更改为Iterator

    【讨论】:

      【解决方案4】:

      这段代码有问题:-

      for(Player p: active)
      {
          if(p.cur==2)
          {
          active.remove(p);
          System.out.println("Player "+p.name+" eliminated ");
          }
      }
      

      您正在对活动列表进行迭代并从中删除元素。

      您需要使用迭代器并从迭代器中删除数据,它将自动从实际列表中删除。

        for(Iterator playerIterator = active.iterator(); playerIterator.hasNext();) {
         Player p = (Player)playerIterator.next();
         if(p.cur==2){
          playerIterator.remove();
         System.out.println("Player "+p.name+" eliminated ");
        }
       }
      

      【讨论】:

      • 迭代器没有remove(T) 方法。它确实有一个remove 方法。
      【解决方案5】:

      在您的循环中使用iterator,您可以在其中修改您当前迭代的集合

      for(Iterator iter = active.iterator(); iter.hasNext();)
      {
          Player p = (Player)iter.next();
          if(p.cur==1)
          {
          iter.remove();
          System.out.println("Player "+p.name+" eliminated ");
          }
      }
      

      【讨论】:

      • 究竟什么是迭代器?我还没有那么远。没有什么可以帮上忙的吗?
      • 这里是关于它们的documentationsome examples and info
      • @PredragMaric 此代码将再次出现相同的错误,因为您仍在激活时调用 remove,您需要在迭代器上调用它
      • @user3177843 迭代器是 java 中提供的一种迭代集合的方法。它的优点是您可以修改迭代器而不会出现并发错误,并且您的列表将被更新
      • 迭代器没有remove(E)方法
      猜你喜欢
      • 1970-01-01
      • 2015-05-17
      • 1970-01-01
      • 2015-10-16
      • 2013-01-01
      • 2012-10-07
      • 1970-01-01
      • 2016-02-16
      • 1970-01-01
      相关资源
      最近更新 更多