Guava学习笔记
一、集合类型
Multiset
特点
- Guava提供了Multiset,虽然名字带有Set,但它可以添加重复的元素;
- Multiset可以看成是ArrayList和Map的结合体
- Multiset是没有元素顺序限制的ArrayList
- 提供了键为元素,值为计数的Map
Map | 对应的multiset | 是否支持null元素 |
---|---|---|
HashMap | HashMultiset | 是 |
TreeMap | TreeMultiset | 是 |
LinkedHashMap | LinkedHashMultiset | 是 |
ConcurrentHashMap | ConcurrentHashMultiset | 否 |
ImmutableMap | ImmutableMultiset | 否 |
HashMultiset
好用的方法:
Multiset<String> multiset = HashMultiset.create();// 创建
multiset.count("str");// 查询str在集合中的个数
multiset.addAll(list);// 把一个对象加入集合 (list mapHashMultiset都可以的)
Set<String> set = multiset.elementSet();// 去重 返回一个set
multiset.setCount("str",5);// 设置str在集合中的个数 多了就增加 少了就减少
SortedMultiset
支持高效的获取指定范围的子集
支持高效的获取指定范围的子集
好用的方法:
SortedMultiset<String> multiSet = TreeMultiset.create();// 创建
multiSet.firstEntry();// 获取第一个元素
multiSet.lastEntry();// 获取最后一个元素
SortedMultiset<String> newMultiSet = multiSet.subMultiset("str1", BoundType.OPEN, "str3", BoundType.CLOSED);// 指定str1后第一个开始 str3结束生成一个新的集合
Multimap
Guava为我们提供了Multimap,可以用来做一个Key映射多个值的操作
Multimap multimap = ArrayListMultimap.create();
multimap.putAll(multimap1);// 对一个key加多个value
System.out.println("a-->" + multimap.get("a"));// [a_value1, a_value2] putAll可以加入list、map
multimap.remove("a", "a_value1");// 一次删除一个key的value值
multimap.replaceValues("a", Lists.newArrayList("b1_value","b2_value"));// 给a替换value值
multimap.removeAll("a");// 删除key的所有值
Map<String,List<String>> map = multimap.asMap();// 把multimap转换为Map
实现 | 键行为类似 | 值行为类似 |
---|---|---|
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap | LinkedHashMap | LinkedList |
LinkedHashMultimap | LinkedHashMap | LinkedHashMap |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap | ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
BiMap
在JDK中,如果我们要维护一个双向Map,需要定义两个Map来存储,并且两个要同时进行变更
Guava提供了BiMap,它是一种特殊的Map,可以实现键值的反转
BiMap biMap = HashBiMap.create();
biMap.put("a", "123");
System.out.println(biMap);// {a=123}
System.out.println(biMap.inverse());// {123=a}
biMap.put("b","123");// 会抛异常 value already present: 123
Table
在JDK中当需要做key映射到Key-value对时,你需要这样写Map<K,Map<K,V>>,这种写法同样不够友好,同时也不便维护
Guava里面提供了表格来解决这种场景,其实就是一个行、列、值的结构
Table<String, String, String> table = HashBasedTable.create();
table.put("a1","b1","c1");
table.put("a1","b1","c1");
table.put("a2","b1","c2");
table.put("a3","b3","c3");
// row colum value
System.out.println("row-->" + table.row("a1"));// {b1=c1}
System.out.println("column-->" + table.column("b1"));// {a1=c1, a2=c2}
查结果时,key 会去做一次去重
ClassToInstanceMap
ClassToInstanceMap是一种特殊的Map:它的键是类型,而值是符合键所指类型的对象
ClassToInstanceMap classToInstanceMap = MutableClassToInstanceMap.create();
classToInstanceMap.putInstance(Integer.class,123);
classToInstanceMap.putInstance(Integer.class,456);
classToInstanceMap.putInstance(Integer.class,789);
System.out.println(classToInstanceMap.getInstance(Integer.class));// 789
Immutable Collections 不可变集合
什么是不可变集合
对象创建后,所有的状态和属性在整个生命周期内不能被修改
同理,不可变集合就是集合创建后,不能对集合中的对象进行修改
为什么需要不可变集合
让并发处理变得更简单了。
一般我们处理并发问题,都是在共享资源上加锁,比如synchronize、Lock等,让线程串行的来进行处理。其实仔细想一下,之所有会有并发的问题,是因为线程之间会进行资源争抢,对共享资源进行修改才会影响到其他线程。
共享资源不能被任何线程修改,那线程之间根本就不会相互影响,天然就是线程安全的!
消除了副作用。
创建后属性和状态都不能被改变,就不会出现数据在意料之外被修改了
不可变对象可以减少集合出错的概率。
常用方法
copyOf() 方法
List<String> unList = Collections.unmodifiableList(list);
unList.add("d");// 往不可变List中添加元素会报错
of方法
ImmutableList<String> immutableList = ImmutableList.of("a","b","c");
Builder方法
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
ImmutableList<String> immutableList = ImmutableList.<String>builder().addAll(list).add("d").build();
二、常用集合工具类
Lists
常用方法
- asList()将数据组转成list
- partition(List list, int size) 将list按指定大小分隔成多个list
- cartesianProduct(List<> lists) 获取多个list的笛卡尔集
- charactersOf(String str) 将字符串转成字符集合
- reverse(List list) 反转list
Sets
常用方法
- cartesianProduct(Set<> sets) 笛卡尔集
- combinations(Set set, final int size) 按指定大小进行排列组合
- difference(final Set set1, final Set<?> set2) 两个集合的差集
- intersection(final Set set1, final Set<?> set2) 交集
- filter(Set unfiltered, Predicate<? super E> predicate) 过滤
- powerSet(Set set) 获取set可分隔成的所有子集
- union(final Set<? extends E> set1, final Set<? extends E> set2) 并集
Maps
常用方法
- Maps.newConcurrentMap();。。。
- asMap(Set set, Function<> function) set转map
- difference(Map<K, V> left, Map<K, V> right) 计算map的差值
- filterEntries(Map<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) 通过Entry过滤
- filterKeys(Map<K, V> unfiltered, final Predicate<? super K> keyPredicate) 通过Key过滤
三、Guava缓存
Guava缓存的介绍
Guava Cache为了限制内存的使用,通常都会设置自动回收
Guava缓存的使用场景
- 以空间换取时间,就是用内存的消耗来换取读取性能的提升
- 预测到某些数据会被频繁的查询
- 缓存中存放的数据不会超过内存空间
Cache常用参数
- .initialCapacity(1024) // 初始容量
- maximumSize 最大记录数,存储数据的个数
- maximumWeight 最大容量,存储数据的大小
- expireAfterWrite 写入后多长时间,数据就过期了
- expireAfterAccess 数据多长时间没有被访问,就过期
常用方法
回收策略
- expireAfterWrite 写入多长时间后就回收
- expireAfterAccess 多长时间没有被访问就回收
Guava Cache还支持基于引用级别的回收,这种回收策略是Java特有的
数据清除监听器
@Override
public void onRemoval(RemovalNotification<Object, Object> notification) {
System.out.println("[" +notification.getKey() + ":" + notification.getValue() + "] 被删除了");
}
统计信息
cache.put("cache","1");
cache.getIfPresent("cache");
四、String工具类
Joiner方法
Joiner是用来连接字符串的,它能以指定的字符对多个字符串进行连接
ArrayList<String> list = Lists.newArrayList("1", "2", "3", "4", "5");
System.out.println(Joiner.on(",").join(list));// 1,2,3,4,5
// skipNulls会跳过空值,当有空值时,join方法会报空指针异常
System.out.println(Joiner.on(",").skipNulls().join(list));// 1,2,3,4,5
// useForNull会把空值编程指定值
System.out.println(Joiner.on(",").useForNull("%").join(list));// 1,2,%,3,4,5
// withKeyValueSeparator用来连接map的方法
Map<String,String> map = Maps.newHashMap();
map.put("1","abc");
map.put("2","def");
map.put("3","ghi");
System.out.println(Joiner.on(",").withKeyValueSeparator(":").join(map));// 1:abc,2:def,3:ghi
Splitter方法
System.out.println(Splitter.on(",").splitToList("a,b,c"));// [a, b, c]
CharMatcher方法
CharMatcher用来处理复杂的字符串操作,一般用于查找、处理匹配的字符串
查询的方法
- is(char c): 返回匹配指定字符的Matcher
- isNot(char c): 返回不匹配指定字符的Matcher
- anyOf(CharSequence sequence): 返回匹配sequence中任意字符的Matcher
- noneOf(CharSequence sequence): 返回不匹配sequence中任何一个字符的Matcher
- inRange(char startInclusive, char endIncludesive): 返回匹配范围内任意字符的Matcher
- forPredicate(Predicate<? super Charater> predicate): 返回使用predicate的apply()判断匹配的Matcher
- and(CharMatcher other): 返回与other匹配条件组合做与来判断的Matcher
- or(CharMatcher other): 返回与other匹配条件组合做或来判断的Matcher
处理查询结果的方法
- removeFrom(CharSequence sequence): 删除sequence中匹配到到的字符并返回
- retainFrom(CharSequence sequence): 保留sequence中匹配到的字符并返回
- replaceFrom(CharSequence sequence, char replacement): 替换sequence中匹配到的字符并返回
- trimFrom(CharSequence sequence): 删除首尾匹配到的字符并返回
- trimLeadingFrom(CharSequence sequence): 删除首部匹配到的字符
- trimTrailingFrom(CharSequence sequence): 删除尾部匹配到的字符
- collapseFrom(CharSequence sequence, char replacement): 将匹配到的组(连续匹配的字符)替换成replacement
- trimAndCollapseFrom(CharSequence sequence, char replacement): 先trim在replace
String str = " uahfdsiudsufhud sJNjn hji 9123BHG91284 hdSas 8ds";
// inRange()排查条件 retainFrom提取对应的字母
System.out.println(CharMatcher.inRange('a', 'z').retainFrom(str));// uahfdsiudsufhudsjnhjihdasds
// digit()查询所有的数字 removeFrom() 移除对应的数据
System.out.println(CharMatcher.digit().removeFrom(str));// uahfdsiudsufhud sJNjn hji BHG hdSas ds
Charsets
- Charsets.UTF_8
- Charsets.ISO_8859_1
- Charsets.US_ASCII
- Charsets.UTF_16
- Charsets.UTF_16BE
- Charsets.UTF_16LE
CaseFormat
- CaseFormat是一种实用工具类,以提供不同的ASCII字符格式之间的转换
- 可以用CaseFormat进行驼峰规则转换
String str = "hello_world";
System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, str));// helloWorld
System.out.println(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, str));// HelloWorld