Scala的Array就是Java数组的封装,但Scala给它装上了集合操作的"超能力"。索引访问、map/filter、与List互转——让数组处理从Java的for循环中解放出来。
如果你从Java转到Scala,第一次用数组时可能会有疑问:Scala的Array和Java的数组是同一个东西吗?为什么可以直接用map和filter?
第一个问题的答案是:是的,Scala的Array编译后就是Java的数组(int[]、String[]),JVM层面完全一样。第二个问题的答案是:Scala通过隐式转换,把Array当作Seq来操作——你写的是数组,用的却是集合的API。
在大数据开发中,数组无处不在:Spark RDD的分区数据是数组、Flink的窗口缓冲区是数组、NumPy风格的数值计算依赖数组。理解Scala的Array,就是理解大数据内存计算的底层数据结构。
这篇文章从七个层面拆解Scala的Array操作,帮你从Java的数组处理中平滑迁移。

01 Array基础:定长、可变、与Java互操作
Array就是Java数组
// Scala的Array编译后就是Java数组
val arr = Array(1, 2, 3, 4, 5)
// 编译后等价于Java的 int[] arr = {1,2,3,4,5};
// 可以直接索引访问
arr(0) // 1
arr(4) // 5
// 可以修改元素(数组是可变的)
arr(0) = 10
// arr: Array(10, 2, 3, 4, 5)
Array是定长的
val arr = new Array[Int](5)
// 长度固定为5,不能动态扩展
arr(0) = 1
arr(1) = 2
// arr: Array(1, 2, 0, 0, 0)
// arr += 6 // 编译错误:Array长度固定
Array与Java数组互操作
// Scala Array就是Java数组,可以直接传给Java方法
def processJavaArray(arr: Array[Int]): Unit = {
// 这个arr在JVM层面就是int[]
arr.foreach(println)
}
// 也可以从Java数组创建Scala Array
val javaArr: Array[Int] = Array(1, 2, 3)
// 完全等价
对Java开发者的启示:Java数组和Scala数组在JVM层面是同一个东西,互操作零成本。这意味着你可以在Scala代码中直接调用Java库,传入数组参数,不需要任何转换。
02 Array创建与初始化
用apply方法创建
// 最常用:Array.apply
val arr1 = Array(1, 2, 3, 4, 5)
// Array[Int] = Array(1, 2, 3, 4, 5)
// 混合类型会自动推断公共父类型
val arr2 = Array(1, "two", 3.0)
// Array[Any] = Array(1, two, 3.0)
// 空数组
val empty = Array.empty[String]
// Array[String] = Array()
用new创建指定长度
// 创建指定长度的数组,元素为默认值
val arr1 = new Array[Int](5)
// Array(0, 0, 0, 0, 0)
val arr2 = new Array[String](3)
// Array(null, null, null)
val arr3 = new Array[Boolean](2)
// Array(false, false)
常用初始化方法
// range:生成范围数组
Array.range(1, 10) // Array(1,2,3,4,5,6,7,8,9)
Array.range(1, 10, 2) // Array(1,3,5,7,9),步长2
// fill:填充相同值
Array.fill(5)("hello") // Array(hello, hello, hello, hello, hello)
Array.fill(3, 2)(0) // 二维数组 Array(Array(0,0), Array(0,0), Array(0,0))
// tabulate:按函数生成
Array.tabulate(5)(n => n * n)
// Array(0, 1, 4, 9, 16)
// concatenate:合并数组
Array.concat(Array(1,2), Array(3,4))
// Array(1, 2, 3, 4)
03 Array常用操作
索引访问与修改
val arr = Array(10, 20, 30, 40, 50)
// 读取
arr(0) // 10
arr.last // 50
arr.head // 10
arr.apply(2) // 30,等价于arr(2)
// 修改
arr(0) = 100
// arr: Array(100, 20, 30, 40, 50)
// 长度
arr.length // 5
arr.size // 5,等价于length
遍历
val arr = Array("a", "b", "c")
// 最简单:foreach
arr.foreach(println)
// 带索引
for ((elem, i) <- arr.zipWithIndex) {
println(s"$i: $elem")
}
// 传统for循环
for (i <- 0 until arr.length) {
println(arr(i))
}
转换与映射
val arr = Array(1, 2, 3, 4, 5)
// map:每个元素转换
arr.map(_ * 2)
// Array(2, 4, 6, 8, 10)
// filter:过滤元素
arr.filter(_ % 2 == 0)
// Array(2, 4)
// reduce:聚合
arr.reduce(_ + _)
// 15
// fold:带初始值的聚合
arr.fold(0)(_ + _)
// 15
排序
val arr = Array(3, 1, 4, 1, 5, 9, 2, 6)
// 升序排序(返回新数组)
arr.sorted
// Array(1, 1, 2, 3, 4, 5, 6, 9)
// 降序
arr.sortWith(_ > _)
// Array(9, 6, 5, 4, 3, 2, 1, 1)
// 按指定字段排序
case class Person(name: String, age: Int)
val people = Array(Person("Alice", 25), Person("Bob", 20), Person("Charlie", 30))
people.sortBy(_.age)
// 按年龄升序
04 ArrayBuffer:可变数组
Array是定长的,需要动态扩展时用ArrayBuffer。
创建与操作
import scala.collection.mutable.ArrayBuffer
// 创建ArrayBuffer
val buf = ArrayBuffer[Int]()
// ArrayBuffer()
// 添加元素
buf += 1
buf += 2
buf += 3
// ArrayBuffer(1, 2, 3)
// 添加多个元素
buf += (4, 5, 6)
// ArrayBuffer(1, 2, 3, 4, 5, 6)
// 追加另一个集合
buf ++= Array(7, 8)
// ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)
删除与修改
val buf = ArrayBuffer(1, 2, 3, 4, 5)
// 删除最后一个元素
buf.remove(buf.length - 1)
// ArrayBuffer(1, 2, 3, 4)
// 删除指定位置
buf.remove(0)
// ArrayBuffer(2, 3, 4)
// 修改
buf(0) = 100
// ArrayBuffer(100, 3, 4)
转换为Array
val buf = ArrayBuffer(1, 2, 3, 4, 5)
// 转换为定长Array
val arr = buf.toArray
// Array(1, 2, 3, 4, 5)
// 转换为List
val list = buf.toList
// List(1, 2, 3, 4, 5)
05 Array与集合互转
Array ↔ List
val arr = Array(1, 2, 3, 4, 5)
// Array转List
val list = arr.toList
// List(1, 2, 3, 4, 5)
// List转Array
val arr2 = list.toArray
// Array(1, 2, 3, 4, 5)
// Array转Seq
val seq = arr.toSeq
// WrappedArray(1, 2, 3, 4, 5)
Array与集合操作的关系
val arr = Array(1, 2, 3, 4, 5)
// Array本身不是Seq,但可以通过隐式转换使用Seq的方法
arr.map(_ * 2) // 返回Array
arr.filter(_ > 2) // 返回Array
arr.reduce(_ + _) // 返回Int
arr.mkString(", ") // "1, 2, 3, 4, 5"
// 注意:map/filter返回的还是Array
arr.map(_ * 2).getClass.getSimpleName
// int[](基本类型数组)或 Object[]
WrappedArray:Array的Seq视图
val arr = Array(1, 2, 3)
// 当你需要Seq类型时,Array会自动转换为WrappedArray
val seq: Seq[Int] = arr
// WrappedArray(1, 2, 3)
// WrappedArray是Array的Seq视图,不复制数据
// 修改原数组,视图也会变
arr(0) = 100
println(seq)
// WrappedArray(100, 2, 3)
大数据场景提示:Spark的RDD.collect()返回的就是Array,而RDD的map/filter返回的是RDD。理解Array和集合操作的关系,有助于理解Spark转换操作的底层实现。
06 多维数组
创建多维数组
// 二维数组:3行4列
val matrix = Array.ofDim[Int](3, 4)
// Array(Array(0,0,0,0), Array(0,0,0,0), Array(0,0,0,0))
// 赋值
matrix(0)(0) = 1
matrix(1)(1) = 2
// Array(Array(1,0,0,0), Array(0,2,0,0), Array(0,0,0,0))
// 创建并初始化
val grid = Array(
Array(1, 2, 3),
Array(4, 5, 6),
Array(7, 8, 9)
)
// 3x3矩阵
多维数组操作
val matrix = Array(
Array(1, 2, 3),
Array(4, 5, 6),
Array(7, 8, 9)
)
// 访问
matrix(0)(0) // 1
matrix(1)(2) // 6
// 遍历所有元素
for {
row <- matrix
elem <- row
} print(elem + " ")
// 1 2 3 4 5 6 7 8 9
// 扁平化:二维数组转一维
matrix.flatten
// Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
07 与Java数组的对比
理解Scala和Java数组操作的差异,能帮助你避免常见的迁移陷阱。

核心差异对比
| 维度 | Java | Scala |
|---|---|---|
| 数组创建 | int[] arr = new int[5] | Array(1,2,3) 或 new ArrayInt |
| 索引访问 | arr[0] | arr(0) |
| 长度 | arr.length | arr.length 或 arr.size |
| 遍历 | for(int i=0;…) | arr.foreach 或 for推导式 |
| 转换 | Arrays.stream(arr) | arr.map/filter/reduce |
| 排序 | Arrays.sort(arr) | arr.sorted 或 arr.sortBy |
| 拼接 | Arrays.toString(arr) | arr.mkString(", ") |
| 可变数组 | ArrayList | ArrayBuffer |
| 互操作 | 本身就是数组 | 编译后就是Java数组 |
Java数组操作 vs Scala数组操作
// Java: 数组创建
int[] arr = new int[5];
arr[0] = 1;
arr[1] = 2;
// Java: 数组遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// Java: 数组排序
Arrays.sort(arr);
// Java: 数组转字符串
System.out.println(Arrays.toString(arr));
// Scala: 数组创建
val arr = Array(1, 2, 3, 4, 5)
// Scala: 数组遍历
arr.foreach(println)
// Scala: 数组排序
arr.sorted
// Scala: 数组转字符串
arr.mkString(", ")
Scala数组工具方法
// 常用工具方法
import scala.util.Sorting.quickSort
val arr = Array(3, 1, 4, 1, 5, 9, 2, 6)
// 快速排序(原地修改)
quickSort(arr)
// arr: Array(1, 1, 2, 3, 4, 5, 6, 9)
// 数组合并
Array.concat(Array(1,2), Array(3,4))
// 数组填充
Array.fill(5)(0)
写在最后:数组是数据工程的底层数据结构
Scala的Array,表面上是Java数组的"语法糖封装",本质上是把数组从"一个固定大小的内存块"提升为"一个可以函数式操作的集合"。
这种提升带来三个好处:
- 更简洁的操作:map/filter/reduce替代了Java的for循环和Stream,代码更易读
- 更强的互操作性:Scala Array编译后就是Java数组,与Java库零成本互操作
- 更灵活的扩展:ArrayBuffer提供了动态扩展能力,不需要手动管理数组大小
这些特性不是孤立的,它们共同支撑了Scala的数据处理范式。Spark的RDD分区数据是数组、Flink的窗口缓冲区是数组、NumPy风格的数值计算依赖数组——这些框架的底层都是Scala数组操作的分布式版本。
学习建议:不要试图一次记住所有方法。先从数组创建和索引访问开始,写一些小练习。当你习惯了用map/filter处理数组后,再学习ArrayBuffer和多维数组。数组是编程的基本功,但在Scala里,它不仅是基本功——它是函数式数据处理的入口。
从Java的数组遍历和操作,到Scala的map/filter/reduce,不是学习"另一种数组API",而是学习一种"更函数式、更声明式、更组合的数据处理方式"。当你习惯了用Array.apply创建、用foreach遍历、用map转换、用reduce聚合,你会发现:原来数组处理可以这么优雅。
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/zmj_0817/article/details/167225052




