HOWTO · Java
在 Java 中对数组进行切片
本文将帮助你用 Java 将数组切片为子数组。
本页内容
要对 Java 数组进行切片,可以把一个连续范围内的元素复制到一个新数组中。下面的示例使用左闭右开的范围:fromIndex 包含在内,toIndex 是第一个不包含在内的索引。例如,范围 [2, 5) 选取的是索引 2、3 和 4。原始数组保持不变。
在 Java 中通过复制元素对数组进行切片
用循环可以让索引的对应关系一目了然。先分配长度为 toIndex - fromIndex 的结果数组,然后把每个选中的值复制到结果数组中对应的位置。
下面这个完整的程序从一个整数数组中选取索引 1 到 3 的元素:
import java.util.Arrays;
public class ArraySliceLoop {
static int[] slice(int[] values, int fromIndex, int toIndex) {
int[] result = new int[toIndex - fromIndex];
for (int i = 0; i < result.length; i++) {
result[i] = values[fromIndex + i];
}
return result;
}
public static void main(String[] args) {
int[] values = {10, 20, 30, 40, 50};
int[] part = slice(values, 1, 4);
System.out.println(Arrays.toString(part));
}
}
结果是一个独立的数组。循环计数器 i 针对结果数组从零开始,而 fromIndex + i 则定位源数组中对应的元素。调用该方法时,应传入在源数组范围内描述有效范围的索引。
在 Java 中使用 copyOfRange() 方法对数组进行切片
Arrays.copyOfRange() 提供了一种从某个范围直接创建新数组的方法。该方法属于 java.util.Arrays;它的 from 参数包含在内,to 参数不包含在内。确切的 API 名称中包含 copyOfRange()。
下面这个程序复制索引 1、2 和 3 的元素:
import java.util.Arrays;
public class ArraySliceCopyOfRange {
public static void main(String[] args) {
int[] values = {10, 20, 30, 40, 50};
int[] part = Arrays.copyOfRange(values, 1, 4);
System.out.println(Arrays.toString(part));
}
}
返回的数组包含选中的值,修改它不会替换原始数组中的元素。对于 int[] 等基本类型数组,复制的是值本身。对于对象数组,数组是新建的,但其中的元素仍是对相同对象的引用。
在 Java 中使用流对数组进行切片
流可以通过把索引流映射回源数组来选取数组中的值。把这种方式当作一种可选方案:只有当项目配置的 Java 运行时支持所需的流 API 时才使用它。这里不预设任何运行时版本。
这个操作可以写成 IntStream.range(fromIndex, toIndex).map(i -> values[i]).toArray()。IntStream.range 使用包含起始、排除结尾的约定,因此与其它方法遵循相同的范围约定。这个紧凑的表达式只是一个示意;在实际使用之前,请先对照项目声明的 Java 运行时确认 API 可用性。当运行时未知时,循环或 Arrays.copyOfRange() 是直接明了的替代方案。
在 Java 中使用 System.arraycopy 方法对数组进行切片
System.arraycopy 把指定数量的元素从一个数组复制到另一个数组。先创建一个长度为 toIndex - fromIndex 的目标数组,然后传入源位置、目标位置和要复制的元素数量。
import java.util.Arrays;
public class ArraySliceSystemArraycopy {
public static void main(String[] args) {
int[] values = {10, 20, 30, 40, 50};
int fromIndex = 1;
int toIndex = 4;
int[] part = new int[toIndex - fromIndex];
System.arraycopy(values, fromIndex, part, 0, part.length);
System.out.println(Arrays.toString(part));
}
}
这些参数依次是源数组、源位置、目标数组、目标位置和要复制的元素数量。这里目标位置为零,因此选中的源范围会从目标数组的第一个位置开始填满 part。源数组和目标数组的元素类型必须兼容,位置和长度也必须同时适合两个数组。
在 Java 中使用 asList 和 subList 对数组进行切片
对于引用类型数组,Arrays.asList() 会创建一个由该数组支撑的固定大小列表。subList(fromIndex, toIndex) 返回所选列表范围的视图。当结果应当是一个独立数组时,把该视图转换成数组。
import java.util.Arrays;
import java.util.List;
public class ArraySliceSubList {
public static void main(String[] args) {
String[] values = {"red", "green", "blue", "gold"};
List<String> list = Arrays.asList(values);
List<String> selected = list.subList(1, 3);
String[] part = selected.toArray(new String[0]);
System.out.println(Arrays.toString(part));
}
}
Arrays.asList() 返回的列表大小固定:你可以替换某个元素,但不能添加或删除列表条目。子列表是与该列表绑定的视图。调用 toArray() 会创建一个独立的数组,尽管对象元素本身仍是对相同对象的引用。这种方式适用于 String[] 等引用类型数组;基本类型数组需要使用上面展示的循环、copyOfRange() 或 System.arraycopy 等处理基本类型数组的方法。
结论
当你想看清或定制逐元素复制的过程时,使用循环。想要直接复制数组时选择 Arrays.copyOfRange(),或者在需要指定目标位置和复制长度时选择 System.arraycopy。当项目的 Java 运行时支持所需的 API 时,流提供了基于索引的选取方式。对于引用类型数组,asList 和 subList 提供了列表视图;调用 toArray() 即可获得一个独立的结果数组。