目录
1. 泛型方法 + 手动遍历
2. Arrays.asList() + 列表构造器
3. Arrays.stream() + Stream.collect() 方法
4. Guava 的工具类 (推荐)
1. 泛型方法 + 手动遍历
JDK1.5 之后才能实现。其原理就是利用泛型方法,使用循环遍历数组,将其手动转为集合。示例代码如下:
/**
* 第一种数组转列表的方式:
* JDK1.5+ 泛型方法 + 手动遍历
*
* @author wl
* @date 2022/10/12 11:21
*/
public class ArrayToList01 {
public static void main(String[] args) {
// 创建一个 Integer 类型的数组
Integer [] arr = {16, 41, 89, 33, 40, 54, 48, 37, 35, 44,
26, 53, 28, 24, 36, 18, 61, 29, 66, 66, };
List<Integer> manual = manual(arr);
}
/**
* 利用 JDK1.5 之后的泛型特性,
* 手动将数组转为列表
*
* @param array 待转为集合的数组
* @return java.util.List<T>
* @author wl
* @date 2022/10/17 18:17
*/
public static <T> List<T> manual(final T[] array) {
// 创建一个泛型列表
final List<T> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final T i : array) {
list.add(i);
}
//
return list;
}
}
不过这个方法仅适用于对象类型的数组,如果是基本数据类型的数组,就比较麻烦,需要为每一种数据类型写一个单独的方法,如下所示:
/**
* 第一种数组转列表的方式:
* JDK1.5+ 泛型方法 + 手动遍历
*
* @author wl
* @date 2022/10/12 11:21
*/
public class ArrayToList01 {
public static void main(String[] args) {
// 创建一个 Integer 类型的数组
int [] arr = {16, 41, 89, 33, 40, 54, 48, 37, 35, 44,
26, 53, 28, 24, 36, 18, 61, 29, 66, 66, };
// 将数组转为对应类型的列表
List<Integer> manual = manual(arr);
}
/**
* 将 byte 数组转为 Byte 列表
*
* @param array 数组
* @author wl
* @date 2022/10/17 19:19
* @return java.util.List<java.lang.Integer>
*/
public static List<Byte> manual(byte[] array) {
// 创建一个泛型列表
final List<Byte> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final byte i : array) {
list.add(i);
}
return list;
}
/**
* 将 short 数组转为 Short 列表
*
* @param array 数组
* @author wl
* @date 2022/10/17 19:19
* @return java.util.List<java.lang.Integer>
*/
public static List<Short> manual(short[] array) {
// 创建一个泛型列表
final List<Short> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final short i : array) {
list.add(i);
}
return list;
}
/**
* 将 int 数组转为 Integer 列表
*
* @param array 数组
* @author wl
* @date 2022/10/17 19:19
* @return java.util.List<java.lang.Integer>
*/
public static List<Integer> manual(int[] array) {
// 创建一个泛型列表
final List<Integer> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final int i : array) {
list.add(i);
}
return list;
}
/**
* 将 long 数组转为 Long列表
*
* @param array 数组
* @author wl
* @date 2022/10/17 19:19
* @return java.util.List<java.lang.Integer>
*/
public static List<Long> manual(long[] array) {
// 创建一个泛型列表
final List<Long> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final long i : array) {
list.add(i);
}
return list;
}
/**
* 将 boolean 数组转为 Boolean 列表
*
* @param array 数组
* @author wl
* @date 2022/10/17 19:19
* @return java.util.List<java.lang.Integer>
*/
public static List<Boolean> manual(boolean[] array) {
// 创建一个泛型列表
final List<Boolean> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final boolean i : array) {
list.add(i);
}
return list;
}
/**
* 将 float 数组转为 Float 列表
*
* @param array 数组
* @author wl
* @date 2022/10/17 19:19
* @return java.util.List<java.lang.Integer>
*/
public static List<Float> manual(float[] array) {
// 创建一个泛型列表
final List<Float> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final float i : array) {
list.add(i);
}
return list;
}
/**
* 将 double 数组转为 Double 列表
*
* @param array 数组
* @author wl
* @date 2022/10/17 19:19
* @return java.util.List<java.lang.Integer>
*/
public static List<Double> manual(double[] array) {
// 创建一个泛型列表
final List<Double> list = new ArrayList<>(array.length);
// 遍历数组,手动将其每个元素加入到刚创建的泛型列表中
for (final double i : array) {
list.add(i);
}
return list;
}
}
由于 JDK 官方的 “ 短视 ” ,在早期,也就是 JDK版本还是 1.0 时候的版本没能推出泛型,直到 JDK 1.5 之后才引入了泛型。因为引入的很晚, JDK 官方也考虑到代码可能会有部分兼容性的问题,如果实现真泛型的话,原先的 JDK1.0 的部分代码可能会无法运行。
/**
* 第一种数组转列表的方式:
* JDK1.5+ 泛型方法 + 手动遍历
*
* @author wl
* @date 2022/10/18 9:22
*/
public class ArrayToList01 {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>(20);
integerList.add(1);
List<Double> doubleList = new ArrayList<>(20);
doubleList.add(1.0D);
Class<? extends Integer> aClass = integerList.get(0).getClass();
Class<? extends Double> aClass1 = doubleList.get(0).getClass();
// 这里会打印出 true
System.out.println(aClass.getClass() == aClass1.getClass());
}
}
所以为了保持代码的兼容性,在使用泛型的时候,程序在底层执行 javac 命令编译的时候就会将所有的泛型类型直接替换为 Object 的类型。
2. Arrays.asList() + 列表构造器
上面那种是手动转置的写法,一般情况不会用到,正常写代码都会直接使用现成的工具类或方法。这是一种常见的写法,相信大家或多或少都见过,不过还是要在这里介绍一下:
/**
* 第二种数组转列表的方式:
* Arrays.asList() + 列表构造器
*
* @author wl
* @date 2022/10/12 11:21
*/
public class ArrayToList02 {
public static void main(String[] args) {
// 创建数组
Double[] doubles = new Double[10];
Scanner in = new Scanner(System.in);
for (int i = 0; i < doubles.length; i++) {
doubles[i] = in.nextDouble();
}
// 将数组转为对应类型的列表
List<Double> arrayList = new ArrayList<>(Arrays.asList(doubles));
}
}
Arrays.asList() 方法其实就可以返回一个列表了,为什么还需要借列表的构造器方法创建列表。其实,原因是这样的,Arrays.asList() 确实会返回一个列表不假,但是这是一个 “ 阉割版 ” 的列表,无法执行增删元素操作,如果强制调用其 add() 或 remove() 方法,就会抛出一个 UnsupportedOperationException 异常,查看底层实现你会发现 Arrays.asList()
此外,这个方法不适合基本数据类型的数组,必须要先将其转为其包装类的数组才行
3. Arrays.stream() + Stream.collect() 方法
此方法只适用于 JDK1.8 之后的版本,通过 Stream 流的方法间接把数组转为列表,如果你还不知道如何使用 Stream 流,那么可以看看我的另一篇文章:巧用Stream流
好了,废话不多说,看看示例吧:
/**
* 第三种数组转列表的方式:
* Arrays.stream() + Stream.collect() 方法
*
* @author wl
* @date 2022/10/12 11:21
*/
public class ArrayToList03 {
public static void main(String[] args) {
// 创建一个 long 基本数据类型的数组
Long[] longs = new Long[20];
for (int i = 0; i < longs.length; i++) {
longs[i] = (long) (Math.random() * 100L) + 1L;
}
// 将数组转为 Stream 流
Stream<Long> stream = Arrays.stream(longs);
// 将 Stream 流转为列表
List<Long> arrayList = stream
.collect(Collectors.toList());
}
}
这种方式也支持部分基本数据类型的数组转为列表,其中包含 int、double 和 long,其他的基本数据类型数组暂不支持:
/**
* 第三种数组转列表的方式:
* Arrays.stream() + Stream.collect() 方法
*
* @author wl
* @date 2022/10/12 11:21
*/
public class ArrayToList03 {
public static void main(String[] args) {
// 创建 double 类型的数组
double[] arr = {1.2, 7.4, -4,8, 9.2, 4.0};
// 通过 Stream 流创建列表
ArrayList<Object> arrayList = Arrays
.stream(arr)
.collect(ArrayList::new,
ArrayList::add,
ArrayList::addAll);
// 还可以依赖 Boxed 的装箱操作实现
List<Double> arrayList2 = Arrays.stream(arr)
.boxed()
.collect(Collectors.toList());
}
}
4. Guava 第三方库 (推荐)
在使用前需要先引入依赖或 jar 包:
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
ImmutableList 类及其 of()与 copyOf()
/**
* 第四种数组转列表的方式:
* Guava 的工具类 (推荐)
*
* @author wl
* @date 2022/10/12 11:21
*/
public class ArrayToList04 {
public static void main(String[] args) {
String[] aStringArray = {"string", "elements"};
// 对于可变参数使用 ImmutableList 的 of() 方法进行创建
List<String> i1 = ImmutableList.of("string", "elements");
// 对于数组则可以使用 ImmutableList 的 copyOf() 方法创建
List<String> i2 = ImmutableList.copyOf(aStringArray);
}
}
为什么要使用不可变集合呢,因为不可变集合主要有以下优点:
- 在多线程操作下,是线程安全的。
- 所有不可变集合会比可变集合更有效的利用资源。
- 当对象被不可信的库调用时,不可变形式是安全的。
- 不可变集合不需要考虑变化,因此可以节省时间和空间。
- 不可变对象因为有固定不变,可以作为常量来安全使用。
另一种为可变集合,不过在可变集合上,似乎 Guava 不支持用数组创建,因为可变集合的大部分类都是 Map、Set 之类,无法直接或间接支持使用数组进行创建列表,如果想使用可变集合,那么使用 JDK 的 ArrayList 或 LinkedList 就行。