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

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

原文地址:https://www.cnblogs.com/qing-gee/p/12000765.html

时间: 2024-08-15 00:29:24

Stack Overflow上59万浏览量的提问:为什么会发生ArrayIndexOutOfBoundsException?的相关文章

关于Stack Overflow上ASP.NET最大连接数限制提问的一个思考

原文地址:Why request queuing is high even when request executing is below its limit? We are using below settings Target Framework : .Net 3.5 Framework Application Pool :.Net Framework v2.0.50727 with Managed pipeline mode – Integrated And, no of CPU is 8

为什么开发者热衷在Stack Overflow上查阅API文档?

摘要:一项新研究跟踪了Android开发者的访问历史,发现开发者多达二分之一的文档是从Stack Overflow上获取到的,而Stack Overflow上的示例也多于官方指南,开发者通过搜索更多时候是去访问Stack Overflow上的问题讨论而不是访问官方文档.那么,为什么开发者热衷在Stack Overflow上查看API文档呢? 微软等软件公司为API.服务和软件平台等主题创建数以百万计的文档,创建软件文档费时费力,然而却越来越不讨好,因为软件开发者对这些枯燥的文字日益失去兴趣.如果

Stack Overflow 上排名前十的与API相关的问题

Stack Overflow是一个庞大的编程知识仓库,在Stack Overflow 上,数百万的提问被回答,并且这些回答都是高质量的.这就是为什么在Google搜索结果的排行榜上,Stack Overflow 总是位居首位. 虽然Stack Overflow上有非常多的提问,但是仍然每天都有大量的问题被提出,其中的很多都等待解答或者没有得到好的解答.因此,问题是如何找到答案的,通过Stack Overflow是不够的. 随着成千上万的开发者使用Java的API并且在Github上分享他们的项目

Stack Overflow 上人气最旺的 10 个 Java 问题

1. 为什么两个(1927年)时间相减得到一个奇怪的结果? (3623个赞) 如果执行下面的程序,程序解析两个间隔1秒的日期字符串并比较: public static void main(String[] args) throws ParseException { SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String str3 = "1927-12-31 23:54:07"

我30天在Stack Overflow问答网站上回答问题的感受

想法的萌芽 如果非要总结下我多年来是如何使用Stack Overflow的话,我的答案就是:打开网页,搜索问题,查看Stack Overflow的搜索结果,参考答案,最后再关掉网页. 我的生活已经离不开Stack Overflow了.但我从来没有对那些有用的回答做出过反馈,更别提自己提问题和回答问题了. 不过我最终还是意识到,Stack Overflow的成功正是建立在其众多用户的慷慨解答上.我从这个网站上收获了很多,却从未做出回报,因为没有任何人.任何规则的约束.每个问题.每个答案或者每个有帮

玩转 Stack Overflow 之提问篇

Stack Overflow是世界上最大的编程类问答网站, 大多数程序员或多或少和它有所接触: 即使你从来没有在它上面提问或回答过, 别忘了, 在搜索很多技术问题的时候, 结果的第一页往往就有几条链接到Stack Overflow的问题. 很 多人对于Stack Overflow的第一印象是: 很多编程问题都能在上面找到专业的答案, 太牛了. 但当问题没有找到合适答案, 而去上面提新问题的时候, 可能有人会发现自己的问题被残忍的 downvote,甚至被关闭.最后被删除.更有甚者, 发现自己被禁

【Stack Overflow -- 原创加工、原创整理、生产实战】-- 深度复制

一.说明 1.本程序的核心代码不是我原创的,是我在Stack Overflow上搜集后加工出来的,原作者已忘记了~ 2.这段程序是我在上海携程(2014年左右)上班时整理并在生产环境应用的,先后经历了三家公司项目中使用,稳定可靠,放心使用 3.扩展方法部分可根据自己实际需要修改,流可以搞个static,pool,也可以每次 new,根据项目性能需求自己定制就行了 二.代码 代码如下: 核心类  NonSerialiazableTypeSurrogateSelector : 1 /// <summ

(转)Stack Overflow 2016最新架构探秘

这篇文章主要揭秘 Stack Overflow 截止到 2016 年的技术架构. 首先给出一个直观的数据,让大家有个初步的印象. 相比于 2013 年 11 月,Stack Overflow 在 2016 年 02 月统计数据有较大变化,下面给出 2016 年 02 月 09 号一天的数据,如下: HTTP 请求数 209,420,973 (+61,336,090) 网页加载次数 66,294,789 (+30,199,477) HTTP 流量发送有1,240,266,346,053 (+406

Stack Overflow 2016最新架构探秘

这篇文章主要揭秘 Stack Overflow 截止到 2016 年的技术架构. 首先给出一个直观的数据,让大家有个初步的印象. 相比于 2013 年 11 月,Stack Overflow 在 2016 年 02 月统计数据有较大变化,下面给出 2016 年 02 月 09 号一天的数据,如下: HTTP 请求数 209,420,973 (+61,336,090) 网页加载次数 66,294,789 (+30,199,477) HTTP 流量发送有1,240,266,346,053 (+406