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

  为什么要用immutable对象?immutable对象有以下的优点:
    1.对不可靠的客户代码库来说,它使用安全,可以在未受信任的类库中安全的使用这些对象
    2.线程安全的:immutable对象在多线程下安全,没有竞态条件
    3.不需要支持可变性, 可以尽量节省空间和时间的开销. 所有的不可变集合实现都比可变集合更加有效的利用内存 (analysis)
    4.可以被使用为一个常量,并且期望在未来也是保持不变的

  immutable对象可以很自然地用作常量,因为它们天生就是不可变的对于immutable对象的运用来说,它是一个很好的防御编程(defensive programming)的技术实践。

  JDK中实现immutable集合

  在JDK中提供了Collections.unmodifiableXXX系列方法来实现不可变集合, 但是存在一些问题,下面我们先看一个具体实例:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Test; public class ImmutableTest {
@Test
public void testJDKImmutable(){
List<String> list=new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c"); System.out.println(list); List<String> unmodifiableList=Collections.unmodifiableList(list); System.out.println(unmodifiableList); List<String> unmodifiableList1=Collections.unmodifiableList(Arrays.asList("a","b","c"));
System.out.println(unmodifiableList1); String temp=unmodifiableList.get(1);
System.out.println("unmodifiableList [0]:"+temp); list.add("baby");
System.out.println("list add a item after list:"+list);
System.out.println("list add a item after unmodifiableList:"+unmodifiableList); unmodifiableList1.add("bb");
System.out.println("unmodifiableList add a item after list:"+unmodifiableList1); unmodifiableList.add("cc");
System.out.println("unmodifiableList add a item after list:"+unmodifiableList);
}
}

  输出:

[a, b, c]
[a, b, c]
[a, b, c]
unmodifiableList [0]:b
list add a item after list:[a, b, c, baby]
list add a item after unmodifiableList1:[a, b, c, baby]

  说明:Collections.unmodifiableList实现的不是真正的不可变集合,当原始集合修改后,不可变集合也发生变化。不可变集合不可以修改集合数据,当强制修改时会报错,实例中的最后两个add会直接抛出不可修改的错误。

  总结一下JDK的Collections.unmodifiableXXX方法实现不可变集合的一些问题:

  1.它用起来笨拙繁琐你不得不在每个防御性编程拷贝的地方用这个方法
  2.它不安全:如果有对象reference原始的被封装的集合类,这些方法返回的集合也就不是正真的不可改变。
  3.效率低:因为它返回的数据结构本质仍旧是原来的集合类,所以它的操作开销,包括并发下修改检查,hash table里的额外数据空间都和原来的集合是一样的。

  Guava的immutable集合

  Guava提供了对JDK里标准集合类里的immutable版本的简单方便的实现,以及Guava自己的一些专门集合类的immutable实现。当你不希望修改一个集合类,或者想做一个常量集合类的时候,使用immutable集合类就是一个最佳的编程实践。

注意:每个Guava immutable集合类的实现都拒绝null值。我们做过对Google内部代码的全面的调查,并且发现只有5%的情况下集合类允许null值,而95%的情况下都拒绝null值。万一你真的需要能接受null值的集合类,你可以考虑用Collections.unmodifiableXXX。

  Immutable集合使用方法:
  一个immutable集合可以有以下几种方式来创建:
  1.用copyOf方法, 譬如, ImmutableSet.copyOf(set)
  2.使用of方法,譬如,ImmutableSet.of("a", "b", "c")或者ImmutableMap.of("a", 1, "b", 2)
  3.使用Builder类

  实例:

@Test
public void testGuavaImmutable(){ List<String> list=new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
System.out.println("list:"+list); ImmutableList<String> imlist=ImmutableList.copyOf(list);
System.out.println("imlist:"+imlist); ImmutableList<String> imOflist=ImmutableList.of("peida","jerry","harry");
System.out.println("imOflist:"+imOflist); ImmutableSortedSet<String> imSortList=ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
System.out.println("imSortList:"+imSortList); list.add("baby");
System.out.println("list add a item after list:"+list);
System.out.println("list add a item after imlist:"+imlist); ImmutableSet<Color> imColorSet =
ImmutableSet.<Color>builder()
.add(new Color(0, 255, 255))
.add(new Color(0, 191, 255))
.build(); System.out.println("imColorSet:"+imColorSet);
}

  输出:

list:[a, b, c]
imlist:[a, b, c]
imOflist:[peida, jerry, harry]
imSortList:[a, b, c, d]
list add a item after list:[a, b, c, baby]
list add a item after imlist:[a, b, c]
imColorSet:[java.awt.Color[r=0,g=255,b=255], java.awt.Color[r=0,g=191,b=255]]

  对于排序的集合来说有例外,因为元素的顺序在构建集合的时候就被固定下来了。譬如,ImmutableSet.of("a", "b", "c", "a", "d", "b"),对于这个集合的遍历顺序来说就是"a", "b", "c", "d"。

  更智能的copyOf

  copyOf方法比你想象的要智能,ImmutableXXX.copyOf会在合适的情况下避免拷贝元素的操作-先忽略具体的细节,但是它的实现一般都是很“智能”的。譬如:

@Test
public void testCotyOf(){
ImmutableSet<String> imSet=ImmutableSet.of("peida","jerry","harry","lisa");
System.out.println("imSet:"+imSet);
ImmutableList<String> imlist=ImmutableList.copyOf(imSet);
System.out.println("imlist:"+imlist);
ImmutableSortedSet<String> imSortSet=ImmutableSortedSet.copyOf(imSet);
System.out.println("imSortSet:"+imSortSet); List<String> list=new ArrayList<String>();
for(int i=0;i<20;i++){
list.add(i+"x");
}
System.out.println("list:"+list);
ImmutableList<String> imInfolist=ImmutableList.copyOf(list.subList(2, 18));
System.out.println("imInfolist:"+imInfolist);
int imInfolistSize=imInfolist.size();
System.out.println("imInfolistSize:"+imInfolistSize);
ImmutableSet<String> imInfoSet=ImmutableSet.copyOf(imInfolist.subList(2, imInfolistSize-3));
System.out.println("imInfoSet:"+imInfoSet);
}

  输出: 

imSet:[peida, jerry, harry, lisa]
imlist:[peida, jerry, harry, lisa]
imSortSet:[harry, jerry, lisa, peida]
list:[0x, 1x, 2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x, 15x, 16x, 17x, 18x, 19x]
imInfolist:[2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x, 15x, 16x, 17x]
imInfolistSize:16
imInfoSet:[4x, 5x, 6x, 7x, 8x, 9x, 10x, 11x, 12x, 13x, 14x]

  在这段代码中,ImmutableList.copyOf(imSet)会智能地返回时间复杂度为常数的ImmutableSet的imSet.asList()。
  一般来说,ImmutableXXX.copyOf(ImmutableCollection)会避免线性复杂度的拷贝操作。如在以下情况:
  这个操作有可能就利用了被封装数据结构的常数复杂度的操作。但例如ImmutableSet.copyOf(list)不能在常数复杂度下实现。
  这样不会导致内存泄漏-例如,你有个ImmutableList<String> imInfolist,然后你显式操作ImmutableList.copyOf(imInfolist.subList(0, 10))。这样的操作可以避免意外持有不再需要的在hugeList里元素的reference。
  它不会改变集合的语意-像ImmutableSet.copyOf(myImmutableSortedSet)这样的显式拷贝操作,因为在ImmutableSet里的hashCode()和equals()的含义和基于comparator的ImmutableSortedSet是不同的。
  这些特性有助于最优化防御性编程的性能开销。

  asList方法

  所有的immutable集合都以asList()的形式提供了ImmutableList视图(view)。譬如,你把数据放在ImmutableSortedSet,你就可以调用sortedSet.asList().get(k)来取得前k个元素的集合。
  返回的ImmutableList常常是个常数复杂度的视图,而不是一个真的拷贝。也就是说,这个返回集合比一般的List更智能-譬如,它会更高效地实现contains这样的方法。

  实例:

@Test
public void testAsList(){
ImmutableList<String> imList=ImmutableList.of("peida","jerry","harry","lisa","jerry");
System.out.println("imList:"+imList);
ImmutableSortedSet<String> imSortList=ImmutableSortedSet.copyOf(imList);
System.out.println("imSortList:"+imSortList);
System.out.println("imSortList as list:"+imSortList.asList());
}

  输出:

imList:[peida, jerry, harry, lisa, jerry]
imSortList:[harry, jerry, lisa, peida]
imSortList as list:[harry, jerry, lisa, peida]

  Guava集合和不可变对应关系

可变集合类型 可变集合源:JDK or Guava? Guava不可变集合
Collection JDK ImmutableCollection
List JDK ImmutableList
Set JDK ImmutableSet
SortedSet/NavigableSet JDK ImmutableSortedSet
Map JDK ImmutableMap
SortedMap JDK ImmutableSortedMap
Multiset Guava ImmutableMultiset
SortedMultiset Guava ImmutableSortedMultiset
Multimap Guava ImmutableMultimap
ListMultimap Guava ImmutableListMultimap
SetMultimap Guava ImmutableSetMultimap
BiMap Guava ImmutableBiMap
ClassToInstanceMap Guava ImmutableClassToInstanceMap
Table Guava ImmutableTable

Guava学习笔记:Immutable(不可变)集合的更多相关文章

  1. [Guava学习笔记]Collections: 不可变集合, 新集合类型

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3843386.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  2. java代码之美(4)---guava之Immutable(不可变)集合

    Immutable(不可变)集合 一.概述 guava是google的一个库,弥补了java语言的很多方面的不足,很多在java8中已有实现,暂时不展开.Collections是jdk提供的一个工具类 ...

  3. [置顶] Guava学习之Immutable集合

    Immutable中文意思就是不可变.那为什么需要构建一个不可变的对象?原因有以下几点: 在并发程序中,使用Immutable既保证线程安全性,也大大增强了并发时的效率(跟并发锁方式相比).尤其当一个 ...

  4. java代码(4)---guava之Immutable(不可变)集合

    Immutable(不可变)集合   一,概述 guava是google的一个库,弥补了java语音的很多方面的不足,很多在java8中已有实现,暂时不展开,Collections是jdk提供的一个工 ...

  5. Guava学习笔记目录

    Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libra ...

  6. guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用

    guava 学习笔记(二) 瓜娃(guava)的API快速熟悉使用 1,大纲 让我们来熟悉瓜娃,并体验下它的一些API,分成如下几个部分: Introduction Guava Collection ...

  7. Immutable(不可变)集合

    Immutable(不可变)集合 不可变集合,顾名思义就是说集合是不可被修改的.集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变. 为什么要用immutable对象?immutable对 ...

  8. guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁

    guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁 1,本文翻译自 http://eclipsesource.com/blogs/2012/06/06/cleaner-code- ...

  9. SQL反模式学习笔记6 支持可变属性【实体-属性-值】

    目标:支持可变属性 反模式:使用泛型属性表.这种设计成为实体-属性-值(EAV),也可叫做开放架构.名-值对. 优点:通过增加一张额外的表,可以有以下好处 (1)表中的列很少: (2)新增属性时,不需 ...

  10. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

随机推荐

  1. C#并行编程-线程同步原语

    菜鸟学习并行编程,参考<C#并行编程高级教程.PDF>,如有错误,欢迎指正. 目录 C#并行编程-相关概念 C#并行编程-Parallel C#并行编程-Task C#并行编程-并发集合 ...

  2. fir.im Weekly - 2016 年 Android 最佳实践列表

    2016 年已经过去一半,你在年初制定的成长计划都实现了吗? 学海无涯,技术成长不是一簇而就的事情.本期 fir.im Weekly 推荐 王下邀月熊_Chevalier的 我的编程之路--知识管理与 ...

  3. salesforce 零基础学习(四十二)简单文件上传下载

    项目中,常常需要用到文件的上传和下载,上传和下载功能实际上是对Document对象进行insert和查询操作.本篇演示简单的文件上传和下载,理论上文件上传后应该将ID作为操作表的字段存储,这里只演示文 ...

  4. KnockoutJS 3.X API 第四章 数据绑定(2) 控制流foreach绑定

    foreach绑定 foreach绑定主要用于循环展示监控数组属性中的每一个元素,一般用于table标签中 假设你有一个监控属性数组,每当您添加,删除或重新排序数组项时,绑定将有效地更新UI的DOM- ...

  5. 快速入门系列--GIT版本控制工具

    由于GIT刚刚开始使用不久,经常会在Merge时出现没有change-id的情况,在结合gerrit使用时,经常出现不能提交的情形,使得自己很困扰.最近有次熬夜加班,在代码完成后,由于多人在很短时间内 ...

  6. 解决h5的video标签,android、ipad客户端播放正常,iphone客户端无法播放

    在做html5时插入一个视频播放标签video后,测试时android.ipad客户端播放正常,唯独iphone自带浏览器无法播放. 解决办法: 判断用户所使用客户端访问h5页面时是iphone时,点 ...

  7. SQL Server的小数数值类型(float 和 decimal)用法

    在SQL Server中,小数数值实际上只有两种数据类型:float 和 decimal.double precision 整体是数据类型,等价于 float(53),real等价于float(24) ...

  8. Oracle 11g系列:约束

    约束是每个数据库必不可少的一部分,约束的目的在于保存数据的完整性.数据完整性是指数据的精确性和可靠性.数据库约束主要包括:主键约束.外键约束.唯一性约束.检查约束和默认值约束. 1.主键约束 主键约束 ...

  9. poj 1386 Play on Words(有向图欧拉回路)

    /* 题意:单词拼接,前一个单词的末尾字母和后一个单词的开头字母相同 思路:将一个单词的开头和末尾单词分别做两个点并建一条有向边!然后判断是否存在欧拉回路或者欧拉路 再次强调有向图欧拉路或欧拉回路的判 ...

  10. NYOJ 99单词拼接(有向图的欧拉(回)路)

    /* NYOJ 99单词拼接: 思路:欧拉回路或者欧拉路的搜索! 注意:是有向图的!不要当成无向图,否则在在搜索之前的判断中因为判断有无导致不必要的搜索,以致TLE! 有向图的欧拉路:abs(In[i ...