不可变对象
- 对象创建后,所有的状态和属性在整个生命周期内不能被修改
- 同理,不可变集合就是集合创建后,不能对集合中的对象进行修改
好处:
- 并发处理,由于多个线程对共享资源的一个修改,会导致并发问题的出现。如果共享资源不能被修改,每个线程拿到的都是同样的数据,就不存在并发问题了
- 减少集合的出错率,平时我们使用一个map,通过key去拿value,可变集合就会有一种情况,就是通过key去拿value的时候,可能Map中Key已经变了
Map<String,String> map = new HashMap<String,String>();
String key = "hello";
map.put(key,"world");
为什么要使用不可变集合?
- 不可变对象提供给别人使用时是安全的,因为不可变,所有人都无法进行修改,只能读
- 支持多个线程调用,不存在竞争的问题,天然支持多线程
- 不可变集合节省内存空间,因为不可变,集合空间在创建时就已经确定好了,不用考虑扩容等问题,内存利用率高
- 不可变集合可用于常量
Guava中不可变集合的使用方法
1. copyOf()
public void test1(){
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
ImmutableList<String> immutList = ImmutableList.copyOf(list);
list.add("d");
//最后输出结果:[a,b,c]
System.out.println(immutList);
}
2. of()
public void test2(){
//创建一个内容为:[a,b,c]的不可变集合
ImmutableList<String> immutableList = ImmutableList.of("a","b","c");
//最后输出结果:[a,b,c]
System.out.println(immutableList);
}
3. Builder()
public void test3(){
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
ImmutableList<String> immutableList = ImmutableList.<String>builder().addAll(list).add("d").build();
//最后输出结果:[a, b, c, d]
System.out.println(immutableList);
}
细节:关联可变集合和不可变集合
可变集合接口 | 属于JDK还是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 |
Multiset
public void test4(){
//通过create()方法创建
Multiset<String> multiset = HashMultiset.create();
//可直接添加元素
multiset.add("a");
multiset.add("b");
multiset.add("c");
multiset.add("c");
multiset.add("c");
List<String> list = new ArrayList<String>();
list.add("xx");
list.add("yy");
list.add("zz");
//addAll:添加集合进来
multiset.addAll(list);
//获取元素"c"的计数
System.out.println(multiset.count("c"));
//返回去重后的元素set集合
Set<String> set = multiset.elementSet();
//multiset所有元素的个数
System.out.println("multiset.size():" + multiset.size());
//multiset去重后的元素个数
System.out.println("elementSet().size():" + multiset.elementSet().size());
//元素迭代
Iterator<String> it = multiset.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//可以通过设置元素的计数,来批量的添加元素,当然能加也能减
multiset.setCount("c",5);
//将元素的计数设为0,就相当于移除所有的"c"元素
multiset.setCount("c",0);
//移除一个元素
multiset.remove("c");
//移除两个"c"元素
multiset.remove("c",2);
}
Multimap
public void test5(){
Multimap multimap = ArrayListMultimap.create();
//新增元素,直接put
multimap.put("a","123");
multimap.put("a","111");
multimap.put("b","456");
multimap.put("d","789");
Multimap multimap1 = LinkedListMultimap.create();
multimap1.put("a","a1_value");
multimap1.put("k2","k2_value");
//使用putAll方法可以添加一个multimap,这个跟JDK中的putAll一样,而且key相同时会进行合并
multimap.putAll(multimap1);
List<String> list = Lists.newArrayList("a_value1","a_value2","a_value3");
//还可以指定key进行批量添加元素,注意此处是追加到key中,不是替换
multimap.putAll("a",list);
//multimap中的所有键值对,重复的算多个
System.out.println(multimap.size());
//key的个数
System.out.println(multimap.keySet().size());
//移除指定key的指定value
multimap.remove("a","111");
System.out.println(multimap);
//移除整个key的所有value
multimap.removeAll("a");
System.out.println(multimap);
//替换指定key的value
multimap.replaceValues("b",Lists.newArrayList("b1_value","b2_value"));
//是否包含指定的key
System.out.println(multimap.containsKey("d"));
//是否包含指定的键值对
System.out.println(multimap.containsEntry("d","789"));
//获取multimap中所有的value
System.out.println(multimap.values());
//返回Multiset
System.out.println(multimap.keys());
//返回Map类型
Map<String,List<String>> map = multimap.asMap();
//清空整个集合
multimap.clear();
System.out.println(multimap);
}