Stack Overflow上59万浏览量的提问:为什么会发生ArrayIndexOutOfBoundsException?
在逛 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: 4
at 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上59万浏览量的提问:为什么会发生ArrayIndexOutOfBoundsException?的更多相关文章
- [转帖]Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?
Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递? http://www.itpub.net/2019/12/03/4567/ 在逛 Stack Overfl ...
- Stack Overflow 上 370万浏览量的一个问题:如何比较 Java 的字符串?
在逛 Stack Overflow 的时候,发现了一些访问量像喜马拉雅山一样高的问题,比如说这个:如何比较 Java 的字符串?访问量足足有 370万+,这不得了啊!说明有很多很多的程序员被这个问题困 ...
- 关于Stack Overflow上ASP.NET最大连接数限制提问的一个思考
原文地址:Why request queuing is high even when request executing is below its limit? We are using below ...
- 为什么开发者热衷在Stack Overflow上查阅API文档?
摘要:一项新研究跟踪了Android开发者的访问历史,发现开发者多达二分之一的文档是从Stack Overflow上获取到的,而Stack Overflow上的示例也多于官方指南,开发者通过搜索更多时 ...
- Stack Overflow 上排名前十的与API相关的问题
Stack Overflow是一个庞大的编程知识仓库,在Stack Overflow 上,数百万的提问被回答,并且这些回答都是高质量的.这就是为什么在Google搜索结果的排行榜上,Stack Ove ...
- Stack Overflow上关于Java Collections的几个常见问题
下面列出Stack Overflow上最常见的几个关于Java Collections的问题并给出答案. 1. 什么时候用LinkedList,什么时候用ArrayList? ArrayList是使用 ...
- JavaScript超越了Java,c,python等等成为Stack Overflow上最热门的
JavaScript超越了Java,c,python等等成为Stack Overflow上最热门的标签 在2015年6月至今,JavaScript超越了Java,c,python等等成为Stack O ...
- Stack Overflow 上 250W 浏览量的一个问题:你对象丢了
在逛 Stack Overflow 的时候,发现最火的问题竟然是:什么是 NullPointerException(java.lang.NullPointerException),它是由什么原因导致的 ...
- Stack Overflow 上人气最旺的 10 个 Java 问题
1. 为什么两个(1927年)时间相减得到一个奇怪的结果? (3623个赞) 如果执行下面的程序,程序解析两个间隔1秒的日期字符串并比较: public static void main(String ...
随机推荐
- [2018-06-28] 创建第一个django项目
1.创建一个名称为tmpl的项目 django-admin.py startproject tmpl 2.进入刚刚创建的tmpl目录 cd tmpl 3.创建一个名称为learn的应用 python ...
- numpy.array 合并和分割
# 导包 import numpy as np numpy.array 的合并 .concatenate() 一维数组 x = np.array([1, 2, 3]) # array([1, 2, 3 ...
- CSPS模拟 98
T1 待改 T2 这道题的爆炸充分说明我最近已经颓到一定境界了 考虑到总步数不可能超过n 直接枚举总步数,那么任意时刻对末态的影响就是确定的 T3 两遍最短路,一遍从-1的限制考虑求出允许的最早时间, ...
- CSPS模拟 57
rank4大众rank T1 天空龙 让他自由翱翔吧 T2 巨神兵 对于n=10的测试点本可以打出非常优秀的分层状压 但是没有打出来,因为对拓扑图理解不够深刻,纠结于指回的边,实际上只关注伸出的边就可 ...
- 在vue中如何使用axios
1.前言 在Vue1.0的时候有一个官方推荐的 ajax 插件 vue-resource,但是自从 Vue 更新到 2.0 之后,官方就不再更新 vue-resource. 关于为什么放弃推荐? -& ...
- 『题解』洛谷P4016 负载平衡问题
title: categories: tags: - mathjax: true --- Problem Portal Portal1:Luogu Portal2: LibreOJ Descripti ...
- pip的简单用法
pip的用法: 其实跟linux的yum很像,它可以帮我们安装python所需要的环境包,并且可以包解决依赖关系 eg: 列出已安装的包 pip list 安装要安装的包 pip install xx ...
- Python 面向对象之五 基础拾遗
Python 面向对象之五 基础拾遗 今天呢,就剩下的面向对象的相关知识进行学习,主要会学习以下几个方面的知识:1.上下文管理协议,2.为类加装饰器 3.元类 一.上下文管理协议 在学习文件操作的时候 ...
- Tomcat开启关闭常见问题
启动 bin/startup.bat ,双击运行该文件即可 访问:浏览器输入: http://localhost:8080 回车访问自己 http://别人的ip:8080 访问别人 可能出现的问题: ...
- My First Cloud Application's Design
Structure Diagram as following: Questions list: 1. Skydrive Integration > Based on the MSDN commu ...