基于版本:Guava 22.0

Wiki:Immutable collections

0. ImmutableCollection简介

类似于JDK的Collections.unmodifiableXXX,可以创建不可变集合,是一种防御式编程的体现。

1. 类图

这张类图也不完全,ImmutableCollection实际上有十几个子类

2. 设计思路

ImmutableCollection是继承于Collection的抽象类,将所有涉及到修改的方法全部设置为final(禁止子类重写),方法体是直接抛出UnsupportedOperationException。

这样就实现了禁止修改的语义。

随意举两个例子如下:

  /**
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
* @deprecated Unsupported operation.
*/
@CanIgnoreReturnValue
@Deprecated
@Override
public final boolean add(E e) {
throw new UnsupportedOperationException();
} /**
* Guaranteed to throw an exception and leave the collection unmodified.
*
* @throws UnsupportedOperationException always
* @deprecated Unsupported operation.
*/
@CanIgnoreReturnValue
@Deprecated
@Override
public final boolean remove(Object object) {
throw new UnsupportedOperationException();
}

但是如何初始化ImmutableCollection呢?

a. ImmutableCollection的子类都实现了of与copyOf方法,通过这两个方法可以直接获取ImmutableCollection的实例。

b. ImmutableCollection.Builder提供了更加方便的构造器,ImmutableCollection的子类通过实现ImmutableCollection.Builder的关键方法,可以创建ImmutableCollection的实例。

3. ImmutableList

简单分析一下ImmutableList的实现

  public static <E> ImmutableList<E> copyOf(Collection<? extends E> elements) {
if (elements instanceof ImmutableCollection) {
@SuppressWarnings("unchecked") // all supported methods are covariant
ImmutableList<E> list = ((ImmutableCollection<E>) elements).asList();
return list.isPartialView() ? ImmutableList.<E>asImmutableList(list.toArray()) : list;
}
return construct(elements.toArray());
}

这个copyOf方法是很有意思的:

如果发现传入的集合是ImmutableCollection,并且不是完全的集合(由subList这种方法创建的集合),则创建一个拷贝(不再保留对原集合的引用,如果原集合很大,可以减少内存泄漏的可能),如果是完全的集合,则直接返回它的引用。

  /**
* Returns an immutable list of the elements between the specified {@code
* fromIndex}, inclusive, and {@code toIndex}, exclusive. (If {@code
* fromIndex} and {@code toIndex} are equal, the empty immutable list is
* returned.)
*/
@Override
public ImmutableList<E> subList(int fromIndex, int toIndex) {
checkPositionIndexes(fromIndex, toIndex, size());
int length = toIndex - fromIndex;
if (length == size()) {//直接返回整个引用
return this;
} else if (length == 0) {
return of();//返回EMPTY
} else {
return subListUnchecked(fromIndex, toIndex);//创建subList
}
} /**
* Called by the default implementation of {@link #subList} when {@code
* toIndex - fromIndex > 1}, after index validation has already been
* performed.
*/
ImmutableList<E> subListUnchecked(int fromIndex, int toIndex) {
return new SubList(fromIndex, toIndex - fromIndex);//限定subList的范围
} class SubList extends ImmutableList<E> {
final transient int offset;
final transient int length; SubList(int offset, int length) {
this.offset = offset;
this.length = length;
} @Override
public int size() {
return length;
} @Override
public E get(int index) {//转换下标,从原list的对应位置取值
checkElementIndex(index, length);
return ImmutableList.this.get(index + offset);
} @Override
public ImmutableList<E> subList(int fromIndex, int toIndex) {
checkPositionIndexes(fromIndex, toIndex, length);
return ImmutableList.this.subList(fromIndex + offset, toIndex + offset);
} @Override
boolean isPartialView() {//标注这是一个不完整的集合
return true;
}
}

ImmutableList.subList方法的实现,没有创建ImmutableList的副本,而是直接访问原ImmutableList中的元素,当然中间会进行下标的转换。

由于ImmutableList是不可变的,所以这样做是非常安全的,而且节省了开销。

4. 与Collections.unmodifiableXXX的区别

  • unwieldy and verbose; unpleasant to use everywhere you want to make defensive copies

  • unsafe: the returned collections are only truly immutable if nobody holds a reference to the original collection

  • inefficient: the data structures still have all the overhead of mutable collections, including concurrent modification checks, extra space in hash tables, etc.

直接引用并发编程网的翻译如下

  • 笨重而且累赘:不能舒适地用在所有想做防御性拷贝的场景;

  • 不安全:要保证没人通过原集合的引用进行修改,返回的集合才是事实上不可变的;

  • 低效:包装过的集合仍然保有可变集合的开销,比如并发修改的检查、散列表的额外空间,等等。

Guava源码学习(三)ImmutableCollection的更多相关文章

  1. mybatis源码学习(三)-一级缓存二级缓存

    本文主要是个人学习mybatis缓存的学习笔记,主要有以下几个知识点 1.一级缓存配置信息 2.一级缓存源码学习笔记 3.二级缓存配置信息 4.二级缓存源码 5.一级缓存.二级缓存总结 1.一级缓存配 ...

  2. Vue源码学习三 ———— Vue构造函数包装

    Vue源码学习二 是对Vue的原型对象的包装,最后从Vue的出生文件导出了 Vue这个构造函数 来到 src/core/index.js 代码是: import Vue from './instanc ...

  3. Guava源码学习(五)EventBus

    基于版本:Guava 22.0 Wiki:EventBus 0. EventBus简介 提供了发布-订阅模型,可以方便的在EventBus上注册订阅者,发布者可以简单的将事件传递给EventBus,E ...

  4. spring源码学习(三)--spring循环引用源码学习

    在spring中,是支持单实例bean的循环引用(循环依赖)的,循环依赖,简单而言,就是A类中注入了B类,B类中注入了A类,首先贴出我的代码示例 @Component public class Add ...

  5. [spring源码学习]三、IOC源码——自定义配置文件读取

    一.环境准备 在文件读取的时候,第9步我们发现spring会根据标签的namespace来选择读取方式,联想spring里提供的各种标签,比如<aop:xxx>等应该会有不同的读取和解析方 ...

  6. Guava源码学习(二)Ordering

    基于版本:Guava 22.0 Wiki:Ordering 0. Ordering简介 Guava的Ordering提供了链式风格的比较器的实现,我们可以用Ordering轻松构建复杂的比较器. 1. ...

  7. Guava源码学习(零)前言

    Guava是由Google出品的Java类库,功能强大且易用. 后续我会用多篇博客介绍Guava的使用方法,以及从源码层面分析其实现原理. 分析次序基于Guava的官方Wiki 基于版本:Guava ...

  8. vue 源码学习三 vue中如何生成虚拟DOM

    vm._render 生成虚拟dom 我们知道在挂载过程中, $mount 会调用 vm._update和vm._render 方法,vm._updata是负责把VNode渲染成真正的DOM,vm._ ...

  9. Guava源码学习(一)Optional

    基于版本:Guava 22.0 Wiki:Using and avoiding null 0:Optional简介 null在很多场景下会引发问题,NullPointerException困扰过无数的 ...

随机推荐

  1. Robocopy.exe使用详例

    Robocopy.exe使用详例           Robocopy.exe 是 微软在Windows server 2003 Resource Kit Tools 里面提供的程序来做备份的.Vis ...

  2. js限制文本框只能输入特定字符

    限制只能输入数字 // ---------------------------------------------------------------------- // <summary> ...

  3. eclipse里导入maven项目有红叉的解决办法

    导入maven的项目上有红叉,说明eclipse里maven的插件该更新了 1.help里选择install new software 2.点击add,输入name:MavenArchiver, lo ...

  4. Ext中关于Ext.QuickTips.init()的使用

    在extJS的例子中,大部分都在程序第一行使用了如下语句:Ext.QuickTips.init();但是QuickTips的用处是什么呢?我们看一段最简单的代码: <html> <h ...

  5. HDU 4436 str2int (后缀自动机)

    把所有的字符串连接起来,中间用一个未出现的字符分隔开,题意是求这个串的所有子串(中间不含分隔符)形成的数之和. 把这个串加入SAM,对所有子串进行拓扑排序,从前往后统计. 记录到达这个节点的路径个数c ...

  6. Android记事本08

    昨天: Anr问题异常的原因和解决方案. 今天: Activity数据传递之通用方式. Activity数据传递之静态变量. Activity数据传递之全局变量. 遇到的问题: 无.

  7. JS计算器(自制)

    <!doctype html><html><header><meta charset="utf-8"><script src= ...

  8. POJ 3177 Redundant Paths 无向图边双联通基础题

    题意: 给一个无向图,保证任意两个点之间有两条完全不相同的路径 求至少加多少边才能实现 题解: 得先学会一波tarjan无向图 桥的定义是:删除这条边之后该图不联通 一条无向边(u,v)是桥,当且仅当 ...

  9. IE6对!important单个的类是支持的

    "!important"是什么? 第一个,是设置样式的优先级,设了!important的样式的属性优先于id选择器和class选择器.,比如id为"Main"的 ...

  10. 《c程序设计语言》读书笔记-4.12-递归整数转字符串

    #include <stdio.h> #include <math.h> #include <stdlib.h> void itoa_num(int n, char ...