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 函数式编程