Java 带有 ArrayList 的 ConcurrentModificationException
Java ConcurrentModificationException with an ArrayList
我正在使用 Java 创建在线视频游戏。
如果有一个客户端和一个服务器应用程序。
在服务器中,为了处理玩家数据库,我创建了一个名为 inGamePlayers 的 ArrayList,其中包含 Players 对象(具有 InetAdress ipAdress 和 String 用户名)。
当玩家连接时,它首先检查连接的玩家用户名是否== ArrayList 用户名中的玩家之一。如果不是,则将他添加到列表中。否则,连接玩家被认为是 'reconnected'...
当它在 Eclipse 上运行时,它运行起来很奇怪。所以我决定把我的一部分代码作为测试放在 "Java Tutor" 中(这是一个读取你的代码并向你展示变量的网站,当你开始编程时非常方便)。
第一个
for (Player p : inGamePlayers) {
行,它停下来说java.util.ConcurrentModificationException
,不是第一次,而是第二次经过。
这是我的全部测试代码
import java.util.ArrayList;
public class YourClassNameHere {
public static void main(String[] args) {
ArrayList<Player> inGamePlayers = new ArrayList<Player>();
inGamePlayers.add(new Player("Griff"));
String newUsername = "Polak";
for (Player p : inGamePlayers) {
if (newUsername == p.username) {
System.out.println(p.username+" reconnected!");
break;
}
inGamePlayers.add(new Player(newUsername));
}
for (Player p : inGamePlayers) {
System.out.println(p.username);
}
}
}
class Player {
public String username;
public Player(String username) {
this.username = username;
}
}
此代码有多个缺陷。在这种形式中,它将添加新的 Player 实例,直到找到具有匹配名称的条目。如您所见,开始迭代、修改列表并继续迭代将抛出 ConcurrentModificationException
。此外,您将字符串与 ==
而不是 equals
.
进行比较
for (Player p : inGamePlayers) {
if (newUsername == p.username) { // This needs to be .equals
System.out.println(p.username+" reconnected!");
break;
}
// this line runs many times
inGamePlayers.add(new Player(newUsername));
}
相反,我建议您将该代码提取到一个新函数中,并更改控制流:
private static void handleConnected(ArrayList<Player> inGamePlayers, String newUsername) {
for (Player p : inGamePlayers) {
if (newUsername.equals(p.username)) {
System.out.println(p.username+" reconnected!");
return; // return instead of break
}
}
// we did not return, so this user is new
inGamePlayers.add(new Player(newUsername));
}
// ...
public static void main(String[] args) {
ArrayList<Player> inGamePlayers = new ArrayList<Player>();
inGamePlayers.add(new Player("Griff"));
String newUsername = "Polak";
// Call this function in place of the old loop
handleConnected(inGamePlayers, newUsername);
for (Player p : inGamePlayers) {
System.out.println(p.username);
}
}
我正在使用 Java 创建在线视频游戏。 如果有一个客户端和一个服务器应用程序。 在服务器中,为了处理玩家数据库,我创建了一个名为 inGamePlayers 的 ArrayList,其中包含 Players 对象(具有 InetAdress ipAdress 和 String 用户名)。
当玩家连接时,它首先检查连接的玩家用户名是否== ArrayList 用户名中的玩家之一。如果不是,则将他添加到列表中。否则,连接玩家被认为是 'reconnected'...
当它在 Eclipse 上运行时,它运行起来很奇怪。所以我决定把我的一部分代码作为测试放在 "Java Tutor" 中(这是一个读取你的代码并向你展示变量的网站,当你开始编程时非常方便)。
第一个
for (Player p : inGamePlayers) {
行,它停下来说java.util.ConcurrentModificationException
,不是第一次,而是第二次经过。
这是我的全部测试代码
import java.util.ArrayList;
public class YourClassNameHere {
public static void main(String[] args) {
ArrayList<Player> inGamePlayers = new ArrayList<Player>();
inGamePlayers.add(new Player("Griff"));
String newUsername = "Polak";
for (Player p : inGamePlayers) {
if (newUsername == p.username) {
System.out.println(p.username+" reconnected!");
break;
}
inGamePlayers.add(new Player(newUsername));
}
for (Player p : inGamePlayers) {
System.out.println(p.username);
}
}
}
class Player {
public String username;
public Player(String username) {
this.username = username;
}
}
此代码有多个缺陷。在这种形式中,它将添加新的 Player 实例,直到找到具有匹配名称的条目。如您所见,开始迭代、修改列表并继续迭代将抛出 ConcurrentModificationException
。此外,您将字符串与 ==
而不是 equals
.
for (Player p : inGamePlayers) {
if (newUsername == p.username) { // This needs to be .equals
System.out.println(p.username+" reconnected!");
break;
}
// this line runs many times
inGamePlayers.add(new Player(newUsername));
}
相反,我建议您将该代码提取到一个新函数中,并更改控制流:
private static void handleConnected(ArrayList<Player> inGamePlayers, String newUsername) {
for (Player p : inGamePlayers) {
if (newUsername.equals(p.username)) {
System.out.println(p.username+" reconnected!");
return; // return instead of break
}
}
// we did not return, so this user is new
inGamePlayers.add(new Player(newUsername));
}
// ...
public static void main(String[] args) {
ArrayList<Player> inGamePlayers = new ArrayList<Player>();
inGamePlayers.add(new Player("Griff"));
String newUsername = "Polak";
// Call this function in place of the old loop
handleConnected(inGamePlayers, newUsername);
for (Player p : inGamePlayers) {
System.out.println(p.username);
}
}