目录
guava
最近在公司的项目中注意到了一个依赖guava,在项目中很多地方都用到了它,特别是集合转换时大量使用,而Guava的通用性和实用性相信每一个javaer都有所体会,今天就来介绍一下这款来自Google的Java核心工具库。
官方是这样介绍Guava
Guava is a set of core Java libraries from Google that includes new collection types (such as multimap and multiset), immutable collections, a graph library, and utilities for concurrency, I/O, hashing, primitives, strings, and more! It is widely used on most Java projects within Google, and widely used by many other companies as well.
翻译过来就是,Guava 是 Google 的一组核心 Java 库,其中包括新的集合类型(例如 multimap 和 multiset)、不可变集合、图形库以及用于并发、I/O、哈希、原语、字符串等的实用程序!它被广泛用于 Google 内部的大多数 Java 项目,也被许多其他公司广泛使用。
使用
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.3.0-jre</version>
<!-- or, for Android: -->
<version>33.3.0-android</version>
</dependency>
Collections(集合)
Immutable collections
public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
"red",
"orange",
"yellow",
"green",
"blue",
"purple");
class Foo {
final ImmutableSet<Bar> bars;
Foo(Set<Bar> bars) {
this.bars = ImmutableSet.copyOf(bars); // defensive copy!
}
}
- 可以被不受信任的库安全使用
- 可以在多线程间没有竞争条件风险的使用
- 可以用作常数,并期望它保持不变。
New collection types
Guava 引入了许多 JDK 中没有的新集合类型,结果发现它们非常有用。这些都是为了与 JDK 集合框架愉快地共存而设计的,而不是将某些东西硬塞到 JDK 集合抽象中。
Multiset(多集)
统计一个单词在文本中出现了多少次是这样的
Map<String, Integer> counts = new HashMap<String, Integer>();
for (String word : words) {
Integer count = counts.get(word);
if (count == null) {
counts.put(word, 1);
} else {
counts.put(word, count + 1);
}
}
multiset.add(word)就能解决上述问题
Multimap
结果类似于Map<K, List> 或 Map<K, Set>。例如,Map<K, Set> 是表示无标签有向图的典型方式。 Guava 的 Multimap 框架可以轻松处理从键到多个值的映射。多重映射是将键与任意多个值关联起来的通用方法。
// 创建一个按键排序的Multimap
Multimap<String, Integer> treeMultimap = MultimapBuilder.treeKeys().hashSetValues().build();
// 创建一个使用哈希表存储键的Multimap
Multimap<String, Integer> hashMultimap = MultimapBuilder.hashKeys().arrayListValues().build();
Bimap
将值映射回键的传统方法是维护两个单独的映射并使它们保持同步,但这很容易出现错误,并且当值已存在于映射中时可能会变得非常混乱。
Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();
nameToId.put("Bob", 42);
idToName.put(42, "Bob");
// what happens if "Bob" or 42 are already present?
// weird bugs can arise if we forget to keep these in sync...
BiMap<K, V>
允许您使用 inverse() 查看反映射BiMap<V, K>
确保值是唯一的,使values()成为一个Set
如果您尝试将键映射到已经存在的值,BiMap.put(key, value) 将抛出 IllegalArgumentException。如果您希望删除具有指定值的任何预先存在的条目,请改用 BiMap.forcePut(key, value)
BiMap<String, Integer> userId = HashBiMap.create();
...
String userForId = userId.inverse().get(id);
New collection出了上面三个常用的类型外,还有Table、ClassToInstanceMap、RangeSet、RangeMap,这些在 [github](GitHub - google/guava: Google core libraries for Java) 上有详细介绍和用法示例
Extension utilities
Forwarding Decorators(转发装饰器)
对于所有各种集合接口,Guava 提供了 Forwarding 抽象类来简化装饰器模式的使用。
class AddLoggingList<E> extends ForwardingList<E> {
final List<E> delegate; // backing list
@Override protected List<E> delegate() {
return delegate;
}
@Override public void add(int index, E elem) {
log(index, elem);
super.add(index, elem);
}
@Override public boolean add(E elem) {
return standardAdd(elem); // implements in terms of add(int, E)
}
@Override public boolean addAll(Collection<? extends E> c) {
return standardAddAll(c); // implements in terms of add
}
}
PeekingIterator
Iterators 支持 Iterators.peekingIterator(Iterator) 方法,该方法包装 Iterator 并返回 PeekingIterator,它是 Iterator 的子类型,可让您 peek() 查找下一次调用 next() 将返回的元素。
List<E> result = Lists.newArrayList();
PeekingIterator<E> iter = Iterators.peekingIterator(source.iterator());
while (iter.hasNext()) {
E current = iter.next();
while (iter.hasNext() && iter.peek().equals(current)) {
// skip this duplicate element
iter.next();
}
result.add(current);
}
Graphs
-
Definitions
graph.addEdge(nodeU, nodeV, edgeUV);
- nodeU和nodeV是互相邻近的
- edgeUV关联nodeU和nodeV,反之亦然
如果是有向图
- nodeU是nodeV的前者
- nodeV是nodeU的后者
- edgeUV是nodeU的出边
- edgeUV是nodeV的入边
- nodeU是edgeUV的源头
- nodeV是edgeUV的终点
如果是无向图
- nodeU是nodeV的前者和后者
- nodeV是nodeU的前者和后者
- edgeUV是nodeU的入边和出边
- edgeUV是nodeV的入边和出边
Graph
Graph是最简单、最基本的图类型。它定义了处理节点到节点关系的低级运算符,例如 successors(node)、adjacentNodes(node) 和 inDegree(node)。它的节点是一级唯一对象;您可以将它们视为类似于将键映射到图形内部数据结构中
ValueGraph
ValueGraph是带权重的Graph
Network
Network 具有 Graph 所具有的所有与节点相关的方法,但添加了处理边和节点到边关系的方法,例如 outEdges(node)、incidentNodes(edge) 和 EdgesConnecting(nodeU, nodeV)。
构建图实例
// Creating mutable graphs
MutableGraph<Integer> graph = GraphBuilder.undirected().build();
MutableValueGraph<City, Distance> roads = ValueGraphBuilder.directed()
.incidentEdgeOrder(ElementOrder.stable())
.build();
MutableNetwork<Webpage, Link> webSnapshot = NetworkBuilder.directed()
.allowsParallelEdges(true)
.nodeOrder(ElementOrder.natural())
.expectedNodeCount(100000)
.expectedEdgeCount(1000000)
.build();
// Creating an immutable graph
ImmutableGraph<Country> countryAdjacencyGraph =
GraphBuilder.undirected()
.<Country>immutable()
.putEdge(FRANCE, GERMANY)
.putEdge(FRANCE, BELGIUM)
.putEdge(GERMANY, BELGIUM)
.addNode(ICELAND)
.build();
图的遍历
Iterable<Path> iterable =
Traverser.<Path>forTree(
// This lambda function implements SuccessorsFunction, which returns the
// successor nodes of a given node.
path -> path.isDirectory() ? path.listFiles() : ImmutableList.of())
.breadthFirst(Path.ROOT);
stream(iterable).filter(path -> containsText(path, query)).findFirst();
还有可变图和不可变图等等,Guava里的图对象和数学概念相对应,这些概念和应用在我们大多数项目中极少用到,不必太过深究,确实碰到了,我们也可以查阅 [github](GitHub - google/guava: Google core libraries for Java) 上Guava工程师写的文档,进一步了解Graph的使用。