Arrays.asList使用指南和一些坑(转)
一、java.util.Arrays.asList() 的一般用法
List 是一种很有用的数据结构,如果需要将一个数组转换为 List 以便进行更丰富的操作的话,可以这么实现:
String[] myArray = { "Apple", "Banana", "Orange" };
List<String> myList = Arrays.asList(myArray);
或者
List<String> myList = Arrays.asList("Apple", "Orange");
上面这两种形式都是十分常见的:将需要转化的数组作为参数,或者直接把数组元素作为参数,都可以实现转换。
二、极易出现的错误及相应的解决方案
错误一: 将原生数据类型数据的数组作为参数
前面说过,可以将需要转换的数组作为 asList 方法的参数。假设现在需要转换一个整型数组,那可能有人会想当然地这么做:
public class Test {
public static void main(String[] args) {
int[] myArray = { 1, 2, 3 };
List myList = Arrays.asList(myArray);
System.out.println(myList.size());
}
}
上面这段代码的输出结果是什么,会是3吗?如果有人自然而然地写出上面这段代码的话,那么他也一定会以为 myList 的大小为3。很遗憾,这段代码的输出结果不是3,而是1。如果尝试遍历 myList ,你会发现得到的元素不是1、2、3中的任意一个,而是一个带有 hashCode 的对象。为什么会如此?
来看一下asList 方法的签名:
public static <T> List<T> asList(T... a)
注意:参数类型是 T ,根据官方文档的描述,T 是数组元素的 class。
如果你对反射技术比较了解的话,那么 class 的含义想必是不言自明。我们知道任何类型的对象都有一个 class 属性,这个属性代表了这个类型本身。原生数据类型,比如 int,short,long等,是没有这个属性的,具有 class 属性的是它们所对应的包装类 Integer,Short,Long。
因此,这个错误产生的原因可解释为:asList 方法的参数必须是对象或者对象数组,而原生数据类型不是对象——这也正是包装类出现的一个主要原因。当传入一个原生数据类型数组时,asList 的真正得到的参数就不是数组中的元素,而是数组对象本身!此时List 的唯一元素就是这个数组。
解决方案:使用包装类数组
如果需要将一个整型数组转换为 List,那么就将数组的类型声明为 Integer 而不是 int。
public class Test {
public static void main(String[] args) {
Integer[] myArray = { 1, 2, 3 };
List myList = Arrays.asList(myArray);
System.out.println(myList.size());
}
}
这时 myList 的大小就是3了,遍历的话就得到1、2、3。这种方案是比较简洁明了的。
其实在文章中,作者使用了另一种解决方案——他使用了 Java 8 新引入的 API:
public class Test {
public static void main(String[] args) {
int[] intArray = { 5, 10, 21 };
//Java 8 新引入的 Stream 操作
List myList = Arrays.stream(intArray).boxed().collect(Collectors.toList());
}
}
因为我对 Java 8 的这一新特性了解得不多,所以在此就不展开阐述,有兴趣的朋友可以自行查阅相关资料。
错误二:试图修改 List 的大小
我们知道 List 是可以动态扩容的,因此在创建一个 List 之后最常见的操作就是向其中添加新的元素或是从里面删除已有元素:
public class Test {
public static void main(String[] args) {
String[] myArray = { "Apple", "Banana", "Orange" };
List<String> myList = Arrays.asList(myArray);
myList.add("Guava");
}
}
尝试运行这段代码,结果抛出了一个 java.lang.UnsupportedOperationException 异常!这一异常意味着,向 myList 添加新元素是不被允许的;如果试图从 myList 中删除元素,也会抛出相同的异常。为什么会如此?
仔细阅读官方文档,你会发现对 asList 方法的描述中有这样一句话:
返回一个由指定数组生成的固定大小的 List。
谜底揭晓,用 asList 方法产生的 List 是固定大小的,这也就意味着任何改变其大小的操作都是不允许的。
那么新的问题来了:按道理 List 本就支持动态扩容,那为什么偏偏 asList 方法产生的 List 就是固定大小的呢?如果要回答这一问题,就需要查看相关的源码。Java 8 中 asList 方法的源码如下:
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
方法中的的确确生成了一个 ArrayList ,这不应该是支持动态扩容的吗?别着急,接着往下看。紧跟在 asList 方法后面,有这样一个内部类:
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
//...
}
这个内部类也叫 ArrayList ,更重要的是在这个内部类中有一个被声明为 final 的数组 a ,所有传入的元素都会被保存在这个数组 a 中。到此,谜底又揭晓了: asList 方法返回的确实是一个 ArrayList ,但这个 ArrayList 并不是 java.util.ArrayList ,而是 java.util.Arrays 的一个内部类。这个内部类用一个 final 数组来保存元素,因此用 asList 方法产生的 ArrayList 是不可修改大小的。
解决方案:创建一个真正的 ArrayList
既然我们已经知道之所以asList 方法产生的 ArrayList 不能修改大小,是因为这个 ArrayList 并不是“货真价实”的 ArrayList ,那我们就自行创建一个真正的 ArrayList :
public class Test {
public static void main(String[] args) {
String[] myArray = { "Apple", "Banana", "Orange" };
List<String> myList = new ArrayList<String>(Arrays.asList(myArray));
myList.add("Guava");
}
}
在上面这段代码中,我们 new 了一个 java.util.ArrayList ,然后再把 asList 方法的返回值作为构造器的参数传入,最后得到的 myList 自然就是可以动态扩容的了。
三、用自己的方法实现数组到 List 的转换
有时,自己实现一个方法要比使用库中的方法好。鉴于 asList 方法有一些限制,那么我们可以用自己的方法来实现数组到 List 的转换:
public class Test {
public static void main(String[] args) {
String[] myArray = { "Apple", "Banana", "Orange" };
List<String> myList = new ArrayList<String>();
for (String str : myArray) {
myList.add(str);
}
System.out.println(myList.size());
}
}
这么做自然也是可以达到目的的,但显然有一个缺点:代码相对冗长,而且这么做其实无异于自己造轮子(reinventing the wheel)。当然了,自己实现方法的好处也是显而易见的,不管有什么需求,自己来满足就好了,毕竟自己动手丰衣足食嘛。
Arrays.asList使用指南和一些坑(转)的更多相关文章
- Arrays.asList中所遇到的坑
前言 最近在项目上线的时候发现一个问题,从后台报错日志看:java.lang.UnsupportedOperationException异常 从代码定位来看,原来是使用了Arrays.asList() ...
- Arrays.asList()使用指南
简介 Arrays.asList()在平时开发中还是比较常见的,我们可以使用它将一个数组转换为一个List集合. String[] myArray = { "Apple", &qu ...
- Java集合工具类使用的一些坑,Arrays.asList()、Collection.toArray()、foreach
Arrays.asList() 使用指南 最近使用Arrays.asList()遇到了一些坑,然后在网上看到这篇文章:Java Array to List Examples 感觉挺不错的,但是还不是特 ...
- 【Java必修课】好用的Arrays.asList也有这三个坑
好用的asList 在开发或写测试用例的过程中,经常会用到Arrays.asList()这个方法,可以快速方便地将数组转化成一个List.例如: List<String> list = A ...
- Java踩坑记系列之Arrays.AsList
java.util.Arrays的asList方法可以方便的将数组转化为集合,我们平时开发在初始化ArrayList时使用的比较多,可以简化代码,但这个静态方法asList()有几个坑需要注意: 一. ...
- Arrays.asList 存在的坑
引语: 阿里巴巴java开发规范说到使用工具类Arrays.asList()方法把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedO ...
- 由于java.util.Arrays.asList(...)导致的异常
前言: Collections.toArray()与Arrays.asList() 是Java API提供的友好的相互转换工具,日常开发中用于列表和数组之间的转换非常方便,但今天测试时,发现一下隐藏的 ...
- 为什么阿里规约手册要求谨慎使用Arrays.asList方法
前言 在开发中,有时候会碰到把多个参数,或者说把数组转成List的需求,通常我们会使用 Arrays.asList()方法.但是该方法在使用的过程中,稍有不慎就会出现严重的异常.有如下代码: @Tes ...
- coding++:Arrays.asList() - java.lang.UnsupportedOperationException异常处理
这个异常遇到了才知道坑这么大,坑爹的方法. private String[] otherUserFromArray = new String[]{“3”, “4”, “发放”}; List<St ...
随机推荐
- Spring源码--Bean的管理总结(一)
前奏 最近看了一系列解析spring管理Bean的源码的文章,在这里总结下,方便日后复盘.文章地址https://www.cnblogs.com/CodeBear/p/10336704.html sp ...
- C++ GUI Qt4学习笔记07
C++ GUI Qt4 qtc++scrollobject编程 事件(event)是由串口系统或者Qt自身产生的,用以响应所发生的各类事情.当用户按下或者松开键盘或者鼠标上的按键时,就可以产生一个 ...
- js中的 与和或 , && ,||
|| 1.只要"||"前面为false,不管"||"后面是true还是false,都返回"||"后面的值. 2.只要"||&quo ...
- react native 之 在现有的iOS工程中集成react native
在现有的iOS工程中集成react native, 或者说将react native引入到iOS 项目,是RN和iOS混合开发的必经之路 参考官网教程:https://reactnative.cn/d ...
- es的索引库模板
在实际的生产中,如果要插入大批量数据的时候需要使用多个索引库,如果我们还是手工指定每个索引的配置信息settings和mappings,是非常耗时的: 针对这种情况,es有index template ...
- oracle 如何更改密码的hash
如何迁移oracle user的密码到新的环境,一下列出了方法: select name,spare4||';'||password pwd from sys.user$ where name = ' ...
- benchmarks
系统性能测试 stream SPARK 测试 streaming benchmark https://github.com/yahoo/streaming-benchmarks
- 快速入门分布式消息队列之 RabbitMQ(1)
目录 目录 前言 简介 安装 RabbitMQ 基本对象概念 Message 消息 Producer 生产者 Consumer 消费者 Queue 队列 Exchange 交换机 Binding 绑定 ...
- Delphi XE2 之 FireMonkey 入门(20) - TStyleBook(皮肤、样式相关)
我觉得叫 "皮肤" 不如叫 "样式" 或 "风格", 因为它可以包含和动作关联的动画. 在 FMX 下, 控件可以任意绘制, 各部件个性化的 ...
- javascript 跳出循环比较
for continue 跳出当前循环,继续下一个循环 break 结束循环 forEach 不能使用continue , break return/return false 跳出当前循环,在forE ...