当前位置: 首页 > article >正文

Arrays.asList()新增报错,该怎么解决

一、前言

在 Java 开发中,Arrays.asList() 是一个常用的工具方法,它允许开发者快速将数组转换为列表。尽管这个方法非常方便,但许多开发者在使用时可能会遭遇一个常见的错误:尝试向由 Arrays.asList() 返回的列表中添加元素时抛出异常。本文将详细探讨这个现象的根本原因,并提供相关的使用示例和解决方案。。

二、事故回顾

这个问题是出现开发一个电商平台的订单系统时,遇到了类似的问题。需要将一个订单ID数组转换为一个List,并在后续的业务逻辑中向这个List中添加新的订单ID。

由于小伙伴经验不足,使用了Arrays.asList()方法,部署到线上导致在添加新订单ID时抛出了UnsupportedOperationException异常,整个订单处理流程中断,线上系统出现了严重的故障。

影响分析

这次事故对电商平台造成了巨大的影响:

  1. 用户体验下降: 由于订单处理流程中断,用户无法正常下单,导致用户体验大幅下降。
  2. 业务中断: 订单系统的故障直接影响到了整个电商平台的业务运营,造成了大量的订单积压。
  3. 经济损失: 由于业务中断,平台失去了大量的潜在收入,给公司带来了不小的经济损失。
  4. 信任危机: 频繁的系统故障让用户对平台的信任度下降,可能导致用户流失。

后面也是及时修复,吸取本次事故教训。

三、事故问题描述

1、首先先简单描述一下这个事故问题,废话不多说,直接看实际业务代码,也就将一个数组转换为List,并对这个List进行增删操作。

Integer[] arr = {1, 2};

List<Integer> list = Arrays.asList(arr);

list.add(3);

上述代码看起来,没问题,编译器也没有报错。但是运行这段代码时,会抛出UnsupportedOperationException异常,提示我们不支持添加操作。这究竟是怎么回事呢?

所以这是不是个大坑,如果在实际开发中没有进行自测,必定不会酿成重大线上事故。

四、问题分析

上述已经知道这个使用Arrays.asList()将数组装换成List会在add情况会报错,接下来深入源码进行分析。

Arrays.asList()的内部实现

Arrays.asList(arr)方法实际上返回的是一个Arrays类的内部类ArrayList,而不是我们常用的java.util.ArrayList。这个内部类ArrayList继承自AbstractList,并没有实现add和remove方法。

Arrays类的内部类ArrayList完整源码如下:

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;
    }

    @Override
    public Object[] toArray() {
        return a.clone();
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        int size = size();
        if (a.length < size)
            return Arrays.copyOf(this.a, size,
                                 (Class<? extends T[]>) a.getClass());
        System.arraycopy(this.a, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    @Override
    public E get(int index) {
        return a[index];
    }

    @Override
    public E set(int index, E element) {
        E oldValue = a[index];
        a[index] = element;
        return oldValue;
    }

    @Override
    public int indexOf(Object o) {
        E[] a = this.a;
        if (o == null) {
            for (int i = 0; i < a.length; i++)
                if (a[i] == null)
                    return i;
        } else {
            for (int i = 0; i < a.length; i++)
                if (o.equals(a[i]))
                    return i;
        }
        return -1;
    }

    @Override
    public boolean contains(Object o) {
        return indexOf(o) != -1;
    }

    @Override
    public Spliterator<E> spliterator() {
        return Spliterators.spliterator(a, Spliterator.ORDERED);
    }

    @Override
    public void forEach(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        for (E e : a) {
            action.accept(e);
        }
    }

    @Override
    public void replaceAll(UnaryOperator<E> operator) {
        Objects.requireNonNull(operator);
        E[] a = this.a;
        for (int i = 0; i < a.length; i++) {
            a[i] = operator.apply(a[i]);
        }
    }

    @Override
    public void sort(Comparator<? super E> c) {
        Arrays.sort(a, c);
    }
}

可以看到并没有实现add和remove方法,这两个方法在父类中,默认抛出UnsupportedOperationException异常。

具体原因

下面是内部源码的分析

1.内部类ArrayList的限制:

Arrays.asList(arr)返回的内部类ArrayList是一个固定长度的列表,它没有实现add和remove方法。

当我们调用list.add(3)时,实际上调用的是AbstractList中的add方法,而这个方法直接抛出了UnsupportedOperationException异常。

2.源码分析:

AbstractList的add方法如下:

五、解决方案

面对这一限制,开发者可以采取以下几种方式来处理 Arrays.asList() 返回的列表:

1、使用 new ArrayList<>() 创建可变列表

如果需要一个可变大小的列表,可以使用 new ArrayList<>(Arrays.asList(fruits)) 进行转换:   这种方式创建了一个新的 ArrayList 实例,它的大小是可变的,因此可以自由添加、删除元素。

List<String> dynamicList = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));

dynamicList.add("Date");  // 现在可以成功添加元素

System.out.println(dynamicList);

2、直接初始化 ArrayList

另一种选择是直接使用 ArrayList 的构造函数,并传入数组元素:   这种方法提供了更大的灵活性,适合需要动态修改的场景。

List<String> dynamicList = new ArrayList<>();

Collections.addAll(dynamicList, "Apple", "Banana", "Cherry");

dynamicList.add("Date");  // 添加成功

3、使用流(Streams)

在 Java 8 及更高版本中,可以利用流的 API 来创建可变列表:   这种方法简洁而现代化,适合喜欢函数式编程风格的开发者。

List<String> dynamicList = Stream.of("Apple", "Banana", "Cherry").collect(Collectors.toList());

dynamicList.add("Date");  // 添加成功

转载:小哈学Java


http://www.kler.cn/a/418482.html

相关文章:

  • LWIP和FATFS 实现 FTP 服务端
  • 多线程篇-8--线程安全(死锁,常用保障安全的方法,安全容器,原子类,Fork/Join框架等)
  • 内网穿透步骤
  • Maya 中创建游戏角色的头发,并将其导出到 Unreal Engine 5
  • 【QNX+Android虚拟化方案】127 - QNX侧 uart 读写程序分析
  • 全面解读权限控制与RBAC模型在若依中的实现
  • 云原生周刊:K8s 严重漏洞
  • AI智能体与代理IP:携手共创智能网络新时代
  • ts解决vite unplugin-auto-import/vite
  • 【自动化】配置信息抽取
  • C#VB.NET开发整体一键国际化显示
  • 银河麒麟v4/v10 Ubuntu上添加服务过程-以编译postgressql数据库为例
  • 【论文复现】基于BERT的语义分析实现
  • 深度转点云 点云着色
  • springboot+jsp二级页面无法请求
  • NLP 的研究任务
  • c++类和对象(2)
  • 前端http,ws拉流播放视频
  • 多种平台上安装部署调试Open5GS(二)
  • 嵌入式C语言技巧11:当系统崩溃遇上断电危机:如何确保嵌入式系统的绝对安全?
  • 杰发科技AC7803——不同晶振频率时钟的配置
  • 五:OpenStack环境准备-compute node
  • 从web前端角度浅析网络安全
  • 【C++】—— 二叉搜索树
  • 网络安全分析
  • 如何确保数据库和Redis数据的一致性