Java集合操作:可变集合和不可变集合
Java集合操作:可变集合和不可变集合
问题产生:java.lang.UnsupportedOperationException
问题定位:在通过mybatisPlus获取分页列表的时候写了下面这段代码
1 //分页获取列表 2 PageResult<InsuranceBeneficiaryDO> pageList = this.insuranceBeneficiaryDAO.getList(beneficiaryListBO); 3 4 List<InsuranceBeneficiaryDO> insuredList = pageList.getData(); 5 6 insuredList.add(0, applicantDO); 7 8 ... 9 public PageResult<InsuranceBeneficiaryDO> getList(BeneficiaryListBO beneficiaryListBO) { 10 LambdaQueryWrapper<InsuranceBeneficiaryDO> beneficiaryQueryWrapper = new LambdaQueryWrapper<>(); 11 12 beneficiaryQueryWrapper.eq(InsuranceBeneficiaryDO::getCurrentUserId, beneficiaryListBO.getUserId()) 13 .eq(InsuranceBeneficiaryDO::getIsApplicant, YesnoEnum.NO.getType()) 14 .eq(InsuranceBeneficiaryDO::getIsDelete, YesnoEnum.NO.getType()) 15 .like(Objects.nonNull(beneficiaryListBO.getBeneficiaryName()), InsuranceBeneficiaryDO::getBeneficiaryName,beneficiaryListBO.getBeneficiaryName()) 16 .orderByDesc(InsuranceBeneficiaryDO::getCreateTime) 17 .orderByDesc(InsuranceBeneficiaryDO::getId); 18 19 IPage<InsuranceBeneficiaryDO> page = new Page<>(beneficiaryListBO.getCurrentPage(), beneficiaryListBO.getPageSize()); 20 IPage<InsuranceBeneficiaryDO> pageData = this.page(page, beneficiaryQueryWrapper); 21 22 return new PageResult<>(pageData.getRecords(), PageUtil.transformToPaginator(pageData)); 23 }
明明编辑器也没有提示不能使用add,怎么会报出这个异常呢?
通过查阅资料,结合代码进行分析,原来是对不可变集合进行添加操作,导致的异常。下面是分析过程:
上面获取分页数据,用到了Page类(com.baomidou.mybatisplus.extension.plugins.pagination.Page),它的构造方法如下:
1 public Page() { 2 this.records = Collections.emptyList(); 3 this.total = 0L; 4 this.size = 10L; 5 this.current = 1L; 6 this.orders = new ArrayList(); 7 this.optimizeCountSql = true; 8 this.isSearchCount = true; 9 this.hitCount = false; 10 }
下面是Collections(java.util.Collections)中的相关代码:
1 public static final <T> List<T> emptyList() { 2 return (List<T>) EMPTY_LIST; 3 } 4 5 public static final List EMPTY_LIST = new EmptyList<>(); 6 7 //静态内部类 8 private static class EmptyList<E> extends AbstractList<E> implements RandomAccess,Serializable { 9 10 private static final long serialVersionUID = 8842843931221139166L; 11 ... 12 }
分析:Collections.emptyList()返回的结果实际上是 Collections.EmptyList,是 Collections 类的一个私有静态内部类,在继承AbstractList后并没有实现add()、remove()等方法,所以返回的List不能进行增加和删除元素操作。
因此,Collections.emptyList() 返回一个空的、不可修改的 List实例。尝试对其进行add,remove操作就会throw UnsupportedOperationException。
由于这里业务需要的是可修改的列表,可以这样来处理:
List<InsuranceBeneficiaryDO> insuredList = new ArrayList<>(pageList.getData());
说明:java.util.ArrayList在继承 AbstractList 后,实现了remove、add等方法,所以是支持这些操作的。
一、AbstractList
AbstractList 是一个部分实现的抽象类,提供了一些基本的列表操作,比如 size()、get() 等方法的默认实现。而对于修改操作(如 add、remove),由于不同的列表实现(如 ArrayList、LinkedList)有不同的添加方式,AbstractList 无法给出通用的实现,因此选择让这些方法抛出 UnsupportedOperationException,以表示默认实现中不支持该操作。
部分源码如下:
1 package java.util; 2 3 public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { 4 5 protected AbstractList() { 6 } 7 8 9 public boolean add(E e) { 10 add(size(), e); 11 return true; 12 } 13 14 15 abstract public E get(int index); 16 17 18 public E set(int index, E element) { 19 throw new UnsupportedOperationException(); 20 } 21 22 public void add(int index, E element) { 23 throw new UnsupportedOperationException(); 24 } 25 26 27 public E remove(int index) { 28 throw new UnsupportedOperationException(); 29 } 30 31 //... 32 33 }
二、不可变集合
不可变集合是指一旦创建就不能更改的集合。
在 Java 中,常见的不可变集合包括 Collections.unmodifiableList()
返回的列表,以及 Java 9 之后引入的 List.of()
等方法返回的不可变集合。不可变集合的优点在于其线程安全性和对错误的防范性。但是,它们的缺点是无法进行修改操作。
除了上面提到的Collections.emptyList(),还有Arrays.asList()。Arrays.asList()是一个用于将数组转换为列表的方法。然而,它返回的列表并非来自java.util.ArrayList,而是来自Arrays 内部的一个特殊实现。这个实现继承自 AbstractList
,并且没有重写 remove
、add
等方法,在这些方法上直接抛出UnsupportedOperationException异常。
2 问题示例: 3 List<String> myList = Arrays.asList("apple", "orange", "banana"); 4 5 myList.add("grape"); // 抛出 UnsupportedOperationException 异常 6 7 8 解决方案: 9 10 List<String> myList = new ArrayList<>(Arrays.asList("apple", "orange", "banana")); 11 12 myList.add("grape"); // 不再抛出异常
三、可变集合
可变集合是可以进行修改操作的集合。常见的可变集合包括 ArrayList
、LinkedList
等。这些集合允许在运行时添加、删除和修改元素。然而,需要注意的是,在多线程环境下使用可变集合可能需要额外的同步措施,以确保线程安全性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
2020-12-09 Redis执行失败后如何处理
2020-12-09 Redis实现分布式锁