先看再点赞,给自己一点思考的时间,微信搜索【沉默王二】关注这个靠才华苟且的程序员。
本文 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,都是不可修改的。

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

来看一下使用方法:

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

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

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

运行后会抛出 UnsupportedOperationException 异常:

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。先来看一下源码:

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

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

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 语句对参数的个数进行了判断,然后调用不同的重载方法:

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 的。

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

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

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

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

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 依赖。

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

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

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

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

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

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

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

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

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() 方法类似,同样有很多相同签名的重载方法,使用方法也完全类似:

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

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

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 进行修改,从而影响到包装器,来看下面的示例:

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

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

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

System.out.println(iList);

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

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

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

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

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

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

System.out.println(iList);

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

[沉默王二]

这是因为 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. vue全家桶(2.2)

    3.3.router-link配置 3.3.1.实例 需求:实现下面效果,点击不同的菜单,显示不同的文字 核心代码:App组件 <template> <div id="ap ...

  2. List<List<Object>> list = new ArrayList<List<Object>>(); 求回答补充问题 list.get(position).add(Object);为什么会报错啊我想在对应的list里面添加对象

    public static void main(String[] args){ List<List<Object>> list = new ArrayList<List& ...

  3. 关于线上一次DDOS攻击和阿里云DDOS防护相关内容

    问题 最近我们的一台阿里云服务器 (ECS,有公网IP,Nginx 服务器,开放了80,443),遭受到了DDOS攻击,主要攻击的行为是 攻击我们443 端口.发起大量的请求. 但是我们在 Nginx ...

  4. zookeeper 伪集群安装和 zkui管理UI配置

    #=======================[VM机器,二进制安装] # 安装环境# OS System = Linux CNT7XZKPD02 4.4.190-1.el7.elrepo.x86_ ...

  5. JavaScript图形实例:递归生成树

    观察自然界中树的分叉,一根主干生长出两个侧干,每个侧干又长出两个侧干,以此类推,便生长出疏密有致的结构.这样的生长结构,使用递归算法可以模拟出来. 例如,分叉的侧干按45°的偏转角度进行生长的递归示意 ...

  6. SCOI 2009 围豆豆(状压DP)

    SCOI 2009 围豆豆 题目描述 是不是平时在手机里玩吃豆豆游戏玩腻了呢?最近MOKIA手机上推出了一种新的围豆豆游戏,大家一起来试一试吧. 游戏的规则非常简单,在一个N×M的矩阵方格内分布着D颗 ...

  7. Fetch.ai的突破使急速闪电共识成为现实

    Jonathan Ward 区块链的终结问题是由于技术限制,它已经成为区块链技术被广泛采用的障碍.用外行的话来说,终结时间可以看作是事务首次提交到网络并被确认为有效之间的等待时间.为了成功地革新我们的 ...

  8. day53 html收尾

    目录 一.解决浮动带来的影响 二.溢出属性 三.定位 四.验证浮动和定位是否脱离文档流 五.z-index模态框 六.透明度opacity 七.js简介 一.解决浮动带来的影响 块级标签内的浮动如果该 ...

  9. Elasticsearch 内存配置应用案例

    Elasticsearch 内存配置 有三个可选项: 你主要做全文检索吗?考虑给 Elasticsearch 4 - 32 GB 的内存, 让 Lucene 通过操作系统文件缓存来利用余下的内存.那些 ...

  10. JVM 专题一:虚拟机(一)

    1. 虚拟机 1.1 什么是虚拟机? 虚拟机(Virtual Machine)指通过软件模拟的具有完整硬件系统功能的.运行在一个完全隔离环境中的完整计算机系统. 所谓虚拟机,就是一台虚拟的计算机.它是 ...