【问题标题】:Weird error with an ArrayList in for-loopfor循环中ArrayList的奇怪错误
【发布时间】:2014-02-28 21:00:42
【问题描述】:

我有一个很奇怪的问题,这个问题只在案例 3 和 4 中出现。

                for(Sector sector : sectoren)
    {
        switch(sector.getCode())
        {
            case 1:
                for(int i = 0; i<3; i++)
                {
                    for(int j=0;j<3; j++)
                    {
                        Gebiedskaart gbk = gebiedskaarten.get(r.nextInt(gebiedskaarten.size()));
                        vakken[i][j].setGbk(gbk);
                        gebiedskaarten.remove(gbk);
                    }
                vakken[2][2].setGbk(null);
                }
            case 2:
                for(int i = 0; i<3; i++)
                {
                    for(int j=4;j<7; j++)
                    {
                        Gebiedskaart gbk = gebiedskaarten.get(r.nextInt(gebiedskaarten.size()));
                        vakken[i][j].setGbk(gbk);
                        gebiedskaarten.remove(gbk);
                    }
                }
                vakken[2][4].setGbk(null);
            case 3:
                for(int i=4; i<7; i++)
                {
                    for(int j=0;j<3; j++)
                    {
                        System.out.println(gebiedskaarten.size());
                        Gebiedskaart gbk = gebiedskaarten.get(r.nextInt(gebiedskaarten.size()));
                        vakken[i][j].setGbk(gbk);
                        gebiedskaarten.remove(gbk);
                    }
                }
                vakken[4][2].setGbk(null);
           case 4:
                for(int i = 4; i<7; i++)
                {
                    for(int j=4;j<7; j++)
                    {
                        Gebiedskaart gbk = gebiedskaarten.get(r.nextInt(gebiedskaarten.size()));
                        vakken[i][j].setGbk(gbk);
                        //gebiedskaarten.remove(gbk); doet iets raar? moeten we nog naar kijken, hij blijft gewoon verwijderen tot de lijst leeg is
                    }
                }
                vakken[4][4].setGbk(null);
        }
    }

在代码中,您可以看到我为数组分配了一个值,然后我从 ArrayList 中删除了该值。你可以看到我已经把 System.out.println 放在那里,看看它做了什么,这是输出:

34
33
32
31
30
29
28
27
26
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0

然后错误很明显:

Exception in thread "main" java.lang.IllegalArgumentException: n must be positive
    at java.util.Random.nextInt(Random.java:300)
    at domein.Spelbord.wijsGebiedskaartenToe(Spelbord.java:123)
    at domein.Spelbord.<init>(Spelbord.java:19)
    at domein.Spel.setWereldkaart(Spel.java:18)
    at domein.DomeinController.maakWereldkaart(DomeinController.java:39)
    at ui.Uc1.maakWereldkaart(Uc1.java:42)
    at ui.ConsoleApplicatie.behandelUc1(ConsoleApplicatie.java:67)
    at ui.ConsoleApplicatie.startSpel(ConsoleApplicatie.java:29)
    at StartUp.main(StartUp.java:12)
Java Result: 1

我不知道发生了什么,也许你们知道?

【问题讨论】:

  • 您的循环似乎只运行了 9 (3 * 3) 次,它怎么能打印出这么多?
  • 循环的内部运行了 9 次,删除了 9 个元素 (35 -> 26)。所以剩下的输出(从 16 开始)是一些其他代码的结果。为了尽快获得更好的帮助,请尝试提供complete example
  • 您最后一次打印输出的gebiedskaarten.size()0,当传递给r.nextInt() 时,它将传递一个非正数(0)到Random#nextInt,因此java.util.Random.nextInt 中发生的错误(查看您的堆栈跟踪)。
  • 这仍然不是可编译代码,要真正 100% 评估您的问题,我们需要更多代码...(但绝对不是您的所有代码!)但是我也相信有了Random#nextInt 上的当前答案,您就有足够的材料开始让它发挥作用。
  • 问题是我忘记了break语句

标签: java arraylist switch-statement


【解决方案1】:

因为你这样做了:

 r.nextInt(gebiedskaarten.size());

gebiedskaarten.size() == 0

==> 你尝试得到一个从 0 到 0 的随机数 ==> 异常

更新:您似乎也忘记了 switch-case 中的 break; 语句!我猜你想成为你的代码逻辑是这样的:

 switch(sector.getCode()) {
 case 1: /*do something*/ break;
 case 2: /*do something else */ break;
 //...
 default: //do some default action
 }

另见相关问题:Why do we need break after case statements?

【讨论】:

  • 是的,但它不应该是 0
  • @stijn26 啊!您是否忘记了 switch-case 中的 break; 语句?
  • 这是错误,天哪,我不敢相信我忘记了 break 语句,现在一切正常。现在该睡觉了,我想不清楚!
【解决方案2】:

您正在调用 Random.nextInt(),值为 0,这是不受支持的。

正如您从System.out 的输出中看到的那样,数组的大小最终为0,并且您将数组的大小传递给nextInt()

另见http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt(int)

【讨论】:

  • 是的,但它不应该是 0
  • 那是一个不同的问题 - 我看到你更新了你的代码,但我认为它现在包含太多不相关的代码 - 你可以进一步缩小它,以便它包含重现所需的最少代码问题(请参阅sscce.org 以获得一些好读物)?最后,问题肯定是您过于频繁地调用remove,因此最终大小为0 - 请注意@donfuxx 关于缺少breaks 的评论!
【解决方案3】:

我不知道为什么您的循环运行了这么多次,而预期只有 9 (3 * 3) 次,但假设您发布的代码从 gebiedskaarten.size() == 9 开始,它会执行 9 次迭代:

  • System.out.println(gebiedskaarten.size())
    • 打印当前尺寸。
  • Gebiedskaart gbk = gebiedskaarten.get(r.nextInt(gebiedskaarten.size()))
    • 首先执行r.nextInt(...)gebiedskaarten.size(),获得一个新的随机值。
    • 然后使用该随机数调用gebiedskaarten.get(...),并将其分配给gbk
  • vakken[i][j].setGbk(gbk);
    • vakkeni, j 条目上调用setGbk(gbk)
  • gebiedskaarten.remove(gbk);
    • gebiedskaarten 集合中删除gbk,将大小减小一。

哪里出错了,是某个点,gebiedskaarten.size() 变成了0,然后你尝试通过r.nextInt(...)0 上获得一个新的随机数,这是不可能的,因为它需要严格积极的。
但是请注意,调用 gebiedskaarten.get(0) 是有效的,因此您会遇到一次性错误。

我还强烈建议您从荷兰语命名约定转变为英语命名约定,因为这将对您的职业未来和在线发布问题有很大帮助。

另外,为了完整起见,正如@donfuxx 所指出的,您的switch 语句不符合标准,这在99% 的情况下会导致错误,应该是这样的:

switch (variable) {
    case 1:
        //do interesting things
        break;
    case 2:
        //do interesting things
        break;
    case 3:
        //do interesting things
        break;
    default:
        //either allowable base case, or may-not-happen error case
        break;

如您所见,我在每个case 的末尾添加了一个break,这是防止它通过语句的必要条件。如果case 1 的末尾没有break,那么case 2被执行。

【讨论】:

  • 是的,我同意您在代码中只应使用英文名称
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-05
  • 1970-01-01
  • 1970-01-01
  • 2017-02-11
  • 2019-02-11
  • 2019-04-30
相关资源
最近更新 更多