maven依赖
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
不可变集合
不可变集合,顾名思义就是说集合是不可被修改的。集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变。
为什么要用immutable对象?
immutable对象有以下的优点:
- 对不可靠的客户代码库来说,它使用安全,可以在未受信任的类库中安全的使用这些对象
- 线程安全的:immutable对象在多线程下安全,没有竞态条件
- 不需要支持可变性, 可以尽量节省空间和时间的开销. 所有的不可变集合实现都比可变集合更加有效的利用内存 (analysis)
- 可以被使用为一个常量,并且期望在未来也是保持不变的
immutable对象可以很自然地用作常量,因为它们天生就是不可变的对于immutable对象的运用来说,它是一个很好的防御编程(defensive programming)的技术实践。Collections.unmodifiableList实现的不是真正的不可变集合,当原始集合修改后,不可变集合也发生变化。不可变集合不可以修改集合数据,当强制修改时会报错,实例中的最后两个add会直接抛出不可修改的错误。JDK的Collections.unmodifiableXXX方法实现不可变集合的一些问题:
- 它用起来笨拙繁琐你不得不在每个防御性编程拷贝的地方用这个方法
- 它不安全:如果有对象reference原始的被封装的集合类,这些方法返回的集合也就不是正真的不可改变。
- 效率低:因为它返回的数据结构本质仍旧是原来的集合类,所以它的操作开销,包括并发下修改检查,hash table里的额外数据空间都和原来的集合是一样的。
Guava的immutable集合
Guava提供了对JDK里标准集合类里的immutable版本的简单方便的实现,以及Guava自己的一些专门集合类的immutable实现。当你不希望修改一个集合类,或者想做一个常量集合类的时候,使用immutable集合类就是一个最佳的编程实践。注意:每个Guava immutable集合类的实现都拒绝null值。我们做过对Google内部代码的全面的调查,并且发现只有5%的情况下集合类允许null值,而95%的情况下都拒绝null值。万一你真的需要能接受null值的集合类,你可以考虑用Collections.unmodifiableXXX。
Immutable集合使用方法
一个immutable集合可以有以下几种方式来创建:
- 用copyOf方法, 譬如, ImmutableSet.copyOf(set)
- 使用of方法,譬如,ImmutableSet.of(“a”, “b”, “c”)或者ImmutableMap.of(“a”, 1, “b”, 2)
- 使用Builder类
//不可变列表
ImmutableList<String> list = ImmutableList.of("A","B","C");
//不可变Map
ImmutableMap<Integer,String> map = ImmutableMap.of(1,"壹");
//多值Map
Multimap<String,String> phoneBook = ArrayListMultimap.create();
phoneBook.put("张三","110");
phoneBook.put("张三","119");
System.out.println(phoneBook.get("张三"));
//Table表
Table<Double,Double,String> g = HashBasedTable.create();
g.put(31.23,121.48,"人民广场");
//输入坐标点的建筑物
System.out.println(g.get(31.23,121.48));
//Table完全类似于数据库表
Table<Integer,Integer,String> user = HashBasedTable.create();
user.put(1,1,"张三");
user.put(1,2,"李四");
System.out.println(user.get(1,1));
//集合工具类
Map<String,Integer> user1 = new HashMap<>();
user1.put("张三",20);
user1.put("李四",22);
user1.put("王五",25);
//所有年龄大于20岁的人员
Map<String,Integer> filtedMap = Maps.filterValues(user1, new Predicate<Integer>() {
@Override
public boolean apply(Integer _age) {
return _age>20;
}
});
//字符串操作 Joiner
Joiner joiner = Joiner.on(",");
//可以连接多个对象,不局限于String,如果有null,则跳过
String str = joiner.skipNulls().join("嘿","guava很不错吧");
Map<String,String> map1 = new HashMap<>();
map1.put("张三","普通员工");
map1.put("李四","领导");
System.out.println(Joiner.on("\r\n").withKeyValueSeparator("是").join(map1));
//字符串操作 Splitter
String str2 = "你好,guava";
//以","中文逗号分隔
for (String s: Splitter.on(",").split(str2)){
System.out.println(s);
}
//按固定长度分隔
for(String s:Splitter.fixedLength(2).split(str2)){
System.out.println(s);
}
//基本类型工具
int[] ints = {10,9,20,40,80};
//从数组中取出最大值
System.out.println(Ints.max(ints));
List<Integer> integers = new ArrayList<>();
//把包装器类型的集合转为基本类型数组
ints = Ints.toArray(integers);