Java容器——UnsupportedOperationException

Wesley13
• 阅读 558

    先看一个例子:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class UnsupportedOperation {
    static void test(String msg, List<String> list) {
        System.out.println("----------" + msg + "----------");
        Collection<String> c = list;
        Collection<String> subList = list.subList(1, 4);
        Collection<String> subList2 = new ArrayList<>(subList);
        try { c.retainAll(subList2); } catch (Exception e) {
            System.out.println("retainAll: " + e);
        }
        try { c.removeAll(subList2); } catch (Exception e) {
            System.out.println("removeAll: " + e);
        }
        try { c.clear(); } catch (Exception e) {
            System.out.println("clear: " + e);
        }
        try { c.add("X"); } catch (Exception e) {
            System.out.println("add: " + e);
        }
        try { c.addAll(subList2); } catch (Exception e) {
            System.out.println("addAll: " + e);
        }
        try { c.remove("C"); } catch (Exception e) {
            System.out.println("remove: " + e);
        }
        try { list.set(0, "W"); } catch (Exception e) {
            System.err.println("List.set: " + e);
        }
        System.out.println("List.className=" + list.getClass().getSimpleName());
    }
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A B C D E F G".split(" "));
        test("Modifiable Copy", new ArrayList<String>(list));
        test("Arrays.asList", list);
        test("Unmodifiable List", Collections.unmodifiableList(list));
    }
}

执行结果:

----------Modifiable Copy----------
List.className=ArrayList
----------Arrays.asList----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.className=ArrayList
----------Unmodifiable List----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.set: java.lang.UnsupportedOperationException
List.className=UnmodifiableRandomAccessList

    那么为什么会出现这样的结果呢?对于Unmodifiable的List不能做修改很好理解,但从结果中可以看到,同样是ArrayList,为什么Array.asList()返回的List就不能做修改呢?

    Arrays.asList()会生成一个List,它基于一个固定大小的数组,仅支持那些不会改变数组大小的操作,任何对引起底层数据结构的尺寸进行修改的方法都会产生一个UnsupportedOperationException异常,以表示对未获支持操作的调用。

    其实上面的代码中,我故意使用的是getSimpleName(),因为这个方法不会显示包名。如果我们将

System.out.println("List.className=" + list.getClass().getSimpleName());

    替换为:

System.out.println("List.className=" + list.getClass().getName());

    那么结果就是这样的了:

----------Modifiable Copy----------
List.className=java.util.ArrayList
----------Arrays.asList----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.className=java.util.Arrays$ArrayList
----------Unmodifiable List----------
retainAll: java.lang.UnsupportedOperationException
removeAll: java.lang.UnsupportedOperationException
clear: java.lang.UnsupportedOperationException
add: java.lang.UnsupportedOperationException
addAll: java.lang.UnsupportedOperationException
remove: java.lang.UnsupportedOperationException
List.className=java.util.Collections$UnmodifiableRandomAccessList
List.set: java.lang.UnsupportedOperationException

    可以看到,Arrays.asList返回的名字虽然叫ArrayList,但此ArrayList是Arrays中的一个内部类,而非java.util.ArrayList。

查看其源码,可以发现此Arrays.ArrayList内部类的声明如下:

private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable

    而该类的实现方法中,并没有实现修改E[]数组(增、删、清除等)的方法

Java容器——UnsupportedOperationException

    因此对这种对象调用这些方法时会调用其父类AbstractList的实现,于是就直接抛出了UnsupportedOperationException:

Java容器——UnsupportedOperationException

    因此,通常的做法是,把Arrays.asList()的结果作为构造方法的参数传递给任何Collection(或者使用addAll()方法或Collections.addAll()静态方法),这样就可以生成允许使用所有的方法的普通容器——这在main()中的第一个对test()的调用中得到了展示,这样的调用会产生新的尺寸可调的底层数据结构。Collections类的“不可修改”方法将容器包装到了一个代理中,只要你执行任何试图修改容器的操作,这个代理就会产生UnsupportedOperationException异常。使用这些方法的目标就是产生“常量”容器对象。

    test()中的最后一个try语句块将检查作为List的一部分set()方法。Arrays.asList()返回固定大小的List,而Collections.unmodifiableList()产生不可修改的列表。正如输出中看到的,修改Arrays.asList()返回的List中的元素是可以的,因为这没有违反“大小固定”这一特性。但很明显,unmodifiableList()的结果在任何情况下都是不可修改的。

--------------------------------------------------------------

像上述抛出异常的操作,在Java容器中被称为“未获支持的操作”。那么为什么会将方法定义为可选的呢?那是因为这样做可以防止在设计中出现接口爆炸的情况。为了让这种方式能工作:

    1. UnsupportedOperationException必须是一种罕见的事件。即,对于大多数类来说,所有操作都应该可以工作,只有在特例中才会有这类操作。在Java容器中也确实如此,因为你在99%的时间里使用的容器类,如ArrayList、LinkedList、HashSet和HashMap,以及其他的具体实现,都支持所有的操作。

    2. 如果一个操作是未获支持的,那么在实现接口的时候可能就会导致UnsupportedOperationException异常,而不是将产品交付给客户以后才出现此异常,这种情况是有道理的,毕竟,它表示编程上有错误:使用了不正确的接口实现。

    值得注意的是,这类操作只有在运行时才能探测到。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
java多线程读取、操作List集合
import java.util.ArrayList;import java.util.List;import org.apache.commons.lang3.ArrayUtils;public class Test_4 {/ 多线程处理list
Stella981 Stella981
2年前
POI导入大excel文件
package me.shanzhi.test;import java.io.InputStream;import java.util.ArrayList;import java.util.Iterator;import java.util.List;import org.apac
Wesley13 Wesley13
2年前
Excel导出工具类.
 Excel导出工具类.POIimport java.io.OutputStream;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.ArrayList;import java.uti
Stella981 Stella981
2年前
None of the configured nodes are available
1.今天写了一段ES的测试代码,如下:package elasticSearch;import java.net.InetSocketAddress;import java.util.ArrayList;import java.util.List;import java.util.M
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这