为什么总是遇到索引越界?分析常见原因与预防措施。

吉云

今天又碰上这老朋友——索引越界。写代码时间长,这种错时不时就会跳出来烦你一下,虽然不是啥大问题,但排查起来有时候也挺磨人的。正好今天解决,就顺手记一笔。

是这么个事儿,我当时正在捣鼓一个数据列表,想从里面按顺序取点东西出来处理。思路挺简单的,就是写个循环,从头到尾过一遍,拿到数据再干别的。

开始动手

为什么总是遇到索引越界?分析常见原因与预防措施。

我就噼里啪把代码写好,大概就是弄个循环,用个变量 `i` 从 0 开始,每次加 1,然后用 `list[i]` 这种方式去拿列表里的数据。心里想着这不挺简单的嘛跑起来应该没啥问题。

结果一运行,程序“咣”一下就停,控制台报一堆红字,定睛一看,核心就是那个 `ArrayIndexOutOfBoundsException` 或者类似的提示,反正意思就是“索引超出边界”。说我用的那个 `i` ,数字不对,列表里没那么多东西。

排查过程

第一反应:是不是循环条件写错?比如列表里明明只有 5 个东西,我循环条件写成 `i < 6` 或者 `i <= 5` ,那肯定一个就越界。回去仔细检查循环的头和尾,`for (int i = 0; i < *(); i++)` 这样的,看着没毛病,`*()` 获取的大小是动态的,`i` 是从 0 到 `size() - 1`,正好是合法的索引范围。

第二反应:难道是哪个地方直接用个固定的数字去访问列表?比如代码某个角落写死 `list[10]`,但列表根本没那么长。全局搜一下,也没有发现这种硬编码的、可能出问题的索引。

有点懵:循环条件没错,直接访问的固定索引也没找到问题。那怪,怎么还会越界?

为什么总是遇到索引越界?分析常见原因与预防措施。

我就开始用最笨的办法,在循环前后,还有循环里面,加打印语句。把列表的大小 `*()` 打印出来看看,再把每次循环的索引 `i` 也打印出来。

找到原因

重新跑一遍,盯着控制台输出看。一开始都好好的,列表大小是 5,索引从 0 到 4 正常打印和访问。但是!在某个特定的操作之后,下一次循环开始前,我发现打印出来的 `*()` 居然变成 0!但是我的循环逻辑没停,它还是尝试去执行 `list[0]`,这列表都空,你上哪儿找第 0 个元素去?可不就报错嘛

原来问题出在,我在循环的过程中,或者说在处理某个特定数据的时候,有可能触发一个逻辑,把这个列表给清空,或者移除所有元素。但我后续的循环代码并没有考虑到这个列表可能变空的情况,还是傻乎乎地按原来的逻辑去访问,自然就撞墙。

解决办法

找到原因就好办。处理方法也直接:

为什么总是遇到索引越界?分析常见原因与预防措施。

  • 加判断: 在每次循环访问 `list[i]` 之前,加个判断。最简单的,判断一下列表是不是空的。if (*() > 0 && i < *()) { ...访问list[i]... } 这样,确保列表有东西,并且当前的 `i` 确实在范围内,才去访问。或者更干脆,在循环开始前就判断 `if (*()) { // 直接跳过或做其他处理 }`。
  • 调整逻辑: 更根本的是,审视一下为啥列表会被意外清空。如果那个清空操作是符合业务逻辑的,那就在清空后,确保后续的访问逻辑能正确处理空列表的情况,比如直接结束循环。

我选第一种,加个判断,简单有效。再跑,程序就顺利跑完,没再报错。

一点想法

为什么总是遇到索引越界?分析常见原因与预防措施。

说到底,这“索引越界”多数时候还是自己代码逻辑不够严谨造成的。特别是处理动态数据、列表长度会变化的情况,一定要多考虑边界条件,比如列表为空、列表只有一个元素等等这些特殊情况。写代码的时候稍微多想一步,加个判断,就能省下后面不少排查问题的时间。这回也算又给自己提个醒。

免责声明:由于无法甄别是否为投稿用户创作以及文章的准确性,本站尊重并保护知识产权,根据《信息网络传播权保护条例》,如我们转载的作品侵犯了您的权利,请您通知我们,请将本侵权页面网址发送邮件到qingge@88.com,深感抱歉,我们会做删除处理。

目录[+]