Immutable集合
JDK提供了Collections.UnmodifiableList(),Collections.UnmodifiableSet()和Collections.unmodifiableMap()这些包装方法。事实上它们的实现都是包装了原来的集合对象,然后在add,put,remove这样的方法上面抛出UnsupportedOperationException。这样就实现了Unmodifiable特性。这种做法在编程中叫作转发(forwarding)。
这样的Unmodifiable集合能满足一般的需求,但是如果碰到下面的情况 - 例如你需要定义2个常数放在List里面然后把这个List做成final,而且用Collections.UnmodifiableList()包装一下,就以为高枕无忧了:
List<String> l = new ArrayList<String>();
l.add("FULL");
l.add("LOW");
final List<String> unmodifiableList = Collections.unmodifiableList(l);
看上去unmodifiableList是不可改变的,但是如果这样:
l.add("NORMAL");
你再看unmodifiableList已经被加了"NORMAL"。
当然有经验的程序员可以把原来的List放到新作的List然后Unmodifiable包装一下:
List<String> unmodifiableList= Collections.unmodifiableList(new ArrayList(l));
但是已经有Google Collection的Immutable集合解决了这个问题。刚才unmodifiableList可以这样来做:
ImmutableList<String> unmodifiableList = ImmutableList.copyOf(l);
除此之外Immutable集合还提供了ImmutableSet和ImmutableMap来包装集合。
为了便捷开发Immutable集合还能让开发者方便地在初始化设值:
//Before
List<String> list = new ArrayList<String>();
list.add("day");
list.add("night");
//Now
ImmutableList<String> immutableList = ImmutableList.of("day", "night");
//Before
Set<String> set = new HashSet<String>();
set.add("day");
set.add("night");
//Now
ImmutableSet<String> immutaleSet = ImmutableSet.of("day", "night");
//Before
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(0,"day");
map.put(1,"night");
//Now
ImmutableMap<Integer, String> immutaleMap = ImmutableMap.of(0, "day", 1,"night");
//Use builder pattern
ImmutableMap<Integer, String> immutaleMap2 = new ImmutableMap.Builder<Integer, String>()
.put(0,"day")
.put(1,"night")
.build();
值得注意的是这些Immutable集合都是abstract类,它们的初始化都是由of(),copyOf()以及builder模式这样方式来实现。