[Guava源码日报](8)ImmutableCollection

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/71080164 不可变集合,顾名思义就是说集合是不可被修改的。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SunnyYoona/article/details/71080164

不可变集合,顾名思义就是说集合是不可被修改的。集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变。

1. UnmodifiableXXX

JDK提供了UnmodifiableXXX(Collections.unmodifiable)用于生成不可变容器。不可变容器无法修改返回容器的内容。但是这里值的是无法通过set或add方法修改容器内的reference的指向,而不是禁止reference指向内容的修改。

public static void test1(){
        List<User> list = Lists.newArrayList(new User());
        list.get(0).setName("yoona");
        list.get(0).setCompany("quanr");
        List<User> unmodifiableList = Collections.unmodifiableList(list);
        System.out.println(unmodifiableList.get(0).getName()); //yoona
        unmodifiableList.get(0).setName("sjf");
        //unmodifiableList.add(new User());
        //unmodifiableList.remove(0);
        System.out.println(unmodifiableList.get(0).getName()); //sjf
}

Collections.unmodifiableXXX返回的是原容器的视图。虽然无法对返回容器进行修改,但是对原容器的修改,会影响返回容器的内容。

容器内容的变更也会通过视图展现出来:

public static void test2(){
        User user = new User();
        user.setName("yoona");
        user.setCompany("quanr");
        List<User> list = Lists.newArrayList(user);
        List<User> unmodifiableList = Collections.unmodifiableList(list);
        // 对原容器的修改
        User user2 = new User();
        user2.setName("sjf");
        list.add(user2);
        // 影响返回容器
        System.out.println(unmodifiableList.get(1).getName()); //sjf
    }

2. ImmutableXXX

2.1 说明

(1)提供了不可修改容器的功能,保证返回的容器不能被调用者修改,并且原容器的修改也不会影响ImmutableXXX。这一点与UnmodifiableXXX不同。

(2)对不可靠的客户代码来说,它使用安全,可以在未受信任的类库中安全的使用这些对象。

(3)线程安全的,Immutable对象在多线程下安全,没有竟态条件。

(4)不需要支持可变性,可以尽量节省空间和时间的开销。所有的不可变集合实现都比可变集合更加有效的利用内存。

(5)可以被使用为一个常量,并且期望在未来也是保持不变的。

2.2 原理

返回的对象不是原容器的视图,而是原容器的一份拷贝。

public static final void test1(){
        User user = new User();
        user.setName("Yoona");
        List<User> list = Lists.newArrayList(user);
        ImmutableList<User> immutableList = ImmutableList.copyOf(list);
        User user2 = new User();
        user2.setName("sjf");
        list.add(user2);
        System.out.println(immutableList.size()); // 1
    }

3.源码

3.1 Builder
public abstract static class Builder<E> {
        static final int DEFAULT_INITIAL_CAPACITY = 4;
        /**
         * 扩容
         * @param oldCapacity
         * @param minCapacity
         * @return
         */
        static int expandedCapacity(int oldCapacity, int minCapacity) {
            if (minCapacity < 0) {
                throw new AssertionError("cannot store more than MAX_VALUE elements");
            }
            // careful of overflow!
            int newCapacity = oldCapacity + (oldCapacity >> 1) + 1;
            if (newCapacity < minCapacity) {
                newCapacity = Integer.highestOneBit(minCapacity - 1) << 1;
            }
            if (newCapacity < 0) {
                newCapacity = Integer.MAX_VALUE;
            }
            return newCapacity;
        }
        Builder() {
        }
        /**
         * 这是一个抽象方法,添加元素到集合中,具体怎么添加取决于是什么样的集合。具体的实现由ImmutableCollection子类实现
         * @param element 待添加的元素
         * @throws  element为null 抛出空指针异常
         */
        public abstract Builder<E> add(E element);
        /**
         * 使用了可变长参数,添加多个element元素到集合中。
         * 每个生成器类重写此方法,以返回其自己的类型。
         * @param elements
         * @throws 如果elements为null,或者包含一个元素为null都会抛出空指针异常
         */
        public Builder<E> add(E... elements) {
            for (E element : elements) {
                add(element);
            }
            return this;
        }
        /**
         * 使用了迭代器Iterable,添加Iterable中的element元素到集合中。
         * 每个生成器类重写此方法,以返回其自己的类型。
         * @param elements
         * @throws 如果elements为null,或者包含一个元素为null都会抛出空指针异常
         */
        public Builder<E> addAll(Iterable<? extends E> elements) {
            for (E element : elements) {
                add(element);
            }
            return this;
        }
        /**
         * 使用了迭代器Iterator,添加Iterator中的element元素到集合中。
         * 每个生成器类重写此方法,以返回其自己的类型。
         * @param elements
         * @throws 如果elements为null,或者包含一个元素为null都会抛出空指针异常
         */
        public Builder<E> addAll(Iterator<? extends E> elements) {
            while (elements.hasNext()) {
                add(elements.next());
            }
            return this;
        }
        /**
         * 抽象方法,由具体实现类返回相应类型的ImmutableCollection
         * @return
         */
        public abstract ImmutableCollection<E> build();
    }
3.2 copyIntoArray(Object[] dst,int offset)

复制不可变集合中内容到指定数组dst的指定位置offset。返回最新的偏移量。

int copyIntoArray(Object[] dst, int offset) {
    for (E e : this) {
      dst[offset++] = e;
    }
    return offset;
  }
3.3 Object[] toArray()

不可变集合转变为Object数组。如果不可变集合的长度为0,返回一个空的Object数组。

Object[] EMPTY_ARRAY = new Object[0];

如果不可变集合的长度不为0,使用上面提到的copyIntoArray()函数拷贝到一个新的Object数组。

public final Object[] toArray() {
    int size = size();
    if (size == 0) {
      return ObjectArrays.EMPTY_ARRAY;
    }
    Object[] result = new Object[size];
    copyIntoArray(result, 0);
    return result;
  }
3.4 boolean add(E e)

当试图为一个不可变集合添加元素时,抛出UnsupportedOperationException异常,表示不可变集合不支持添加元素操作,从而保证集合的不可修改性。

public final boolean add(E e) {
    throw new UnsupportedOperationException();
  }
3.5 boolean remove(Object object)

当试图从一个不可变集合删除元素时,抛出UnsupportedOperationException异常,表示不可变集合不支持删除元素操作,从而保证集合的不可修改性。

@Deprecated
  @Override
  public final boolean remove(Object object) {
    throw new UnsupportedOperationException();
  }

同理,也不支持多个元素的添加与删除操作,都会抛出UnsupportedOperationException异常。

@Deprecated
  @Override
  public final boolean addAll(Collection<? extends E> newElements) {
    throw new UnsupportedOperationException();
  }
 @Deprecated
  @Override
  public final boolean removeAll(Collection<?> oldElements) {
    throw new UnsupportedOperationException();
  }
3.6 UnmodifiableIterator<E> iterator()

通过集合获取不可变性迭代器UnmodifiableIterator。这是一个抽象方法,具体实现看具体的继承类。

@Override
  public abstract UnmodifiableIterator<E> iterator();
3.7 ImmutableList<E> asList() 与 createAsList()

从集合得到不可变性链表ImmutableList,具体为啥在ImmutableCollection中写此方法还没明白。

public ImmutableList<E> asList() {
    ImmutableList<E> list = asList;
    return (list == null) ? (asList = createAsList()) : list;
  }
  ImmutableList<E> createAsList() {
    switch (size()) {
      case 0:
        return ImmutableList.of();
      case 1:
        return ImmutableList.of(iterator().next());
      default:
        return new RegularImmutableAsList<E>(this, toArray());
    }
  }
目录
相关文章
|
6月前
|
移动开发 前端开发 Java
nbcio-boot的flowable流程模型查询修正为按发布时间倒序
nbcio-boot的flowable流程模型查询修正为按发布时间倒序
47 1
|
XML 存储 Java
Maven复习题及其答案
1、什么是Maven?它的作用是什么? Maven是一个用于构建和管理Java项目的工具。它提供了一种简化项目构建过程的方式,通过定义项目的结构、依赖等,使得开发者可以更轻松地测试和部署项目。 2、Maven的核心概念是什么? Maven的核心概念包括POM、坐标、仓库、生命周期、插件、依赖管理。 3、什么是POM? POM是Maven项目的核心文件,它是Project Object Model(项目对象模型)的缩写。POM以XML格式编写,POM文件包含了项目的基本信息; 4、什么是坐标? 坐标是在Maven中用于唯一标识一个项目或依赖项的信息。它由三个部分组成:groupId、arti
145 1
|
6月前
|
安全 Java 程序员
火爆全网的Spring Security手册及源码笔记,在Github上标星103K
Spring Security 是一个基于 Spring AOP 和 Servlet 过滤器的安全框架,它提供了安全性方面的解决方案
|
人工智能 NoSQL Java
SpringBoot实战(十八):签到奖励实现方案
SpringBoot实战(十八):签到奖励实现方案
311 0
|
存储 SQL 移动开发
JDK8 新特性, stream流用起来有多爽 (结合案例详解--通透--讲清)
这是一期关于JDK8 新特性 Stream API 进阶使用的文章, 来帮助咱们经常写crud的朋友来简化开发, 可能你刚开始用的时候很抵触, 但是你用熟练了会觉得它真的爽.希望大家多多支持
190 0
|
JSON 前端开发 Java
💘10分钟,6个点,SpringBoot集成丝袜哥(Swagger)整的明明白白💘
相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟注释一样,经常会抱怨别人写的代码没有写注释,然而自己写起代码起来,最讨厌的,也是写注释。所以仅仅只通过强制来规范大家是不够的,随着时间推移,版本迭代,接口文档往往很容易就跟不上代码了。
269 0
💘10分钟,6个点,SpringBoot集成丝袜哥(Swagger)整的明明白白💘
|
IDE Java 开发工具
Github热度周排行第一,阿里Java规约插件开发之路曝光
10月14号,云栖大会研发效能专场,《阿里巴巴Java开发手册》IDE插件(包括PMD规则实现库)正式对外开源,并且迅速占领Github开源热度周排行榜第一的位置,作为项目组的一员,看到业界对该项目的关注及认可,发自内心的高兴。高兴之余,分享一下在整个过程中的一些心得体会。
4957 0
|
JSON 自然语言处理 Java
Java实现英汉词典API初版发布在Maven
基于ECDICT词典数据, 开发一个Java库实现词典接口, 发布到Maven主库. Publish Java library to provide English-to-Chinese dictionary API on Maven Central.
1456 0
|
Java API Android开发
IDEA中用好Lombok,撸码效率至少提升5倍
任何技术的出现都是为了解决某一类问题,如果在此基础上再建立奇技淫巧,不如回归Java本身,应该保持合理使用而不滥用。 Lombok的使用非常简单: 1)引入相应的maven包 <dependency>   <groupId>org.projectlombok</groupId>   <artifactId>lombok</artifactId>   <version>1.16.18</version>   <scope>provided</scope></dependency> Lombok的scope=provided,说明它只在编译阶段生效,不需要打入包中。
1071 0
guava_学习_00_资源帖
一、精选 1、Google Guava 官方教程       二、参考资源 1、Google Guava官方教程(中文版) 2、使用Guava编写优雅代码 3、Google guava工具类的介绍和使用
1174 0