-
Guava进修笔记:Immutable(不成变)凑集
添加时间:2013-7-4 点击量:不成变凑集,顾名思义就是说凑集是不成被批改的。凑集的数据项是在创建的时辰供给,并且在全部生命周期中都不成改变。
为什么要用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:[0 x, 1x, 2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10 x, 11x, 12x, 13x, 14x, 15x, 16x, 17x, 18x, 19x]
imInfolist:[2x, 3x, 4x, 5x, 6x, 7x, 8x, 9x, 10 x, 11x, 12x, 13x, 14x, 15x, 16x, 17x]
imInfolistSize:16
imInfoSet:[4x, 5x, 6x, 7x, 8x, 9x, 10 x, 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凑集和不成变对应关系
可变凑集类型