1. 简介
本文将介绍如何在 Kotlin 中遍历 JSONArray
对象。
我们会先尝试使用传统的 for
循环方式,然后通过扩展函数(extension function)来优化代码,让遍历更简洁、更符合 Kotlin 的惯用写法。这种技巧不仅能提升可读性,还能避免重复“样板代码”——这可是实际开发中常见的踩坑点。
2. 遍历 JSONArray
⚠️ 关键点:JSONArray
类并未实现 Iterable
接口,因此无法直接用于 Kotlin 的 for-each
循环(即 for (item in collection)
这种语法)。
这意味着你不能这样写:
// ❌ 编译报错!JSONArray 没有 iterator()
for (book in booksJSONArray) {
println(book)
}
那怎么办?我们来看几种替代方案。
2.1 使用 for 循环手动遍历
最直接的方式是通过索引进行遍历:
val booksJSONArray = JSONArray(BOOKS_STRING)
for (i in 0 until booksJSONArray.length()) {
val book = booksJSONArray.getJSONObject(i)
println("${book.get("book_name")} by ${book.get("author")}")
}
✅ 输出示例:
The Great Gatsby by F. Scott Fitzgerald
To Kill a Mockingbird by Harper Lee
你也可以改用 forEach
结合区间表达式,使代码更具函数式风格:
val booksJSONArray = JSONArray(BOOKS_STRING)
(0 until booksJSONArray.length()).forEach {
val book = booksJSONArray.getJSONObject(it)
println("${book.get("book_name")} by ${book.get("author")}")
}
虽然这种方式比原始 for 循环稍显现代,但仍然不够直观,尤其是当你频繁处理 JSON 数据时,容易写出大量重复逻辑。
2.2 添加便捷的扩展函数
Kotlin 的一大优势就是支持扩展函数,我们可以借此“修补” JSONArray
的短板,让它支持标准的 for-in
遍历。
目标效果如下:
// ✅ 现在可以这么写了!
for (book in booksJSONArray) {
println("${(book as JSONObject).get("book_name")} by ${(book as JSONObject).get("author")}")
}
要实现这一点,只需定义一个操作符扩展函数 iterator()
:
operator fun <T> JSONArray.iterator(): Iterator<T> =
(0 until this.length()).asSequence().map { this.get(it) as T }.iterator()
📌 解析一下这段代码:
operator
关键字:让该函数成为合法的迭代器操作符,从而支持for-in
语法。- 泛型
<T>
:允许返回任意类型(实际使用中通常是JSONObject
或String
)。 - 利用
(0 until length())
生成索引序列,再通过map
转换为实际元素。 - 最终调用
.iterator()
返回标准迭代器。
一旦这个扩展函数被导入作用域,所有 JSONArray
实例都将“获得”迭代能力。
🎯 使用建议:
- 将此扩展函数放在工具类或顶层函数文件中(如
JsonExtensions.kt
),便于复用。 - 注意类型转换安全问题,确保你知道
JSONArray
中存储的是JSONObject
还是基本类型。
3. 总结
- ❌
JSONArray
原生不支持Iterable
,无法直接用于for-in
循环。 - ✅ 可通过索引循环(
for
或forEach
)完成遍历,适合简单场景。 - ✅ 更优雅的做法是使用
operator fun JSONArray.iterator()
扩展函数,使其无缝集成进 Kotlin 的集合遍历体系。 - 💡 此技巧适用于任何未实现
Iterable
但可通过索引访问的容器类,属于典型的“Kotlin 扩展思维”。
所有示例代码已托管至 GitHub:https://github.com/Baeldung/kotlin-tutorials/tree/master/kotlin-json
示例中的
BOOKS_STRING
可 mock 如下:const val BOOKS_STRING = """ [ {"book_name": "The Great Gatsby", "author": "F. Scott Fitzgerald"}, {"book_name": "To Kill a Mockingbird", "author": "Harper Lee"} ] """