Guava functional 函数式编程
Guava 的函数式支持可以显著简化代码,但请谨慎使用它
本节只讨论直接与 Function 和 Predicate 打交道的Guava功能。一些其他工具类也和”函数式风格”相关,在使用过程中,会相继学习认识到。
一、Functions[函数] 和 Predicates[断言]
Function<A, B>它声明了单个方法B apply(A input)。
Function 对象通常被预期为引用透明的,没有副作用,并且引用透明性中的”相等”语义与 equals 一致,如 a.equals(b)意味着 function.apply(a).equals(function.apply(b))。
Predicate<T>它声明了单个方法boolean apply(T input)。
Predicate 对象通常也被预期为无副作用函数,并且”相等”语义与 equals 一致。
二、特殊的断言
字符类型有自己特定版本的 Predicate。
CharMatcher 实现了 Predicate<Character>,可以当作 Predicate 一样使用,要把 Predicate 转成 CharMatcher,可以使用 CharMatcher.forPredicate。
此外,对可比较类型和基于比较逻辑的 Predicate,Range 类可以满足大多数需求,它表示一个不可变区间。Range 类实现了 Predicate,用以判断值是否在区间内。例如:Range.atMost(2) 就是个完全合法的 Predicate<Integer>。
三、操作 Functions 和 Predicates
Functions 提供简便的 Function 构造和操作方法,包括:
forMap(Map<A, B>)compose(Function<B, C>, Function<A, B>)constant(T)identity()toStringFunction()
细节请参考Javadoc。
相应地,Predicates 提供了更多构造和处理 Predicate 的方法,下面是一些例子:
instanceOf(Class)assignableFrom(Class)contains(Pattern)in(Collection)isNull()alwaysFalse()alwaysTrue()equalTo(Object)compose(Predicate, Function)and(Predicate...)or(Predicate...)not(Predicate)
节请参考Javadoc。
四、使用函数式编程
Guava 提供了很多工具方法,以便用 Function 或 Predicate 操作集合。这些方法通常可以在集合工具类找到,如 Iterables,Lists,Sets,Maps,Multimaps等。
五、断言
断言的最基本应用就是过滤集合。所有Guava过滤方法都返回”视图”,而视图并非用一个新的集合表示过滤,而只是基于原集合的视图。
| 集合类型 | 过滤方法 | 
|---|---|
Iterable | Iterables.filter(Iterable, Predicate) FluentIterable.filter(Predicate) | 
Iterator | Iterators.filter(Iterator, Predicate) | 
Collection | Collections2.filter(Collection, Predicate) | 
Set | Sets.filter(Set, Predicate) | 
SortedSet | Sets.filter(SortedSet, Predicate) | 
Map | Maps.filterKeys(Map, Predicate) Maps.filterValues(Map, Predicate) Maps.filterEntries(Map, Predicate) | 
SortedMap | Maps.filterKeys(SortedMap, Predicate) Maps.filterValues(SortedMap, Predicate) Maps.filterEntries(SortedMap, Predicate) | 
Multimap | Multimaps.filterKeys(Multimap, Predicate) Multimaps.filterValues(Multimap, Predicate) Multimaps.filterEntries(Multimap, Predicate) | 
List 的过滤视图被省略了,因为不能有效地支持类似 get(int) 的操作。请改用 Lists.newArrayList(Collections2.filter(list, predicate)) 做拷贝过滤。
除了简单过滤,Guava 另外提供了若干用 Predicate 处理 Iterable 的工具——通常在 Iterables 工具类中,或者是 FluentIterable 的 fluent(链式调用)方法。
| Iterables方法签名 | 说明 | 另请参见 | 
|---|---|---|
boolean all(Iterable, Predicate) | 是否所有元素满足断言?懒实现:如果发现有元素不满足,不会继续迭代 | Iterators.all(Iterator, Predicate)FluentIterable.allMatch(Predicate) | 
boolean any(Iterable, Predicate) | 是否有任意元素满足元素满足断言?懒实现:只会迭代到发现满足的元素 | Iterators.any(Iterator, Predicate)FluentIterable.anyMatch(Predicate) | 
T find(Iterable, Predicate) | 循环并返回一个满足元素满足断言的元素,如果没有则抛出 NoSuchElementException | Iterators.find(Iterator, Predicate) Iterables.find(Iterable, Predicate, T default) Iterators.find(Iterator, Predicate, T default) | 
Optional<T>tryFind(Iterable, Predicate) | 返回一个满足元素满足断言的元素,若没有则返回 Optional.absent() | Iterators.find(Iterator, Predicate) Iterables.find(Iterable, Predicate, T default) Iterators.find(Iterator, Predicate, T default) | 
indexOf(Iterable, Predicate) | 返回第一个满足元素满足断言的元素索引值,若没有返回-1 | Iterators.indexOf(Iterator, Predicate) | 
removeIf(Iterable, Predicate) | 移除所有满足元素满足断言的元素,实际调用 Iterator.remove() 方法 | Iterators.removeIf(Iterator, Predicate) | 
六、函数
到目前为止,函数最常见的用途为转换集合。同样,所有的Guava转换方法也返回原集合的视图。
| 集合类型 | 转换方法 | 
|---|---|
Iterable | Iterables.transform(Iterable, Function) FluentIterable.transform(Function) | 
Iterator | Iterators.transform(Iterator, Function) | 
Collection | Collections2.transform(Collection, Function) | 
List | Lists.transform(List, Function) | 
Map | Maps.transformValues(Map, Function) Maps.transformEntries(Map, EntryTransformer) | 
SortedMap | Maps.transformValues(SortedMap, Function) Maps.transformEntries(SortedMap, EntryTransformer) | 
Multimap | Multimaps.transformValues(Multimap, Function) Multimaps.transformEntries(Multimap, EntryTransformer) | 
ListMultimap | Multimaps.transformValues(ListMultimap, Function) Multimaps.transformEntries(ListMultimap, EntryTransformer) | 
Table | Tables.transformValues(Table, Function) | 
Map 和 Multimap 有特殊的方法,其中有个 EntryTransformer<K, V1, V2> 参数,它可以使用旧的键值来计算,并且用计算结果替换旧值。
对 Set 的转换操作被省略了,因为不能有效支持 contains(Object) 操作,懒视图实际上不会全部计算转换后的 Set 元素,因此不能高效地支持 contains(Object),改用 Sets.newHashSet(Collections2.transform(set, function)) 进行拷贝转换。
List<String> names;
Map<String, Person> personWithName;
List<Person> people = Lists.transform(names, Functions.forMap(personWithName));
ListMultimap<String, String> firstNameToLastNames;
// maps first names to all last names of people with that first name
ListMultimap<String, String> firstNameToName = Multimaps.transformEntries(firstNameToLastNames,
    new EntryTransformer<String, String, String> () {
        public String transformEntry(String firstName, String lastName) {
            return firstName + " " + lastName;
        }
    });可以组合 Function 使用的类包括:
| 类名 | 方法 | 
|---|---|
Ordering | Ordering.onResultOf(Function) | 
Predicate | Predicates.compose(Predicate, Function) | 
Equivalence | Equivalence.onResultOf(Function) | 
Supplier | Suppliers.compose(Function, Supplier) | 
Function | Functions.compose(Function, Function) | 
此外,ListenableFuture API支持转换 ListenableFuture。
Futures 也提供了接受 AsyncFunction 参数的方法,AsyncFunction 是 Function 的变种,它允许异步计算值。
| 方法 | 
|---|
Futures.transform(ListenableFuture, Function) | 
Futures.transform(ListenableFuture, Function, Executor) | 
Futures.transform(ListenableFuture, AsyncFunction) | 
Futures.transform(ListenableFuture, AsyncFunction, Executor) | 
七、相关文章
未经允许请勿转载:程序喵 » Google Guava 快速入门 —— functional 函数式编程
程序喵