最近接手一个同事的代码,返回一个 list,我在添加数据时提示 UnsupportedOperationException 这个报错是提示不支持的操作,为什么不支持呢?往上翻代码发现传过来的 list 是这样的 Arrays.asList(1,2); 看到这个报错就明白了,下面详细说说。
几种 list 的创建方式:
1、通过 new 对象的方式
List<Integer> list = new ArrayList<>();
// 最常用的方式,可以理解为是一个标准 List
// 源码就不看了,应该都看过了
复制代码
2、使用匿名内部类
List<Integer> list = new ArrayList<>() {{
add(1);
add(2);
}};
// 原理同上,只是使用了匿名内部类
复制代码
3、通过 Arrays 创建
List<Integer> list = Arrays.asList(1,2);
// 参数是可变长度的
// 使用:没有增删操作的场景,如 接口直接返回
复制代码
下图是源码,asList() 返回一个 ArrayList,这样看似没什么不同,但你仔细看返回的这个 ArrayList 是 Arrays 的一个私有内部类,并非常用的那个 ArrayList,虽然同样继承自 AbstractList,但这个 ArrayList 内部并没有重写 add() 方法(没有重写父类的方法,执行 add() 时会去调用父类的 add(),AbstractList里面的add() 直接抛出一个 UnsupportedOperationException 不支持的操作),只有几个简单的函数。
作为设计者去写一个类为内部类,肯定是希望只有内部调用,而非公开使用。
4、使用 Collections 创建一个单数据 List
List<Integer> list = Collections.singletonList(1);
// 也是一个常用方式,参数只有一个,内部数据也只有一个
复制代码
下图 SingletonList 同样也是一个私有内部类,同样继承自 AbstractList,同样没有重新 add() 函数,所以同样不支持 add() 操作。还有一个注意的点,因为是单个数据的 list,它的 size() 返回 1。
5、使用 Stream 流创建 List
List<Integer> list = Stream.of(1, 2, 3).collect(toList());
// 下面是 collect(toList()) 的 toList()
复制代码
Stream 是 JDK1.8 推出的,1.8 以下的版本不支持这种方式,这里要看 toList() 函数。可以看到源码也是使用 new ArrayList,然后调用 add() 方法依次添加的。
6、使用 List 接口的静态的方法
List<Integer> list = List.of(1, 2, 3);
// 接口的静态的方法,也称默认函数
复制代码
返回了 new ImmutableCollections.List12<>(e1)
ImmutableCollections
是一个不可变集合 既然不可变,说明也是不能 add 的。
不过有一点,既然有可变参数函数 static <E> List<E> of(E... elements),为什么还要每不同参数数量都要写一个函数呢,虽然再往下,一个是 List12 一个是 ListN,但里面实现也差不多
7、使用 Collections 集合创建一个空的 list
List<Integer> list = Collections.emptyList();
// 返回一个空的 List,不可变,也是不能 add 的
复制代码
这大概是防止报错用的吧...hhh 实际真的就是防止报错用的。你可能会想用 new ArrayList<>()
不也一样吗? 不一样!
new ArrayList<>() 是构造一个初始容量为 10 的空列表。
Collections.emptyList() 返回的是 EmptyList(空数组), 减少了内存开销
复制代码
8、使用 Collections 集合创建带副本的 list
/**
* 参数 n :重复多少个o
* 参数 o :要添加的元素
*/
List<Integer> list = Collections.nCopies(n, o);
例子:
// list 里面有3个元素,3个元素都是 1
// [1, 1, 1]
List<Integer> list = Collections.nCopies(3, 1);
// list 里面有4个元素,4个元素都是 "AAA"
// ["AAA", "AAA", "AAA", "AAA"]
List<String> list = Collections.nCopies(4, "AAA");
复制代码
同样是私有的内部类,继承了 AbstractList 没有重写 add() 方法,注释提示,与 list.addAll() 配合服用效果更佳哦。
总结
今天不总结,上面都说明白了,再看不明白出来挨打! 下班!!!