要说Java程序员必须要学习的东西的话,Spring当仁不让,必须是第一个框架,也有另外一个东西,也是新手程序员必须要学习的东西,那就是Google的Guava库,这个库的作者,和Effective Java的作者是同一人,都来自于Google,学好了这个库,你的Java的能力,相信会更上一个台阶。Java的优势是什么?那就是各种成熟的轮子,Guava就是其中之一,如果想代码很少BUG,就开始使用它吧。
目录
1、基本工具
2、集合
1、基本工具
1.1 避免NULL
NULL的含义是不确定的,应该避免,尤其是在Map和Set中,返回NULL,并不清楚是不存在,还是有值,但是是NULL,最常用的一个技巧就是:
1 | // 好的代码 |
这样可以避免空指针。Guava的建议是: 使用快速失败操作拒绝null值对开发者更有帮助。
1.2 Guava用Optional表示可能为null的T类型引用:
1 | Optional<Integer> possible = Optional.of(50); |
2、集合类
2.1 不可变集合
这个属于防御性编程内容,不可变集合的意思就是集合创建了之后,就不能改变了,类似于:
1 | // SIZE 的值是不可以改变的 |
想要设计不可变集合类的主要原因有:
- 当对象被不可信的库调用时,不可变形式是安全的。
- 线程安全。
- 容易测试。
- 安全,不容易出BUG,以防某些错误的代码修改了集合的内容。
创建的方法(还有1个copyOf方法,这里不打算引入了):
1 | final ImmutableSet<Integer> set = ImmutableSet.<Integer>builder() |
2.2 新集合类型
有一些新的类型可以使用,例如java没有Table类型,下面将一一介绍。
2.2.1 Multiset
这个东西,可以想象成1个ArrayList,没有顺序,但是它是一个Set,不过可以有重复的Key,还记录了重复的Key的出现的数量。比方说你要统计一篇文章中出现的单词的次数:
1 | Map<String, Integer> counts = new HashMap<String, Integer>(); |
这种写法很笨拙,也容易出错,并且不支持同时收集多种统计信息,如总词数。我们可以做的更好。替代方法:
1 | //模拟文章内容 |
Multiset接口的方法:
方法 | 描述 |
---|---|
count(E) | 给定元素在Multiset中的计数 |
elementSet() | Multiset中不重复元素的集合,类型为Set |
entrySet() | 和Map的entrySet类似,返回Set<Multiset.Entry |
add(E, int) | 增加给定元素在Multiset中的计数 |
remove(E, int) | 减少给定元素在Multiset中的计数 |
setCount(E, int) | 设置给定元素在Multiset中的计数,不可以为负数 |
size() | 返回集合元素的总个数(包括重复的元素) |
该接口的实现类:
Map | 对应的**Multiset** | 是否支持**null**元素 |
---|---|---|
HashMap | HashMultiset | 是 |
TreeMap | TreeMultiset | 是(如果comparator支持的话) |
LinkedHashMap | LinkedHashMultiset | 是 |
ConcurrentHashMap | ConcurrentHashMultiset | 否 |
ImmutableMap | ImmutableMultiset | 否 |
2.2.2 Multimap
一般都遇到过以下场景,这种可以使用Multimap替代,需要注意Multimap不是Map。
1 | //传统方法 |
Multimap提供了多种形式的实现。在大多数要使用Map<K, Collection
实现 | 键行为类似 | 值行为类似 |
---|---|---|
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap | LinkedHashMap | LinkedList |
LinkedHashMultimap | LinkedHashMap | LinkedHashMap |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap |
ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
2.2.3 BiMap
传统上,实现键值对的双向映射需要维护两个单独的map,并保持它们间的同步。但这种方式很容易出错,而且对于值已经在map中的情况,会变得非常混乱。例如:
1 | Map<String, Integer> nameToId = Maps.newHashMap(); |
替代方法:
1 | BiMap<String, Integer> nameIdBiMap = HashBiMap.create(); |
如果不是唯一的,会出现什么情况呢? 例如2个人重名了。如果我们放开了上面的注释语句,模拟下这种冲突,就会出现ID为1的人被覆盖掉了,这点在使用的时候,需要特别注意。
BiMap的各种实现
键值实现 | 值键实现 | 对应的BiMap实现 |
---|---|---|
HashMap | HashMap | HashBiMap |
ImmutableMap | ImmutableMap | ImmutableBiMap |
EnumMap | EnumMap | EnumBiMap |
EnumMap | HashMap | EnumHashBiMap |
2.3.4 Table
Table有点类似于2维数组,根据行和列,确认某一个值,没有Table,老方法就是搞个Map<V,Map<K,V>>这样的结构来实现。替代方法:
1 | Table<Integer, Integer, Integer> table = HashBasedTable.create(); |
是不是感觉很方便?
2.3.5 RangeSet
这个东西很有意思,在某些场景,我感觉可能会有用,RangeSet的意思是一些非连续区间,例如:
{[1,10], [11,15)} {[1,10], [11,20)} 在数学上,它是不连续的,也可能是连续的。这个时候,想要描述这段区间的时候,可以使用RangeSet这个类。
注:RangeSet不支持GWT,也不支持JDK5和更早版本;因为,RangeSet需要充分利用JDK6中NavigableMap的特性。
1 | RangeSet<Integer> rangeSet = TreeRangeSet.create(); |
1、RangeSet的实现支持非常广泛的视图:
- complement():返回RangeSet的补集视图。complement也是RangeSet类型,包含了不相连的、非空的区间。
- subRangeSet(Range
):返回RangeSet与给定Range的交集视图。这扩展了传统排序集合中的headSet、subSet和tailSet操作。 - asRanges():用Set<Range
>表现RangeSet,这样可以遍历其中的Range。 - asSet(DiscreteDomain
)(仅ImmutableRangeSet支持):用ImmutableSortedSet 表现RangeSet,以区间中所有元素的形式而不是区间本身的形式查看。(这个操作不支持DiscreteDomain 和RangeSet都没有上边界,或都没有下边界的情况)
2、RangeSet的查询方法 为了方便操作,RangeSet直接提供了若干查询方法,其中最突出的有: - contains(C):RangeSet最基本的操作,判断RangeSet中是否有任何区间包含给定元素。
- rangeContaining(C):返回包含给定元素的区间;若没有这样的区间,则返回null。
- encloses(Range
):简单明了,判断RangeSet中是否有任何区间包括给定区间。 - span():返回包括RangeSet中所有区间的最小区间。
2.3.6 其它
还有一些其它的类,就不多写了,可以自己去看看API文档
- ClassToInstanceMap
- RangeMap 这个和RangeSet有点像,相当于某个区间对应了某个值,例如:具体用到了的时候,可以再研究一下。
1
2RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "foo"); //{[1,10] => "foo"}
全文完。 JAVA程序员必学的Google Guava库(第二篇)
参考文档:
并发编程网 http://ifeve.com/google-guava/