2019独角兽企业重金招聘Python工程师标准>>>

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

为什么要用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");//[a, b, c]System.out.println(list);List<String> unmodifiableList=Collections.unmodifiableList(list); //[a, b, c]System.out.println(unmodifiableList);List<String> unmodifiableList1=Collections.unmodifiableList(Arrays.asList("a","b","c")); //[a, b, c]System.out.println(unmodifiableList1);String temp=unmodifiableList.get(1);//unmodifiableList [0]:bSystem.out.println("unmodifiableList [0]:"+temp);list.add("baby");//list add a item after list:[a, b, c, baby]System.out.println("list add a item after list:"+list);//list add a item after unmodifiableList1:[a, b, c, baby]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);        }
}

说明: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");//list:[a, b, c]System.out.println("list:"+list);ImmutableList<String> imlist=ImmutableList.copyOf(list);//imlist:[a, b, c]System.out.println("imlist:"+imlist);ImmutableList<String> imOflist=ImmutableList.of("peida","jerry","harry");//imOflist:[peida, jerry, harry]System.out.println("imOflist:"+imOflist);ImmutableSortedSet<String> imSortList=ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");//imSortList:[a, b, c, d]System.out.println("imSortList:"+imSortList);list.add("baby");//list add a item after list:[a, b, c, baby]System.out.println("list add a item after list:"+list);//list add a item after imlist:[a, b, c]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();//imColorSet:[java.awt.Color[r=0,g=255,b=255], java.awt.Color[r=0,g=191,b=255]]System.out.println("imColorSet:"+imColorSet);       }

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

更智能的copyOf

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

@Testpublic 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这样的方法。

实例:

@Testpublic 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集合和不可变对应关系

转载于:https://my.oschina.net/heroShane/blog/199242

Guava学习笔记 第6个记录(Immutable(不可变)集合)相关推荐

  1. Guava学习笔记:简化异常处理的Throwables类

    Guava学习笔记:简化异常处理的Throwables类 参考文章: (1)Guava学习笔记:简化异常处理的Throwables类 (2)https://www.cnblogs.com/peida/ ...

  2. Guava学习笔记(转)

    Guava(瓜娃)学习笔记 Guava工程包含了若干被google的java项目广泛依赖的核心库,例如:集合 [collections] .缓存 [caching] .原生类型支持 [primitiv ...

  3. Slam学习笔记——ROS踩坑记录

    Slam学习笔记--ROS踩坑记录 1. 安装 2. ROS文件系统 2.1 工作区 2.2 包package 2.2.1 包的操作 2.2.2 描述文件package.xml 2.3 节点node ...

  4. python中socket模块常用吗_python网络学习笔记——socket模块使用记录

    此文章记录了笔者学习python网络中socket模块的笔记. 建议初次学习socket的读者先读一遍socket模块主要函数的介绍. socket模块的介绍可以参考笔者的前一篇关于socket官方文 ...

  5. Qt5学习笔记之零碎问题记录

    目录 概述 1.qDebug输出问题 1.1 qDebug() << "OK"报错 1.2 qDebug打印QString类型 2.QString字符串的操作 3.修改 ...

  6. Guava学习笔记:Google Guava 类库简介

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

  7. Learn Git Branching 学习笔记(移动提交记录篇)

    目录 一.移动提交记录篇 1.Git Cherry-pick 2.交互式rebase Git用法高级篇在上一篇文章中Learn Git Branching 学习笔记(高级篇)_流年--by gone的 ...

  8. Objective-C学习笔记2013[NSString]字符串[可变字符串中,加用app减用delete]

    Objective-C学习笔记 小常识: NS是Cocoa类对象类型的前缀,来源于史蒂夫-乔布斯被苹果开除那段时间建立的公司NeXT. @是Cocoa元素的前缀,很多地方我们会看到,比如接下来... ...

  9. Guava学习笔记:EventBus(转)

    EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现.对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和 ...

  10. 学习笔记:caffe2 教程记录三

    接着caffe2 教程记录二,这个是第三篇 ##3.图像加载与预处理 图像加载和预处理: 在本教程中,我们将研究如何从本地文件或URL加载图像,然后您可以在其他教程或示例中使用这些文件.此外,我们将深 ...

最新文章

  1. JDK 14 里的调试神器了解一下?
  2. 第九次会议(5.14)
  3. 选哪扇门得奖金的算法
  4. flashcom网址收集
  5. 浅析微信支付:微信支付简单介绍(小程序、公众号、App、H5)
  6. c语言库函数fgets,C语言 标准I/O库函数 fgets 使用心得
  7. IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习保护API
  8. php private方法,php如何调用private方法
  9. 多叉树的前序遍历_多叉树的创建和遍历(为Trie树做准备)
  10. nginx 根据目录指定root_nginx安全优化与性能优化
  11. FleaPHP 开发基础 - 第一部分
  12. 接口测试工具-apifox
  13. ooffice为保护计算机,office已检测到此文件存在问题编辑此文件可能会损害您的计算机!...
  14. 开始刷题--《C语言经典100题》
  15. 计算机编程的经典书籍(强烈推荐)
  16. 条形码类型简介及常用条形码产品
  17. Excel卡死无响应问题
  18. C# 身份证图片识别
  19. 哪一款信用卡累计兑换航空里程最划算?
  20. 原创【歌词类】雪中吟

热门文章

  1. easyui datagrid添加合计行
  2. 重装系统解决:CUPS服务未启动,不能管理打印机
  3. 龙芯OpenJDK更新策略:没必要跟进小版本,最后大版本更新
  4. 全网首发:WORD取消了光标的方向
  5. 某LINUX平台,管道open直接崩溃
  6. 顺序不能改变的算子,是否跟时间有关
  7. 管理感悟:你是产品的第一个用户
  8. python中的计时器timeit_python中的计时器:timeit
  9. python not_刚接触Python,python中not in怎么解释?求解释一下?
  10. css渐变颜色php,CSS3中的颜色值RGBA以及渐变色的具体详解(图)