Kotlin刨根问底(二):for循环引起的一起“血案”(上)

简介: 本文灵感来源于:群友遍历列表时remove元素引发异常,后对for循环的实现原理进行一系列的探究~

0x0、要点提炼


  • 普通for循环」类似代码,Java不报错,Kotlin却数组越界,因「循环条件不一样


Java先判断是否满足条件执行循环体自增


Kotlin遍历的是范围,直接进循环体


  • 增强for循环」=  while循环 + 迭代器Iterator


  • 迭代器的设计哲学」→ 将 遍历行为被遍历对象 分离,无需关心容器底层结构;


  • ConcurrentModificationException」异常原因(通过两个字段配合)


modCount → 记录列表结构修改次数,调用列表的remove方法,此值+1

 

expectedModCount → 预计修改次数,调用Itr迭代器中的remove方法时,会调用列表的remove方法,而后将modCount赋值给expectedModCount,即保证遍历过程中两个值是相等的;

 

如果此时调用列表的remove方法modCount增加1,而迭代器中的expectedModCount没变,两者不等,就会引发ConcurrentModificationException异常。


  • fail-fast(快速失败)」


做系统设计的时候先考虑异常情况,一旦发生异常,直接停止并上报,一种用于提前预警的Bug检测机制;在集合中的应用就是:在遍历一个集合时,当集合结构被修改,直接抛出异常。


  • 规避ConcurrentModificationException的几种方法」


  • 单线程:使用迭代器进行remove;
  • 多线程:在使用迭代器处加锁(如synchronize);
  • 使用fail-safe(安全失败)机制的同步容器,如CopyOnWriteArrayList,在java.util.concurrent包中;


  • Kotlin中使用toList()后可以规避异常的原因


创建了新的ArrayList用作遍历,remove移除的是旧ArrayList的元素,故互不影响


0x1、起因


寒冷的午后,在一个交流群里,一位开发者盆友抛出了下面的问题:



同时附带两张截图




刚好在写代码的我,随手点开了 toList() 的源码:



惯性思维 回了句:涉及到可变列表和不可变列表吧


接着截了个 Collection.kt 的文件结构图后,追加:



其实我并没有理解他的问题,就开始跟起了RecyclerView的源码,再经历过一番排查得出:


应该和 Iterable,普通for循环,增强for循环有关


然后被拉去开了个两个半小时的用例评审…回来看到问题还没解决,看了聊天记录,捋了一下才弄懂他的问题:


1、普通for循环(下标遍历),类似的代码,Java不报错,Kotlin却抛 IndexOutOfBoundsException


2、增强for循环(foreach),remove移除,都会抛 ConcurrentModificationException


看不懂?写个简单的代码演示下问题:


① Java



② Kotlin


初始化列表:



行吧,接着一个个讲解~


相关文章
|
12月前
|
分布式计算 Java 数据安全/隐私保护
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(下 )
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(下)
61 0
|
4月前
|
Kotlin 索引
Kotlin中循环语句
Kotlin中循环语句
|
2月前
|
Java Android开发 开发者
Kotlin 循环与函数详解:高效编程指南
高效编程实践 • 避免不必要的循环 - 尽量使用集合操作如 map、filter 来减少显式的循环。 • 使用尾递归优化 - 对于需要大量递归的情况,考虑使用尾递归以优化性能。 • 内联函数 - 对于传递 Lambda 表达式的函数,使用 inline 关键字可以减少运行时开销。 通过上述指南,您应该能够更好地理解 Kotlin 中的循环和函数,并能够编写更加高效和简洁的代码。Kotlin 的设计哲学鼓励开发者编写易于理解和维护的代码,而掌握循环和函数是实现这一目标的关键步骤。 如果您想了解更多关于 Kotlin 的循环和函数的信息,以下是一些官方文档和资源,它们可以提供额外的参考
35 1
|
2月前
|
Java Kotlin
Kotlin 循环与函数详解:高效编程指南
Kotlin中的循环结构让你能轻松遍历数组或范围内的元素。使用`for`循环结合`in`操作符,可以简洁地访问数组中的每个项,如字符串数组或整数数组。对于范围,可以用`..`来定义一系列连续的值并进行迭代。此外,Kotlin支持通过`break`和`continue`控制循环流程。函数则允许封装可复用的代码块,你可以定义接受参数并返回值的函数,利用简写语法使代码更加紧凑。例如,`myFunction(x: Int, y: Int) = x + y`简洁地定义了一个计算两数之和的函数。
42 1
|
2月前
|
安全 Java Android开发
Android Kotlin中如何优雅地退出循环?
本文介绍Kotlin中如何在`forEach`循环中提前退出的方法,包括使用`for`循环搭配`break`以及利用标签和`return@标签`的方式。此外,还探讨了标签与`return`、`break`和`continue`在不同场景下的应用,如嵌套循环控制、高阶函数中的提前退出及`inline`函数内的非局部返回等,帮助读者更好地掌握Kotlin的控制流技巧。
45 0
|
4月前
|
Kotlin
Kotlin流程控制、循环
Kotlin流程控制、循环
|
12月前
|
Java Kotlin
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(上)
Kotlin 学习笔记(二)—— 数据类、枚举类、循环、常用集合及操作符的写法(上)
51 0
|
安全 Java Kotlin
Kotlin刨根问底(二):for循环引起的一起“血案”(下)
本文灵感来源于:群友遍历列表时remove元素引发异常,后对for循环的实现原理进行一系列的探究~
290 0
|
设计模式 缓存 Java
Kotlin刨根问底(二):for循环引起的一起“血案”(中)
本文灵感来源于:群友遍历列表时remove元素引发异常,后对for循环的实现原理进行一系列的探究~
328 0
|
Java Android开发 图形学
Android修行手册之Kotlin-【条件语句】、【循环控制】篇
众所周知,人生是一个漫长的流程,不断克服困难,不断反思前进的过程。在这个过程中会产生很多对于人生的质疑和思考,于是我决定将自己的思考,经验和故事全部分享出来,以此寻找共鸣!!!
316 0