【问题标题】:Java - Index Out Of Bounds Exception: Index: 1, Size: 2Java - 索引超出范围异常:索引:1,大小:2
【发布时间】:2016-04-09 09:14:28
【问题描述】:

在处理一些 java 项目时,我遇到了这个奇怪的错误:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 2

怎么会有索引越界异常?索引 1 表示它试图获取第二个元素,大小 2 表示有 2 个元素,所以应该没有问题,不是吗?

上下文:

我有以下功能:

public int howManyAgents(){
    // cell is a class that can have 0 or multiple objects
    // I get a list of cells that contain at least 1 agent
    List<Cell> cellsWithAgents = getNonEmptyCells();

    // initializing a counter
    int agentsCount = 0;

    for(int i=0; i<cellsWithAgents.size(); i++){

        // For every cell in the list I add to the counter the number of       
        // agents that cell contains
        agentsCount += cellsWithAgents.get(i).howManyAgents();
    }
    return agentsCount;
}

现在,问题是我在该行遇到了一个空指针异常:

agentsCount += cellsWithAgents.get(i).howManyAgents();

我想调试代码,但是这个函数在程序运行时被多次调用,并且空指针异常出现在不同的时间点(1分钟后10秒后5分钟后)。所以我试图想出一种方法来在单元格为空时设置断点,所以我想出了这个代码:

public int howManyAgents(){
    // cell is a class that can have 0 or multiple objects
    // I get a list of cells that contain at least 1 agent
    List<Cell> cellsWithAgents = getNonEmptyCells();

    // initializing a counter
    int agentsCount = 0;

    for(int i=0; i<cellsWithAgents.size(); i++){

        int pass;
        if (null == cellsWithAgents.get(i))
            pass = 1; // breakpoint here

        // For every cell in the list I add to the counter the number of       
        // agents that cell contains
        agentsCount += cellsWithAgents.get(i).howManyAgents();
    }
    return agentsCount;
}

当然,这不是最好的方法。最合乎逻辑的方法是用 try/catch 包围代码并将断点放在那里。关键是上面的代码不起作用。它并没有在断点处停止,而是在该行将索引抛出边界异常:

if (null == cellsWithAgents.get(i))

为什么?如果索引显然在范围内,怎么可能抛出索引超出范围异常?

编辑:更改了复制代码的错误

更新: 我试图看看为什么空指针异常出现在 try/catch 中,并在那里放置了一个断点。似乎 cellsWithAgents 有时包含一个空值。这很可能是因为@rlinden 所说的并发性。

关于并发:有些单元格可以包含代理。可以在单元之间移动的代理数量不定。有一个特殊的代理试图计算有多少移动代理(使用此功能)。 因此,只有一个代理(线程)可以使用此功能,但多个代理可以修改单元格(从而弄乱 getNonEmptyCells() 和 howManyAgents() 结果)。

不过,如何使索引超出大小 2 和索引 1 的范围?由于并发性,这是不可能的,是吗?因为只有这个线程可以改变列表cellsWithAgents。因此,即使列表中的元素之一变为空,列表仍然包含该数量的指针,因此列表的大小无法更改。或者它可以以某种我想念的方式? 以及如何解释堆栈跟踪打印 Index:1 Size: 2?

【问题讨论】:

  • 在你放的那一行放断点是没用的。当您尝试访问不存在的 ith 索引时会发生错误。至于为什么会越界,我会继续寻找。
  • 为什么你的cellWithType之间的比较是空的?
  • 至于这个异常是如何发生的,我无法理解,但吸引我眼球的是:你迭代了 cellsWithAgents,但使用该索引来访问 CellsWithTypes。
  • 是的,这是复制代码时的错误。我已经修复它,它是相同的列表 cellsWithAgents。
  • @Arc676 起初我有一个空指针异常,这就是我尝试这样做的原因,但后来我得到了一个索引越界异常。就好像它以某种方式改变了一样。我现在真的不知道,这就是发生的事情。

标签: java nullpointerexception indexoutofboundsexception


【解决方案1】:

新思路

尝试更改循环,看看错误是否仍然存在:

int agentsCount = 0;
for(Cell cell : getNonEmptyCells()) {
    if(cell != null) {
       agentsCount += cell.howManyAgents();
    } else {
       System.out.println("Found a null cell");
    }
}

【讨论】:

  • 哦,该死的,我很抱歉。那是一个错误,我刚刚修复了它。它是相同的列表 cellsWithAgents
  • 所以错字出现在您的代码中(现在已修复)或问题中(您仍然有错误?)
  • 啊,你确定它的那个列表抛出了错误?在那条线上?可能不是 howManyAgents ()?
  • 它在问题中,我仍然有错误。好吧,堆栈跟踪准确地显示了这一行,所以我想是因为这里。无论如何 howManyAgents() 返回地图的大小,它不适用于索引。
  • 查看我的修改以更改循环,希望至少能解决您的问题(但不解释)
【解决方案2】:

我想查看getNonEmptyCells() 方法的代码。如果您的程序实际上是多线程的,并且此函数返回一个在每次交互时都会更改的固定 List,那么后续执行中的更改可能会影响之前未完成的执行。

这是因为cellsWithAgents = getNonEmptyCells(); 行没有创建副本,而是对getNonEmptyCells() 的返回值的引用。所以,如果这个方法重用了返回对象,那么第一次执行可能会认为有两个,但是伴随线程将内容大小更改为小于 2。

【讨论】:

  • 对,好像是并发的原因。谢谢你。我刚刚在代码块周围放了一个同步,没有更多的错误。很奇怪,Java 怎么会因为并发修改就抛出这么奇怪的错误。
  • 怪异是可以解释的。出于性能考虑,size() 方法仅在循环开始时调用。之后,循环假定它保持不变(在 2 处)。当您同时更改列表时,不会通知循环,因此会尝试查找列表中不再存在的元素。
  • 哦,好的。这就说得通了。非常感谢!
【解决方案3】:

问题是,程序在cellsWithType.get(i) 处抛出异常。您可以做的是在if (null == cellsWithType.get(i)) 处放置一个断点并尝试调试它。或者改成,

if (i >= cellsWithType.size())
        pass = 1; // breakpoint here

【讨论】:

  • 是的,这是复制代码时的错误。我已经修复它,它是相同的列表 cellsWithAgents。我很抱歉这个错误。
猜你喜欢
  • 1970-01-01
  • 2011-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-01
相关资源
最近更新 更多