https://github.com/google/guava/wiki/NewCollectionTypesExplained
guava 对jdk原生的Collection类型进行了扩充;
允许存在重复元素/Key的Set or Map
- 提供了相应允许重复的版本名为Multixxx, 如 MultiSet, MultiMap(特意提到并不是只是接口很像,但是并不是基于Map or Set的实现); 并提供两种视图,一种是转成List, 另一种是转成Map<K, Collection<V>>类型; 的确是很有用的,可能作用到的场景;
- 元素统计;
- 分组, Collection.groupby;
- 有些场景,我是想将原始Map的key 和 value对调的, MultiMap就可以做到;
BitMap 一种可以方便交换Key Value的Map
- 上面刚提到想要交换Key, Value,这里就提供了专属的Map;再很多场景下,我们的Map希望存储的是PAIR的概念,key 和 value 分别并不是那么明显,都有可能要作为检索的关键字; 刚好可以使用BitMap;
- 从文档描述来看, BitMap 只能处理 key 和 value是一一对应的case;
RangSet 该Set的元素是一个Range<T extend Comparable>, 它可以实现对期间进行拆分,合并等功能
- 此前因为工作需要(开发一个划分按照日期划分收租的系统),写过类似的功能; 但是当时并没有进一步想过去推广到所有实现了Comparable的Type;
简单测试了一下可用, 不过仍然存在几点问题;- 我们可以把这个RangeSet理解为一个集合的概念, 那么就又交集,并集等操作,可以发现Range.class里的确有相关操作(intercourse, span...etc)
- 我们日常对日期的划分,往往是需要按照给定一个期间,按照年份,月份,季度 or 其他因素进行划分; 所以这个API在具体场景下, 是有进一步封装的必要;
RangeSet<Date> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(DateUtil.str2Date("2019-01-31"), DateUtil.str2Date("2019-02-27")));
rangeSet.add(Range.closed(DateUtil.str2Date("2019-01-31"), DateUtil.str2Date("2019-02-27")));
rangeSet.add(Range.openClosed(DateUtil.str2Date("2019-03-31"), DateUtil.str2Date("2019-04-27")));
rangeSet.add(Range.closed(DateUtil.str2Date("2019-05-01"), DateUtil.str2Date("2019-08-27")));
rangeSet.remove(Range.closed(DateUtil.str2Date("2019-06-01"), DateUtil.str2Date("2019-06-30")));
rangeSet.asRanges().forEach(a -> {
System.out.println(String.format("Date Period %s%s to %s%s", a.lowerBoundType() == BoundType.CLOSED ? "[" : "(", DateUtil.date2Str(a.lowerEndpoint())
, DateUtil.date2Str(a.upperEndpoint()), a.upperBoundType() == BoundType.CLOSED ? "]" : ")"));
});
//输出的结果
Date Period [2019-01-31 to 2019-02-27]
Date Period (2019-03-31 to 2019-04-27]
Date Period [2019-05-01 to 2019-06-01)
Date Period (2019-06-30 to 2019-08-27]
guava集合工具集说明
https://github.com/google/guava/wiki/CollectionUtilitiesExplained
-
工具命名都是后面加S(除Collection 命名为Collections); 就如java nio File->Files, Path -> paths;
以后做工具,也按照这个规范命名好了;
image.png - 类似于Arrays.asList,不过它返回的是可以可以进行添加删除操作的List; Arrays.asList是个比较坑的设计,见过不少人出过错;以后可以使用Lists.newArrayList避免出错,并且可以帮忙初始化List容量;
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
- 一般而言我们对性能没这种偏执的要求,但是知道一下;
List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);
Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);
看了一眼源码,设计者还没具体描述他预估容量算法的依据;
- Iterables
- 在Iterables工具中并没法什么对我有价值的功能,都是很基础的功能(这些功能很基础,但是还是很有价值的,比如可以把一个文件流像集合类一样操作,只是一般不需要);而且我个人更偏向于自己实现内部迭代;
Whenever possible, Guava prefers to provide utilities accepting an Iterable rather than a Collection. Here at Google, it's not out of the ordinary to encounter a "collection" that isn't actually stored in main memory, but is being gathered from a database, or from another data center, and can't support operations like size() without actually grabbing all of the elements.
对这句话倒是很有感触, 不仅仅要面向抽象/接口编程,而且要尽可能的面向更底层的抽象和接口编程;这一方面增加了对设计者抽象能力的要求,还免不了拆分/细分工作;因为有迭代器的并不仅仅Collection;希望guava可以切实做到这点,这样我的一些其他类可以使用它的方法了;
Sets 提供了一些基础的集合操作;这个自己也曾经实现过; 结合Range.class,有Range.class和集合互相转化的方法吗?
-
Maps
- 下面这个方法应该有用,它接受的是个Iterable, 可以很方便的将一个可遍历的Object转成Map;
//public static <K,V> ImmutableMap<K,V> uniqueIndex(Iterable<V> values, Function<? super V,K> keyFunction) ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings, new Function<String, Integer> () { public Integer apply(String string) { return string.length(); } });
-
Multimaps
- invertFrom K,V调换Multimaps版本;有用;
ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create(); multimap.putAll("b", Ints.asList(2, 4, 6)); multimap.putAll("a", Ints.asList(4, 2, 1)); multimap.putAll("c", Ints.asList(2, 5, 3)); TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap.<String, Integer> create()); // note that we choose the implementation, so if we use a TreeMultimap, we get results in order /* * inverse maps: * 1 => {"a"} * 2 => {"a", "b", "c"} * 3 => {"c"} * 4 => {"a", "b"} * 5 => {"c"} * 6 => {"b"} */
- forMap 将普通的Map 转成MultiMap(如前所述,Multimap的实现与java原生的Map是完全不同的),然后使用Multimap的一些功能;
Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2); SetMultimap<String, Integer> multimap = Multimaps.forMap(map); // multimap maps ["a" => {1}, "b" => {1}, "c" => {2}] Multimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap.<Integer, String> create()); // inverse maps [1 => {"a", "b"}, 2 => {"c"}]
-
Wraps
- 一个集合的设计方法规范;如果设计一个A(必须是个一个接口), 那么提供了3个版本;普通实现版本, 不可变版本(Unmodifiable),应对并发版本(Synchronized), 以及一个factory 让用户可以选择自定义A的实现细节,如下;
ListMultimap<String, Integer> myMultimap = Multimaps.newListMultimap( Maps.<String, Collection<Integer>>newTreeMap(), new Supplier<LinkedList<Integer>>() { public LinkedList<Integer> get() { return Lists.newLinkedList(); } });