不可变集合
不可变集合例子:
1 | ImmutableSet<String> FRUITS = ImmutableSet.of("apple", "watermelon", "cherry", "mango"); |
将抛出java.lang.UnsupportedOperationException
异常:
创建不可变集合
of
1 | ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c"); |
copyOf
1 | Map<String, String> map = Maps.newHashMap(); |
builder
1 | Map<String, String> map = Maps.newHashMap(); |
除此之外,我们也可以从Java 8 Stream中创建不可变集合:
1 | import static java.util.stream.Collectors.*; |
上面的例子我们也可以使用Guava提供的收集器:
1 | List<String> list = Arrays.asList("a", "b", "c"); |
不可变集合优点
当对象被不可信的库调用时,不可变形式是安全的;
不可变对象被多个线程调用时,不存在竞态条件问题
不可变集合不需要考虑变化,因此可以节省时间和空间。所有不可变的集合都比它们的可变形式有更好的内存利用率(分析和测试细节);
不可变对象因为有固定不变,可以作为常量来安全使用。
新集合类型
Guava提供了许多JDK没有的集合类型。
RangeSet
RangeSet一组不相连的、非空的区间,基本实现为TreeRangeSet,看个RangeSet的例子:
1 | RangeSet<Integer> rangeSet = TreeRangeSet.create(); |
查看RangeSet的范围跨度:
1 | RangeSet<Integer> rangeSet = TreeRangeSet.create(); |
从已有的RangeSet获取一个子范围RangeSet:
1 | RangeSet<Integer> numberRangeSet = TreeRangeSet.create(); |
获取除了RangeSet范围外的RangeSet:
1 | RangeSet<Integer> numberRangeSet = TreeRangeSet.create(); |
判断一个RangeSet是否和另一个范围有交集:
1 | RangeSet<Integer> numberRangeSet = TreeRangeSet.create(); |
遍历RangeSet的范围区间:
1 | RangeSet<Integer> numberRangeSet = TreeRangeSet.create(); |
从RangeSet中获取包含某个值的访问区间:
1 | RangeSet<Integer> numberRangeSet = TreeRangeSet.create(); |
RangeMap
RangeMap是一组不相连的、非空的区间与指定值的映射,基本实现为TreeRangeMap光这样说有点抽象,看些例子:
1 | RangeMap<Integer, String> rangeMap = TreeRangeMap.create(); |
从RangeMap中获取一个Entry:
1 | RangeMap<Integer, String> rangeMap = TreeRangeMap.create(); |
剩下的操作和RangeSet差不多。
BiMap
BiMap是一种特殊的,双向映射的Map,可以确保不会出现重复的值并且我们总是可以安全地通过key获取到value。BiMap的基本实现为HashBiMap。
看看例子:
1 | BiMap<String, String> biMap = HashBiMap.create(); |
通过inverse
可以得到值,键映射的BiMap。
往BiMap里添加重复的值将会报错:
1 | BiMap<String, String> biMap = HashBiMap.create(); |
如果非要添加重复的值的话,可以用forcePut
方法:
1 | BiMap<String, String> biMap = HashBiMap.create(); |
Table
Table是一个包含行,列和单元格的集合类型,行和列组成有序键对。
创建一个HashBasedTable(内部使用LinkedHashMap):
1 | Table<String, String, Integer> hashBasedTable = HashBasedTable.create(); |
如果需要对table的行和列按照自然顺序或者提供的排序规则进行排序的话,可以创建一个TreeBasedTable:
1 | Table<String, String, Integer> treeBasedTable = TreeBasedTable.create(); |
如果事先知道行和列的值,并且table大小是固定的话,可以使用ArrayTable:
1 | List<String> row = Lists.newArrayList("r1", "r2"); |
上面例子创建了一个两行三列的table。
创建不可变table:
1 | Table<String, String, String> immutableTable = ImmutableTable.<String, String, String> builder() |
通过行和列获取单元格的值:
1 | Table<String, String, String> hashBasedTable = HashBasedTable.create(); |
我们可以检测table是否包含某个行键,某个列键,某个值和某个行和列组合的键:
1 | Table<String, String, String> hashBasedTable = HashBasedTable.create(); |
通过行和列删除单元格,返回被删除的值:
1 | Table<String, String, String> hashBasedTable = HashBasedTable.create(); |
我们可以通过行或列得到一个Map,如果通过行得到Map,那么Map的键为列值,Map的值为对应单元格的值,光说有点抽象,看个例子:
1 | Table<String, String, String> hashBasedTable = HashBasedTable.create(); |
我们还可以单独获取所有行或者所有列组成的Map:
1 | Table<String, String, String> hashBasedTable = HashBasedTable.create(); |
获取所有行键、列键或者值的集合:
1 | Table<String, String, String> hashBasedTable = HashBasedTable.create(); |
Multiset
Multiset和java.util.set类似,不过Mutiset可以添加重复的值:
1 | HashMultiset<String> hashMultiset = HashMultiset.create(); |
在并发环境下,我们可以使用ConcurrentHashMultiset,它的add和remove方法是线程安全的。唯一值得注意的是,在并发环境下使用setCount方法时候,需使用下面这种方式:
1 | HashMultiset<String> hashMultiset = HashMultiset.create(); |
第一个参数为需要添加的值,第二个参数为当前Multiset里元素个数,第三个参数为需要添加的元素个数。只有第二个参数的值正确的时候,setCount才有效,所以hashMultiset.setCount("are you ok?", 10, 5)
实际上是不生效的。
Multimap
Multimap可以通过一个键映射多个值:
1 | String key = "hello"; |
ClassToInstanceMap
使用类型作为键:
1 | MutableClassToInstanceMap<Object> classToInstanceMap = MutableClassToInstanceMap.create(); |
Lists、Maps&Sets
Lists
创建一个List:
1 | ArrayList<String> list = Lists.newArrayList("a", "b", "c"); |
反转List:
1 | ArrayList<String> list = Lists.newArrayList("a", "b", "c"); |
通过字符串生成字符集合:
1 | List<Character> characters = Lists.charactersOf("mrbird"); |
将集合按照指定区块大小分区:
1 | List<String> list = Lists.newArrayList("java", "php", "go", "python", "c#", "javascript"); |
一个删除List中重复项的技巧:
1 | List<String> list = Lists.newArrayList("a", "p", "p", "l", "e"); |
从集合中删除null值:
1 | List<String> list = Lists.newArrayList("java", null," python"); |
Sets
通过Sets创建set:
1 | Set<Object> hashSet = Sets.newHashSet(); |
合并两个Set:
1 | Set<String> set1 = ImmutableSet.of("a", "b", "c"); |
可以通过Sets.cartesianProduct()
获取两个Set的笛卡尔积:
1 | Set<Character> first = ImmutableSet.of('a', 'b'); |
获取两个Set的交集:
1 | Set<Character> first = ImmutableSet.of('a', 'b', 'c'); |
获取两个Set的差集:
1 | Set<Character> first = ImmutableSet.of('a', 'b', 'c'); |
Maps
通过Maps创建Map:
1 | HashMap<Object, Object> map = Maps.newHashMap(); |
创建期望大小的Map:
1 | HashMap<Object, Object> map = Maps.newHashMapWithExpectedSize(5); |
Joiner与Splitter
Joiner
Joiner用于连接操作。比如将List里的元素通过“,”连接成一个字符串:
1 | List<String> list = Lists.newArrayList("a", "b", "c"); |
使用Joiner将Map转换为String:
1 | HashMap<String, Integer> map = Maps.newHashMap(); |
在使用Joiner的时候,如果集合中含有null值,我们可以选择跳过它:
1 | List<String> list = Lists.newArrayList("a", null, "b", "c", "d"); |
或者使用指定值替代null:
1 | List<String> list = Lists.newArrayList("a", null, "b", "c", "d"); |
Splitter
Splitter用于将String拆分为集合类型,看个例子:
1 | String value = "a,b,c,d "; |
使用Splitter将String拆分为Map:
1 | String value = "mrbird=18,scott=28"; |
分割具有多种分隔符的String:
1 | String value = "a.b,,c,,.."; |
omitEmptyStrings
用于忽略空字符串。
我们还可以通过指定长度来拆分字符串:
1 | String value = "人们都说:“桂林山水甲天下”,我们乘着木船荡漾在漓江上,来观赏桂林的山水。"; |
也可以指定拆分项的长度:
1 | String value = "a-b-c-d-e"; |
可以看到d-e没有被拆分。
Filter&Transform
Filter
可以通过Guava提供的Predicates来实现各种集合过滤操作。
比如找出集合中包含a的元素:
1 | List<String> list = Lists.newArrayList("java", "javascript", "c#", "golang"); |
上面的例子也可以通过Collections2.filter
来实现:
1 | List<String> list = Lists.newArrayList("java", "javascript", "c#", "golang"); |
我们也可以编写自定义的过滤规则:
1 | Predicate<String> predicate = new Predicate<String>() { |
组合多个过滤条件:
1 | List<String> list = Lists.newArrayList("java", "javascript", "c#", "golang"); |
过滤掉集合中的null:
1 | List<String> list = Lists.newArrayList("java", null," python"); |
检测集合中是否有包含a字符的元素:
1 | List<String> list = Lists.newArrayList("java", "c#"," python"); |
Transform
将集合转换为元素长度的集合:
1 | Function<String, Integer> function = new Function<String, Integer>() { |
上面的例子同样可以使用Collections2.transform
来代替Iterables.transform
。
我们也可以通过Functions.forPredicate
来创建简单的转换函数Function:
1 | List<String> list = Lists.newArrayList("java", "c#", " python"); |
组合多个转换函数:
1 | Function<String, String> f1 = new Function<String, String>() { |
我们也可以将过滤和转换组合在一起使用:
1 | Predicate<String> predicate = new Predicate<String>() { |
Iterables
除了上面涉及的Iterables的用法外,其还提供了许多别的好用的方法。
removeAll
该方法用于从特定集合中删除给定集合中的元素:
1 | List<String> removeFrom = Lists.newArrayList("a", "b", "c"); |
retainAll
retainAll的功能和removeAll相反:
1 | List<String> removeFrom = Lists.newArrayList("a", "b", "c"); |
addAll
addAll用于将给定集合添加到现有集合中:
1 | List<String> list1 = Lists.newArrayList("a", "b", "c"); |
concat
concat用于合并集合,组成一个新的集合对象:
1 | List<String> list1 = Lists.newArrayList("a", "b", "c"); |
Iterables还包含许多别的实用方法:
这里就不一一演示了,溜了。
更详细的内容可以参考guava官方wiki:https://github.com/google/guava/wiki