ImmutableSet && ImutableMap
不可变对象有很多优点,包括:
- 当对象被不可信的库调用时,不可变形式是安全的;
- 不可变对象被多个线程调用时,不存在竞态条件问题
- 不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
- 不可变对象因为有固定不变,可以作为常量来安全使用。
创建对象的不可变拷贝是一项很好的防御性编程技巧。Guava为所有JDK标准集合类型和Guava新集合类型都提供了简单易用的不可变版本。
示例
package guava.collect;
import com.google.common.collect.ImmutableSet;
/**
* @author denny
* @Description 不可变集合
* @date 2018/7/26 下午3:16
*/
public class ImmutableCollectionsTest {
/**
* 1.直接申明静态集合
*/
public static final ImmutableSet<String> COLOR_NAMES_1 = ImmutableSet.of(
"red",
"orange",
"yellow",
"green");
/**
* 2.防御式copy
*/
public static final ImmutableSet<String> COLOR_NAMES_2 = ImmutableSet.copyOf(COLOR_NAMES_1);
/**
* 3.builder建造者模式
*/
public static final ImmutableSet<String> COLOR_NAMES_3 = ImmutableSet.<String>builder().addAll(COLOR_NAMES_2).add("blue").build();
public static void main(String[] args) {
System.out.println("of:"+COLOR_NAMES_1);
System.out.println("防御式copy:"+COLOR_NAMES_2);
System.out.println("建造者模式:"+COLOR_NAMES_3);
System.out.println("转换成list:"+COLOR_NAMES_3.asList());
}
}
/*** 运行结果
*of:[red, orange, yellow, green]
*防御式copy:[red, orange, yellow, green]
*建造者模式:[red, orange, yellow, green, blue]
*转换成list:[red, orange, yellow, green, blue]
***/
Multiset
可以多次添加相等的元素,它和set最大的区别就是它可以对相同元素做一个计数的功能。
数据类型
abstract class AbstractMapBasedMultiset {
private transient Map<E, Count> backingMap;
}
可以看到,Multiset是一个Map类型,它的value值记录了这个key出现了多少次。
实现类
Map | Multiset | 是否支持null |
---|---|---|
HashMap | HashMultiset | 是 |
TreeMap | TreeMultiset | 是 |
LinkedHashMap | LinkedHashMultiset | 是 |
EnumMultiset | 否 | |
ImmutableMap | ImmutableMultiset | 否 |
ConcurrentHashMap | ConcurrentMultiset | 否 |
方法
方法 | 描述 |
---|---|
add(E element) | 向其中添加单个元素 |
add(E element,int occurrences) | 向其中添加指定个数的元素 |
count(Object element) | 返回给定参数元素的个数 |
remove(E element) | 移除一个元素,其count值 会响应减少 |
remove(E element,int occurrences) | 移除相应个数的元素 |
elementSet() | 将不同的元素放入一个Set中 |
entrySet() | 类似与Map.entrySet 返回Set<Multiset.Entry>。包含的Entry支持使用getElement()和getCount() |
setCount(E element ,int count) | 设定某一个元素的重复次数 |
setCount(E element,int oldCount,int newCount) | 将符合原有重复个数的元素修改为新的重复次数 |
retainAll(Collection c) | 保留出现在给定集合参数的所有的元素 |
removeAll(Collectionc) | 去除出现给给定集合参数的所有的元素 |
size() | 这个集合的大小,包含重复元素 |
示例
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;
public class MultisetTest {
public static void main(String[] args) {
String str = "张三 李四 李四 王五 王五 王五";
String[] strArr = str.split(" ");
List<String> words = new ArrayList<String>(Arrays.asList(strArr));
//创建一个HashMultiset集合,并将words集合数据放入
Multiset<String> wordMultiset = HashMultiset.create();
wordMultiset.addAll(words);
//将不同的元素放在一个集合set中
for (String key : wordMultiset.elementSet()) {
//查看指定元素的个数
System.out.println(key + "-->" + wordMultiset.count(key));
}
System.out.println("---------向集合中添加元素----------");
//向集合中添加元素
wordMultiset.add("李四");
for (String key : wordMultiset.elementSet()) {
System.out.println(key + "-->" + wordMultiset.count(key));
}
System.out.println("-------向集合中添加若干个元素------");
//向集合中添加若干个元素
wordMultiset.add("赵六", 10);
for (String key : wordMultiset.elementSet()) {
System.out.println(key + "-->" + wordMultiset.count(key));
}
System.out.println("--------向集合中移出一个元素------");
//向集合中移出一个元素
wordMultiset.remove("张三");
for (String key : wordMultiset.elementSet()) {
System.out.println(key + "-->" + wordMultiset.count(key));
}
System.out.println("------向集合中移出若干个元素------");
//向集合中移出若干个元素,如果元素的个数小于要移除的个数,则会把该元素移除光
wordMultiset.remove("赵六",5);
for (String key : wordMultiset.elementSet()) {
System.out.println(key + "-->" + wordMultiset.count(key));
}
System.out.println("-----设定某一个元素的重复次数-----");
//设定某一个元素的重复次数
wordMultiset.setCount("张三", 10);
for (String key : wordMultiset.elementSet()) {
System.out.println(key + "-->" + wordMultiset.count(key));
}
System.out.println("-----设置复合元素的个数设为新的重复次数-----");
//设置复合元素的个数设为新的重复次数(条件是第二个参数的数量要是实际数量一致,否则无效)
wordMultiset.setCount("and", 1,0);
for (String key : wordMultiset.elementSet()) {
System.out.println(key + "-->" + wordMultiset.count(key));
}
System.out.println("-------删除给定集合中的元素------");
//删除给定集合中的元素
wordMultiset.removeAll(words);
for (String key : wordMultiset.elementSet()) {
System.out.println(key + "-->" + wordMultiset.count(key));
}
}
}
Multimap
multimap和MultiSet的继承结果很相似,只不过在上层的接口是Multimap不是Multiset。
Multimap的特点其实就是可以包含有几个重复Key的value,你可以put进入多个不同value但是相同的key,但是又不是让后面覆盖前面的内容。
它的业务场景:当你需要构造像Map<K, List<V>>或者Map<K, Set<V>>这样比较复杂的集合类型的数据结构,来做相应的业务逻辑处理。那Multimap在合适不过。
实现类
Implementation | Keys 的行为类似 | Values的行为类似 |
---|---|---|
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap | LinkedHashMap* | LinkedList* |
LinkedHashMultimap | LinkedHashMap | LinkedHashSet |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap | ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
方法
方法 | 描述 |
---|---|
put(K, V) | |
putAll(K, Iterable<V>) | |
remove(K, V) | |
removeAll(K) | |
replaceValues(K, Iterable<V>) | |
asMap() | 提供Map<K,Collection>形式的视图 |
entries() | 提供Collection<Map.Entry<K, V>>的视图(对SetMultimap,返回的是Set) |
keySet() | 用Set表示Multimap中所有不同的键 |
keys() | 用Multiset表示Multimap中的所有键 |
values() | 提供Collection包含Multimap中的所有值 |
示例
public class MultimapTest {
public static void main(String args[]){
Multimap<String,String> multimap = ArrayListMultimap.create();
multimap.put("lower", "a");
multimap.put("lower", "b");
multimap.put("lower", "c");
multimap.put("upper", "A");
multimap.put("upper", "B");
List<String> lowerList = (List<String>)multimap.get("lower");
//输出key为lower的list集合
System.out.println("输出key为lower的list集合=========");
System.out.println(lowerList.toString());
lowerList.add("f");
System.out.println(lowerList.toString());
Map<String, Collection<String>> map = multimap.asMap();
System.out.println("把Multimap转为一个map============");
for (Map.Entry<String, Collection<String>> entry : map.entrySet()) {
String key = entry.getKey();
Collection<String> value = multimap.get(key);
System.out.println(key + ":" + value);
}
System.out.println("获得所有Multimap的key值==========");
Set<String> keys = multimap.keySet();
for(String key:keys){
System.out.println(key);
}
System.out.println("输出Multimap所有的value值========");
Collection<String> values = multimap.values();
System.out.println(values);
}
}
/**输出结果:
*输出key为lower的list集合=========
* [a, b, c]
* [a, b, c, f]
* 把Multimap转为一个map============
* lower:[a, b, c, f]
* upper:[A, B]
* 获得所有Multimap的key值==========
* lower
* upper
* 输出Multimap所有的value值========
* [a, b, c, f, A, B]
*/
Table
结构类似于二维数组,它有两个支持所有类型的键:”行”和”列”。
bidirectional maps
bimap的作用很清晰:它是一个一一映射,可以通过key得到value,也可以通过value得到key。与HashMap对比,不仅key能保证唯一,value也能保证唯一。
实现类
Implementation | Keys 的行为类似 | Values的行为类似 |
---|---|---|
HashBiMap | HashMap | HashMap |
EnumBiMap | Enum | Enum |
ImmutableBiMap |
方法
方法 | 描述 |
---|---|
inverse | key, value反转 |
示例
public class bimapTest {
public static void main(String args[]){
//双向map
BiMap<Integer,String> biMap = HashBiMap.create();
biMap.put(1,"张三");
biMap.put(2,"李四");
biMap.put(3,"王五");
biMap.put(4,"赵六");
biMap.put(5,"李七");
biMap.put(4,"小小");
//通过key值得到value值(注意key里面的类型根据泛行
String value = biMap.get(1);
System.out.println("id为1的value值 --"+value);
//通过value值得到key值
int key = biMap.inverse().get("张三");
System.out.println("张三key值 --"+key);
//通过key值重复,那么vakue值会被覆盖。
String valuename = biMap.get(4);
System.out.println("id为4的value值 --"+valuename);
}
}
/*运行结果:
*id为1的value值 --张三
*张三key值 --1
*id为4的value值 --小小
*/
参考:
[1]. https://www.cnblogs.com/qdhxhz/p/9410898.html
[2]. https://www.cnblogs.com/qdhxhz/p/9411511.html
[3]. https://www.cnblogs.com/qdhxhz/p/9425039.html