不可变集合类型转换异常

记录一个异常:class java.util.ImmutableCollections$ListN cannot be cast to class java.util.ArrayList (java.util.ImmutableCollections$ListN and java.util.ArrayList

文章目录

1、原因

代码中做了类型转换,将一个不可变集合 (ImmutableCollections$ListN) 强制转换为 可变集合 (ArrayList)

java 复制代码
List<String> immutableList = List.of("A", "B", "C"); // Java 9+ 不可变列表
ArrayList<String> mutableList = (ArrayList<String>) immutableList; // ❌ 抛出 ClassCastException

业务相关错误代码:

java 复制代码
 List<ClusterJob> jobs = result.get().getJobs()
            .stream()
            .sorted(Comparator.comparing(ClusterJob::getOrderUpdateTime).reversed())
            .toList();
ClusterJobResponse response = new ClusterJobResponse();
response.setJobs((ArrayList<ClusterJob>) jobs);
return BaseVo.createSuccessWithData(response);

而toList方法的源码,是一个不可变集合:

java 复制代码
default List<T> toList() {
     return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));
 }

2、解决方式一

使用 new ArrayList<>(Collection) 复制

java 复制代码
List<String> immutableList = List.of("A", "B", "C");
ArrayList<String> mutableList = new ArrayList<>(immutableList); // ✅ 复制数据

3、解决方式二

直接使用传统的Collectors.toList()

java 复制代码
List<ClusterJob> jobs = result.get().getJobs()
         .stream()
         .sorted(Comparator.comparing(ClusterJob::getOrderUpdateTime).reversed())
         .collect(Collectors.toList());
ClusterJobResponse response = new ClusterJobResponse();
response.setJobs((ArrayList<ClusterJob>) jobs);

4、关于不可变集合的补充

4.1 JDK8和9的对比

不可变集合(Immutable Collections)是指创建后内容不可修改的集合 ,任何尝试修改(add、remove、set)的操作都会抛出 UnsupportedOperationException

  • Java 8 及之前:使用 Collections.unmodifiableXXX() 做一个包装(只是视图,底层数据仍可能被修改)
  • Java 9+:新增 List.of(), Set.of(), Map.of() 等工厂方法(真正的不可变集合)
java 复制代码
public class Main {
    public static void main(String[] args) {
        List<String> original = new ArrayList<>();
        original.add("A");
        original.add("B");
        List<String> unmodifiable = Collections.unmodifiableList(original);
        // 成功
        original.add("C");
        // UnsupportedOperationException
        unmodifiable.add("C");
    }
}

如上,使用Collections.unmodifiableList包装后得到的集合,其不可被更新,但原始被包装的集合,还是可以更改

Java9+以后,创建不可变集合:

java 复制代码
List<String> immutableList = List.of("A", "B", "C");  
Set<Integer> immutableSet = Set.of(1, 2, 3);  
Map<String, Integer> immutableMap = Map.of("A", 1, "B", 2);  

// 空集合
List<String> emptyList = List.of();  
Map<String, Integer> emptyMap = Map.of();  

此时的集合,不可被更新,自然也不能被类型转换,如 (ArrayList) List.of(...) 会抛异常,推荐使用这种方式,内存占用更小,性能更好

4.2 相关源码

核心类:ImmutableCollections

throw UnsupportedOperationException在日常开发用的也很多,一个接口,不同的策略,有时候某一个实现类并不需要实现接口的某一个方法,此时可以直接抛这个异常

4.3 不可变集合的使用场景

用于定义一些存放固定值的常量或者成员变量:

java 复制代码
public static final List<String> COUNTRIES = List.of("China", "US", "UK");
java 复制代码
private static final Map<String, Integer> CACHE = Map.of(
    "VIP", 100,
    "NORMAL", 10
);

用于防御性拷贝,List.copyOf创建不可变副本,此时,哪怕后面original被改变了,我自己还是不受影响

java 复制代码
public void processData(List<String> original) {
    List<String> safeCopy = List.copyOf(original); // 创建不可变副本
    // 安全使用 safeCopy
}

当然,以下这个写法也行

java 复制代码
List<String> original = new ArrayList<>();
List<String> listNew = new ArrayList<>(original);

new ArrayList<>(original)List.copyOf(original) 都会创建独立副本,后续对 original 的修改不会影响副本,区别是:前者返回的一个可变集合,后者则是一个严格的不可变集合

相关推荐
DogDaoDao10 分钟前
【第 05 篇】Python的字典与集合
开发语言·python·集合·字典
摇滚侠12 分钟前
SpringMVC 入门到实战 配置类替换 XML 配置文件 86-91
xml·java·后端·spring·maven·intellij-idea
栗子~~15 分钟前
金融场景下BigDecimal 运算规范 + 常用场景使用 + 数据库字段设计详解
java·数据库·金融
我登哥MVP18 分钟前
SpringCloud Alibaba 核心组件解析:服务注册与发现(Nacos)
java·spring boot·后端·spring·spring cloud·java-ee·maven
兰令水24 分钟前
leecodecode【单调栈】【2026.6.12打卡-java版本】
java·开发语言·算法
云烟成雨TD29 分钟前
Agent Scope Java 2.x 系列【8】工具调用
java·人工智能·agent
AI人工智能+电脑小能手37 分钟前
【大白话说Java面试题 第112题】【并发篇】第12题:AQS 中节点的入队时机有哪些?
java·开发语言·面试
摇滚侠37 分钟前
SpringMVC 入门到实战 处理静态资源的过程 64
java·后端·spring·maven·intellij-idea
影寂ldy38 分钟前
C# 泛型委托
java·算法·c#
摇滚侠39 分钟前
MyBatis 入门到项目实战 MyBatis 核心配置文件 15-19
java·tomcat·mybatis