如何进行Immutable List的原理分析

发布时间:2021-12-09 17:41:10 作者:柒染
来源:亿速云 阅读:240

这期内容当中小编将会给大家带来有关如何进行Immutable List的原理分析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

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

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

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

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

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

那 Immutable List 有什么好处呢?

那接下来,我们来看一下,如何创建 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 上进行了拷贝。

上述就是小编为大家分享的如何进行Immutable List的原理分析了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. 如何进行AGG的原理分析
  2. Immutable.js源码之List类型是什么

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

immutable list

上一篇:如何进行SparkSQL与Hive metastore Parquet转换的分析

下一篇:如何区分SAST、DAST和IAST

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》