在逛 Stack Overflow 的时候,发现了一些访问量像昆仑山一样高的问题,比如说这个:为什么会发生 ArrayIndexOutOfBoundsException?这样看似简单到不值得一问的问题,访问量足足有 69万+,这不得了啊!说明有不少的初级程序员被这个问题困扰过。实话实说吧,我也有点吃不准为什么。

来回顾一下提问者的问题:

ArrayIndexOutOfBoundsException 究竟意味着什么?我该如何摆脱这个错误。

如果你也曾被这个问题困扰过,或者正在被困扰,就请随我一起来梳理一下问题的答案。打怪进阶喽!

来看这样一段代码,它就可以引起 ArrayIndexOutOfBoundsException

String[] names = { "沉", "默", "王", "二" };
for (int i = 0; i <= names.length; i++) {System.out.println(names[i]);
}

错误的堆栈信息如下所示。

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4at com.cmower.java_demo.stackoverflow.Cmower1.main(Cmower1.java:7)

抛出这个错误的原因是由于数组使用了非法的下标访问,比如说下标为负数或者大于或者等于数组的长度。

因为数组 names 的长度为 4,但下标的起始位置为 0,而不是 1,导致 names[4] 的时候越界了。这个问题的修正方法蛮简单的,就是把 <= 改为 <

String[] names = { "沉", "默", "王", "二" };
for (int i = 0; i < names.length; i++) {System.out.println(names[i]);
}

i 为 4 的时候要跳出 for 循环,names 的最大下标值为 3 而不是 4。

Java 的下标都是从 0 开始编号的(我不确定有没有从 1 开始的编程语言),这和我们平常生活中从 1 开始编号的习惯不同。Java 这样做的原因如下:

Java 是基于 C 语言实现的,而 C 语言的下标是从 0 开始的——这听起来好像是一句废话。真正的原因是下标并不是下标,在指针(C)语言中,它实际上是一个偏移量,距离开始位置的一个偏移量。第一个元素在开头,因此它的偏移量就为 0。
此外,还有另外一种说法。早期的计算机资源比较匮乏,0 作为起始下标相比较于 1 作为起始下标,编译的效率更高。

比如说,10 个元素的数组其结构如下图所示。编号从 0 开始,第 9 个元素将在下标 8 处访问。

为了摆脱 ArrayIndexOutOfBoundsException 的困扰,除了 i < 0; i < names.length;还有一种更值得推荐的做法——使用增强的 for 循环,当我们确定不需要使用下标的时候。

String[] names = { "沉", "默", "王", "二" };
for (String name : names) {System.out.println(name);
}

增强的 for 循环,彻底地甩掉了使用数组下标的可能性,也就彻底地摆脱了 ArrayIndexOutOfBoundsException。虽然这只是针对我们开发者来说。

实际上,Java 会把增强的 for 循环语句解释为普通的 for 循环语句,仍然会使用下标。

String[] names = new String[]{"沉", "默", "王", "二"};
String[] var2 = names;
int var3 = names.length;for(int var4 = 0; var4 < var3; ++var4) {String name = var2[var4];System.out.println(name);
}

下标 var4 的起始值为 0,var3 为数组的长度;当 var4 自增长为 4 的时候,发现 var4 不小于 var3,于是循环退出。

但不管怎么说,增强的 for 循环的确为我们开发者带来了福音——有效地摆脱了 ArrayIndexOutOfBoundsException

来对比一下普通的 for 循环和反编译后的增强 for 循环,看看它们之间有什么区别。

for (int i = 0; i < names.length; i++) {System.out.println(names[i]);
}int var3 = names.length;
for(int var4 = 0; var4 < var3; ++var4) {String name = var2[var4];System.out.println(name);
}

从性能的角度来看,差别主要有两点。

1)增强的 for 循环在遍历之前获取了数组的长度,并保存到了一个临时变量 var3 中,这就避免了每次循环的时候再去获取一次数组长度。

2)增强的 for 循环使用了前置自增 ++var4,而普通的 for 循环使用了后置自增 i++。这两者之间是有一定的差别的,感兴趣的同学可以了解一下。

如果使用的是 JDK8 以上的版本,我们还可以这样遍历数组(不使用下标)。

第一种:使用 List.forEach

Arrays.asList(names).forEach(System.out::println);

第二种:使用 Stream

Stream.of(names).forEach(System.out::println);

如果需要对数组执行其他操作,比如说过滤等操作,可以将数组转换为“流”。

这两种做法都需要用到 forEach() 方法,该方法其实是通过增强的 for 循环实现的,源码如下所示。

public void forEach(Consumer<? super E> action) {Objects.requireNonNull(action);for (E e : a) {action.accept(e);}
}

说到底,如果想要摆脱 ArrayIndexOutOfBoundsException 的困扰,使用增强的 for 循环来遍历数组就对了。把我们开发者容易疏忽的错误(比如 i <= names.length)交给智能化的编译器来处理,就是最好的办法。


好了各位读者朋友们,以上就是本文的全部内容了。能看到这里的都是人才,二哥必须要为你点个赞 。如果觉得不过瘾,还想看到更多,我再推荐几篇给大家。

Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
Stack Overflow 上 370万浏览量的一个问题:如何比较 Java 的字符串?
Stack Overflow 上 250万浏览量的一个问题:什么是 NullPointerException

养成好习惯!如果觉得这篇文章有点用的话,求点赞、求关注、求分享、求留言,这将是我写下去的最强动力!

alxc tool 报错数组超出了界限_Stack Overflow上59万浏览量的提问:为什么会发生数组越界?相关推荐

  1. alxc tool 报错数组超出了界限_代码审计之报错信息泄露与字符串截断

    机器在语言编码转换的时候,经常会出现各种各样的异常,这些神奇的字符串就有可能组合成一堆乱码出来,也有可能直接把程序搞崩溃掉,不过总有那么一些字符,可以帮助我们在利用漏洞的时候变得更简单一些,下面我们就 ...

  2. kafka tool报错:Error fetching datea.Offset out of range

    kafka tool报错 Error fetching datea.Offset out of range 解决方案: Kafka tool 升级最新2.0版本,没有此错误 转载于:https://w ...

  3. 关于nmonanalyser报错“输入超出文件尾”的解决方法

    关于nmonanalyser报错"输入超出文件尾"的解决方法   运行环境:nmonanalyserV4.7   原因分析:   这个是工具的VBA宏报错,原因是*.nmon文件中 ...

  4. 使用 Entity Framework Power Tool 报错 0×80070057 解决方法

    最近在使用  Entity Framework + oracle 过程实体生成不方便.于是就用了Entity Framework Power Tool 在SQLserver下没有问题 可以生成 但在o ...

  5. 迭代训练集,随机抽取batch_size数量的图片,报错索引超出范围index out of range

    在训练SRGAN模型时,训练到一半突然终止并报错索引越界,排查发现是在迭代dataloder时,构造数据集的函数中有这样一句: 这句的作用是按照排列好的顺序读取图片 ,打印index语句的时候,打印了 ...

  6. dpabi预处理报错——索引超出矩阵维度

     像是这种,一定要检查是不是重命名的时候存在空格! 红圈处,就是容易存在空格,需要在重新命名看一下. 另外,一定要多看看官网,如果预处理一直报错,建议先用官网的demo data演示一下,如果没问题, ...

  7. confluence正常安装网页报错_NAS折腾手记1:在OMV5上安装ZFS On Linux的正确步骤

    起因是直接安装OVMExtra里自带的zfs插件会报错,所以需要使用命令行来做一些前置准备. 源配置 有两种方法.1是安装OMVExtra并在内直接启用所有测试源 下载地址在此​omv-extras. ...

  8. Synergy报错 grabbed clipboard 和 disconnected 连接不上客户端

    Synergy报错 grabbed clipboard 1,Synergy报错,剪切板不可以,鼠标也不能转移 2,y50和founder挨才一起在可以 3,disconnected 连接不上客户端 1 ...

  9. 使用Ueditor 报错:请求后台配置项http错误,上传功能将不能正常使用

    一.背景 还是最近做的公众号,主题是做医学文章,那编辑的同事肯定要上传内容,laravel-admin常用的编辑器有三种 集成富文本编辑器wangEditor 集成富文本编辑器ckeditor 集成P ...

最新文章

  1. MySQL面试题 | 附答案解析(二十)
  2. AD域与外部网站域名相同处理办法
  3. Linux下Makefile学习笔记
  4. 浏览器接收响应数据过大_DOM总结:数据通信(HTTP协议和Ajax)
  5. EL表达式中,param和requestScope的区别
  6. 如何使用键盘快捷键在Mac上录制屏幕?
  7. 在 MATLAB 或 Python 中使用 ZOS-API 进行光线追跡的批次处理
  8. android cts问题分析,一则CTS测试错误分析
  9. isis学不到looback口的路由_光纤猫接D-Link无线路由器,怎么设置上网
  10. 软考之---软件设计师考试经验与笔记分享
  11. 银河麒麟高级服务器操作系统V10下载安装及安装docker
  12. 小白科研笔记:简析SOTA目标检测算法3D-CVF
  13. vsCode好用插件记录
  14. vscode 侧边栏源代码管理不见了
  15. Quartz 2D 涂鸦
  16. 单反相机的传奇—佳能单反50年辉煌之路(连载二)
  17. 铲屎官期盼已久的电影终于来啦!~
  18. cesium加载各类地图服务
  19. RTthread的FAL组件介绍
  20. c语言程序设计四边形计算,Just oj 2018 C语言程序设计竞赛(高级组)D: 四边形面积...

热门文章

  1. FPGA控制W5500完成UDP环回测试
  2. PostgreSQL问题解决--连接数过多
  3. 首例 3次IPO:前2次申请科创板、创业板均撤回、第3次改为主板、难圆其说变更保代及券商……
  4. 中国味精市场销售现状与十四五发展趋势分析报告2022-2028
  5. 感觉心上有一阵秋风吹过
  6. 计算机云的使用方法,云电脑教程:云电脑怎么用?
  7. Keycloak授权服务指南
  8. Power BI Echart Tree开发自定义可视化对象
  9. GO 语言中模板渲染的原理
  10. 要求: 编写一个程序,提示用户输入: 姓名 ,身份证号(需要一次输完,中间用逗号分隔)随后打印用户的星座。 提示:输入功能用C实现会很简单,其他语言的话,就不用输入姓名和逗号了,直接输入身份证号就