先看再点赞,给自己一点思考的时间,微信搜索【沉默王二】关注这个靠才华苟且的程序员。
本文 GitHub github.com/itwanger 已收录,里面还有一线大厂整理的面试题,以及我的系列文章。

Immutable List,顾名思义,就是,啥,不明白 Immutable 是什么意思?一成不变的意思,所以 Immutable List 就是一个不可变的 List 类,这意味着该 List 声明后,它的内容就是固定的,不可增删改的。

如果对不可变类比较陌生的话,可以先点击下面的链接查看我之前写的另外一篇文章。

这次要说不明白immutable类,我就怎么地

如果尝试对 List 中的元素进行增加、删除或者更新,就会抛出 UnsupportedOperationException 异常。

另外,Immutable List 中的元素是非 null 的,如果使用 null 来创建 Immutable List,则会抛出 NullPointerException;如果尝试在 Immutable List 中添加 null 元素,则会抛出 UnsupportedOperationException。

那 Immutable List 有什么好处呢?

  • 它是线程安全的;
  • 它是高效的;
  • 因为它是不可变的,就可以像 String 一样传递给第三方类库,不会发生任何安全问题。

那接下来,我们来看一下,如何创建 Immutable List。注意,源码是基于 JDK14 的。

01、借助原生 JDK

Collections 类的 unmodifiableList() 方法可以创建一个类似于 Immutable List 的 UnmodifiableList 或者 UnmodifiableRandomAccessList,都是不可修改的。

  1. public static <T> List<T> unmodifiableList(List<? extends T> list) {
        return (list instanceof RandomAccess ?
                new Collections.UnmodifiableRandomAccessList<>(list) :
                new Collections.UnmodifiableList<>(list));
    }

来看一下使用方法:

  1. List<String> list = new ArrayList<>(Arrays.asList("沉默王二", "沉默王三", "沉默王四"));
    List<String> unmodifiableList = Collections.unmodifiableList(list);

我们尝试往 unmodifiableList 中添加元素“沉默王五”:

  1. unmodifiableList.add("沉默王五");

运行后会抛出 UnsupportedOperationException 异常:

  1. Exception in thread "main" java.lang.UnsupportedOperationException
        at java.base/java.util.Collections$UnmodifiableCollection.add(Collections.java:1062)
        at com.cmower.mkyong.immutablelist.ImmutableListDemo.main(ImmutableListDemo.java:16)

02、借助 Java 9

Java 9 的时候,List 类新增了一个 of() 静态工厂方法,可以用来创建不可变的 List。先来看一下源码:

  1. static <E> List<E> of(E e1, E e2, E e3) {
        return new ImmutableCollections.ListN<>(e1, e2, e3);
    }

of() 方法有很多变体,比如说:

  1. static <E> List<E> of(E e1) {
            return new ImmutableCollections.List12<>(e1);
        }
    static <E> List<E> of(E e1, E e2) {
            return new ImmutableCollections.List12<>(e1, e2);
        }
    static <E> List<E> of(E e1, E e2, E e3, E e4) {
        return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
    }
    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
    }
    static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
        return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
                e6, e7, e8, e9, e10);
    }

该方法的设计者也挺有意思的,of() 方法的参数,从 0 到 10 都有一个相同签名的重载方法。

甚至当参数是可变的时候,使用 switch 语句对参数的个数进行了判断,然后调用不同的重载方法:

  1. static <E> List<E> of(E... elements) {
        switch (elements.length) { // implicit null check of elements
            case 0:
                @SuppressWarnings("unchecked")
                var list = (List<E>) ImmutableCollections.ListN.EMPTY_LIST;
                return list;
            case 1:
                return new ImmutableCollections.List12<>(elements[0]);
            case 2:
                return new ImmutableCollections.List12<>(elements[0], elements[1]);
            default:
                return new ImmutableCollections.ListN<>(elements);
        }
    }

不管是 ImmutableCollections.List12 还是 ImmutableCollections.ListN,它们都是 final 的,并且继承了 AbstractImmutableList,里面的元素也是 final 的。

  1. static final class List12<E> extends ImmutableCollections.AbstractImmutableList<E>
            implements Serializable {

        @Stable
        private final E e0;

        @Stable
        private final E e1;
    }

    static final class ListN<E> extends ImmutableCollections.AbstractImmutableList<E>
            implements Serializable {

        // EMPTY_LIST may be initialized from the CDS archive.
        static @Stable List<?> EMPTY_LIST;

        static {
            VM.initializeFromArchive(ImmutableCollections.ListN.class);
            if (EMPTY_LIST == null) {
                EMPTY_LIST = new ImmutableCollections.ListN<>();
            }
        }

        @Stable
        private final E[] elements;
    }

好了,来看一下使用方法吧:

  1. final List<String> unmodifiableList = List.of("沉默王二", "沉默王三", "沉默王四");
    unmodifiableList.add("沉默王五");

ImmutableCollections 的内部类 ListN 或者 List12 同样不可修改,使用 add() 方法添加元素同样会在运行时抛出异常:

  1. Exception in thread "main" java.lang.UnsupportedOperationException
        at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:73)
        at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:77)
        at com.cmower.mkyong.immutablelist.ImmutableListDemo.main(ImmutableListDemo.java:20)

03、借助 Guava

Guava 工程包含了若干被 Google 的 Java 项目广泛依赖的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 所有这些工具每天都在被 Google 的工程师应用在产品服务中。

在实际的项目实战当中,Guava 类库的使用频率真的蛮高的,因此我们需要在项目中先引入 Guava 的 Maven 依赖。

  1. <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>28.1-jre</version>
    </dependency>

Guava 定了一个 ImmutableList 类,它的声明方式如下所示:

  1. @GwtCompatible(serializable = true, emulated = true)
    @SuppressWarnings("serial") // we're overriding default serialization
    public abstract class ImmutableList<E> extends ImmutableCollection<E>
        implements List<E>, RandomAccess {
    }

它的类结构关系如下所示:

  1. java.lang.Object
       java.util.AbstractCollection
           com.google.common.collect.ImmutableCollection
               com.google.common.collect.ImmutableList

ImmutableList 类的 copyOf() 方法可用于创建一个不可变的 List 对象:

  1. List<String> list = new ArrayList<>(Arrays.asList("沉默王二", "沉默王三", "沉默王四"));
    List<String> unmodifiableList = ImmutableList.copyOf(list);
    unmodifiableList.add("沉默王五");

ImmutableList 同样不允许添加元素,add() 方法在执行的时候会抛出 UnsupportedOperationException 异常:

  1. Exception in thread "main" java.lang.UnsupportedOperationException
        at com.google.common.collect.ImmutableCollection.add(ImmutableCollection.java:244)
        at com.cmower.mkyong.immutablelist.ImmutableListDemo.main(ImmutableListDemo.java:25)

ImmutableList 类的 of() 方法和 Java 9 的 of() 方法类似,同样有很多相同签名的重载方法,使用方法也完全类似:

  1. List<String> unmodifiableList = ImmutableList.of("沉默王二", "沉默王三", "沉默王四");

ImmutableList 类还提供了 builder 模式,既可以在创建的时候添加元素,也可以基于已有的 List 创建,还可以将两者混合在一起。

  1. ImmutableList<String> iList = ImmutableList.<String>builder()
            .add("沉默王二", "沉默王三", "沉默王四")
            .build();

    List<String> list = List.of("沉默王二", "沉默王三", "沉默王四");
    ImmutableList<String> iList = ImmutableList.<String>builder()
            .addAll(list)
            .build();

    List<String> list = List.of("沉默王二", "沉默王三", "沉默王四");
    ImmutableList<String> iList = ImmutableList.<String>builder()
            .addAll(list)
            .add("沉默王五")
            .build();

04、Collections.unmodifiableList() 和 ImmutableList 有什么区别?

Collections.unmodifiableList() 基于原有的 List 创建了一个不可变的包装器,该包装器是不可修改的,但是,我们可以通过对原有的 List 进行修改,从而影响到包装器,来看下面的示例:

  1. List<String> list = new ArrayList<>();
    list.add("沉默王二");

    List<String> iList = Collections.unmodifiableList(list);

    list.add("沉默王三");
    list.add("沉默王四");

    System.out.println(iList);

程序输出的结果如下所示:

  1. [沉默王二, 沉默王三, 沉默王四]

但如果我们通过 ImmutableList 类创建一个不可变 List,原有 List 的改变并不会影响到 ImmutableList。

  1. List<String> list = new ArrayList<>();
    list.add("沉默王二");

    ImmutableList<String> iList = ImmutableList.copyOf(list);

    list.add("沉默王三");
    list.add("沉默王四");

    System.out.println(iList);

程序输出的结果如下所示:

  1. [沉默王二]

这是因为 ImmutableList 是在原有的 List 上进行了拷贝。


我是沉默王二,一枚有颜值却靠才华苟且的程序员。关注即可提升学习效率,别忘了三连啊,点赞、收藏、留言,我不挑,奥利给

注:如果文章有任何问题,欢迎毫不留情地指正。

如果你觉得文章对你有些帮助欢迎微信搜索「沉默王二」第一时间阅读,回复「小白」更有我肝了 4 万+字的 Java 小白手册 2.0 版,本文 GitHub github.com/itwanger 已收录,欢迎 star。

给我半首歌的时间,给你说明白Immutable List的更多相关文章

  1. [zt]给你的Mp4大换血,精选Touch里3年收集的900多首歌,"经典不忍去的""最新近流行的",与你共享~~

    如果你是音乐爱好者: 这些歌, 请戴上耳机, 调大音量, 一个人听 ,全世界 都是你的!!!!! (一)这些歌很温暖,没有金属味,适合有阳光的午后,很悠闲... [Anaesthesia]Maximi ...

  2. Oracle中获取当前时间半小时前的时间

    最近项目中有个要根据半个小时前的数据情况判断某一栏位的值,但是一直没想到怎样获取当前时间的半小时前的时间,今天突然想到可以通过sysdate做差来获取,比如sysdate-1这样的,刚开始没有对结果进 ...

  3. 09、 在QQ音乐中查找七里香这首歌的精彩评论

       找到七里香这首歌的精彩评论      URL https://c.y.qq.com/base/fcgi-bin/fcg_global_comment_h5.fcg?g_tk=5381&l ...

  4. SICAU-OJ:要我唱几首歌才能够将你捕捉

    要我唱几首歌才能够将你捕捉 题意: 有N种颜色的牛,现在可以执行以下两种操作: 1.抓捕一只牛,代价为ai: 2.花费x的代价使用魔法,让所有颜色加1,N会变为1. 求得到N种颜色的牛最少花费的代价. ...

  5. BUUCTF-来首歌吧

    来首歌吧 歌曲题目一般就是整个摩斯电码 看上面的样子应该就是摩斯电码解密一下 ..... -... -.-. ----. ..--- ..... -.... ....- ----. -.-. -... ...

  6. mysql客户首末单时间 group by用法_20160927

    一.取用户第一次下单时间 SELECT city,username,`order_date` AS 首单日期,金额 AS 首单金额 FROM ( SELECT city,username,`order ...

  7. python 虾米停服了...用python爬取虾米最近播放的1000首歌

    1. 虾米关服 在这里插入图片描述 用了5年多的音乐软件就这么说关就关了,确实让人心里不好受 ,虽然再去一个新的app里,让它们的算法熟悉你的喜好也不是很困难,可我还是习惯虾米的界面.虾米现在可以支持 ...

  8. 如何使用webpack优化首屏渲染时间

    其实说到性能优化,他的范围太广了,今天我们就只聊一聊通过webpack配置减少http请求数量这个点吧. 简单说下工作中遇到的问题吧,我们做的一个项目中首页用了十多张图片,每张图片都是一个静态资源,所 ...

  9. 首屏渲染时间获取 performance.now()

    Performance — 前端性能监控利器   最近在写一个监控脚本,终于有机会接触到了这一块,整理后写下了本文.Performance是一个做前端性能监控离不开的API,最好在页面完全加载完成之后 ...

随机推荐

  1. mybatis源码配置文件解析之五:解析mappers标签(解析XML映射文件)

    在上篇文章中分析了mybatis解析<mappers>标签,<mybatis源码配置文件解析之五:解析mappers标签>重点分析了如何解析<mappers>标签中 ...

  2. 高速缓存一致性协议MESI与内存屏障

    一.CPU高速缓存简单介绍 CPU高速缓存机制的引入,主要是为了解决CPU越来越快的运行速度与相对较慢的主存访问速度的矛盾.CPU中的寄存器数量有限,在执行内存寻址指令时,经常需要从内存中读取指令所需 ...

  3. go实现爬虫

    条件:1.第三方包github.com/tebeka/selenium,selenium自动化测试工具2.google驱动chromedriver.exe,要与本地浏览器的版本号对应,下载:http: ...

  4. Caocao's Bridges HDU - 4738 求桥

    题目描述 Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn't give up. ...

  5. docker自动化部署前端项目实战一

    docker自动化部署前端项目实战一 本文适用于个人项目,如博客.静态文档,不涉及后台数据交互,以部署文档为例. 思路 利用服务器node脚本,监听github仓库webhook push事件触发po ...

  6. input函数报错"*** is not defined"

    #键盘输入输出name = input('input your name: ') print("姓名:"+name) 运行结果: 只需要在输入时加引号,如"yu" ...

  7. mysql 存储引擎的选择

    MyISAM:如果应用是以读操作和插入操作为主,只有很少的更新和删除操作,并且对事务的完整性.并发性要求不是很高,选择这个存储引擎非常合适.MyISAM在Web.数据仓储和其他应用环境下最常使用的存储 ...

  8. python面试题六: 剑指offer

    面试题3 二维数组中的查找 LeetCode题目:二维数组中,每行从左到右递增,每列从上到下递增,给出一个数,判断它是否在数组中思路:从左下角或者右上角开始比较 def find_integer(ma ...

  9. 数据可视化基础专题(七):Pandas基础(六) 数据增删改以及相关操作

    首先第一部还是导入 Pandas 与 NumPy ,并且要生成一个 DataFrame ,这里小编就简单的使用随机数的形式进行生成,代码如下: import numpy as np import pa ...

  10. IDEA搭建SpringMVC简单接口框架(Maven项目)

    1, 新建项目,选择Maven,如图一次选择,最后点击Next 2, 输入GroupId和ArtifactId,点击Next 3,根据需要选择自定义maven配置,点击Next.(①可以直接跳过) 4 ...