Google Guava - FunctionalExplained(Guava函数式风格说明)
2014-06-16 13:28
841 查看
FunctionalExplained 函数式风格说明
Functional idioms in Guava, explained. explained
Updated Apr 10, 2013 by lowas...@google.com
重要说明
直到 Java 7, 想要在 Java 中实现函数式编程,只能通过笨重的匿名类来达到近似效果。这种情况在 Java 8 会有所改观, 但是 Guava 现在已经给 Java 5 以上版本的用户提供了支持.Guava函数式编程过度使用会导致冗长、混乱、可读性差而且低效的代码。这是Guava中迄今为止最容易(也最经常)被滥用的部分。如果你想通过函数式风格达成一行长到匪夷所思的代码,Guava团队也只有哭的份了。
比较如下代码:
Function<String, Integer> lengthFunction = new Function<String, Integer>() { public Integer apply(String string) { return string.length(); } }; Predicate<String> allCaps = new Predicate<String>() { public boolean apply(String string) { return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string); } }; Multiset<Integer> lengths = HashMultiset.create( Iterables.transform(Iterables.filter(strings, allCaps), lengthFunction));
或是
FluentIterable版本:
Multiset<Integer> lengths = HashMultiset.create( FluentIterable.from(strings) .filter(new Predicate<String>() { public boolean apply(String string) { return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string); } }) .transform(new Function<String, Integer>() { public Integer apply(String string) { return string.length(); } }));
或者:
Multiset<Integer> lengths = HashMultiset.create(); for (String string : strings) { if (CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string)) { lengths.add(string.length()); } }
即使使用静态导入,甚至把Function和Predicate的声明放到其他文件,第一种代码实现仍然不简洁,可读性差并且效率低。
直到Java 7,命令式代码依然应该是你的默认选择。不应该随意使用函数式编程,直到你确信面临以下两点之一:
使用函数式编程会使整个工程的代码明显减少. 上面的例子中, “函数式”的版本用了 11 行来实现, 命令式只用了 6行. 把函数的定义放到另一个文件或常量中,对减少总代码行毫无帮助。
为了提高效率,转换集合的结果需要Lazy视图,而不是明确计算过的集合。此外,确保你已经阅读和重读了Effective Java的第55条,并且除了阅读本章后面的说明,你还真正做了性能测试并且有测试数据来证明函数式版本更快。
务必确保,当使用Guava函数式编程的时候,用传统的命令式做同样的事情不会更具可读性。尝试把代码写下来,看看它是不是真的那么糟糕?会不会比你想尝试的极其笨拙的函数式 更具可读性。
Functions and Predicates(函数和断言)
本章只讨论直接处理Function和
Predicate的Guava特性 .
还有一些其他工具类和函数式风格有关,例如流式风格和在指定时间内返回视图. 请参考 collection utilities .
Guava 提供两个基本 "functional" 接口:
Function<A, B>, 声明了单个方法
B apply(A input).
Function通常被期待是引用透明的-- 无副作用 -- 且 ”equals ”语义 和 equals 一致。
a.equals(b)等同
function.apply(a).equals(function.apply(b)).
Predicate<T>, 声明了单个方法
boolean apply(T input).
Predicate通常也被期待为无副作用函数,并且”equals ”语义与equals一致。
特殊断言
Characters 有自己的特殊Predicate:
CharMatcher, 它通常在一些特殊情况下更高效,更有用。
CharMatcher实现了
Predicate<Character>,
可以同等使用。可以使用
CharMatcher.forPredicate 转换
Predicate到
CharMatcher。详情参见 the
CharMatcher article .
另外, 对于可比较类型和基于比较的 predicates, 使用
Range可以满足绝大部冯需求, 他表示了一个不可变区间.
Range类型实现了
Predicate,
用于判断值是否在区间内. 例如,
Ranges.atMost(2)是一个有效的
Predicate<Integer>.
详情参见 in the corresponding article.
操作 Functions 和 Predicates
Functions 中提供了简单的 Function的构造和操作方法:
forMap(Map<A, B>) | compose(Function<B, C>, Function<A, B>) | constant(T) | identity() | toStringFunction() |
同样 Predicates 中也提供了简单的 Predicate
的构造和操作方法:
instanceOf(Class) | assignableFrom(Class) | contains(Pattern) | in(Collection) |
isNull() | alwaysFalse() | alwaysTrue() | equalTo(Object) |
compose(Predicate, Function) | and(Predicate...) | or(Predicate...) | not(Predicate) |
使用
Guava 提供了大量使用 functions 和 predicates 操作集合的工具方法. 通常出现在如下工具类中:Iterables,
Lists,
Sets,
Maps,
Multimaps...
Predicates(断言)
断言最基本的应用就是过滤集合. 所有的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) |
*由于诸如get(int)之类的操作不能被有效支持,
List视图的过滤操作被省略了。代之使用
Lists.newArrayList(Collections2.filter(list, predicate))来完成类似操作.
不同于简单的过滤, Guava 提供了一系列增强工具使用predicates 处理 iterables -- 通常在
Iterables
工具类中,
或是在
FluentIterable的流式调用方法中。
Iterables方法签名 | 说明 | 参见 |
boolean all(Iterable, Predicate) | 是否所有元素满足断言? Lazy: 如果有元素不满足断言,停止迭代 . | Iterators.all(Iterator, Predicate) FluentIterable.allMatch(Predicate) |
boolean any(Iterable, Predicate) | 是否任何元素满足断言? Lazy: 如果有元素满足断言,停止迭代 . | 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.tryFind(Iterator, Predicate) FluentIterable.firstMatch(Predicate) Optional |
indexOf(Iterable, Predicate) | 返回第一个满足元素断言的元素索引值,否则返回 -1. | Iterators.indexOf(Iterator, Predicate) |
removeIf(Iterable, Predicate) | 删除所有满足元素断言的元素 , 内部使用 Iterator.remove()方法实现。 | Iterators.removeIf(Iterator, Predicate) |
Functions(函数)
目前函数最基本的应用就是转换集合. 所有的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>, 它可以使用旧的键值来计算,并且用计算结果替换旧值。
** 由于诸如
contains(Object)之类的操作不能被有效支持,
Set视图的过滤操作被省略了。代之使用
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; } });
可以组合使用 functions 的类型包括:
Ordering | Ordering.onResultOf(Function) |
Predicate | Predicates.compose(Predicate, Function) |
Equivalence | Equivalence.onResultOf(Function) |
Supplier | Suppliers.compose(Function, Supplier) |
Function | Functions.compose(Function, Function) |
Futures也提供转换
AsyncFunction的方法,AsyncFunction 是允许异步计算数值的
Function。
Futures.transform(ListenableFuture, Function) | Futures.transform(ListenableFuture, Function, Executor) |
Futures.transform(ListenableFuture, AsyncFunction) | Futures.transform(ListenableFuture, AsyncFunction, Executor) |
相关文章推荐
- [Google Guava] 4-函数式编程
- [Google Guava] 1.4 排序: Guava强大的”流畅风格比较器”
- 有关google的guava工具包详细说明
- [Google Guava] 1.4排序: Guava强大的”流畅风格比较器”
- [Google Guava] 排序: Guava强大的”流畅风格比较器”
- Google Guava 类库简介
- google guava简单使用
- Google 开源项目风格指南 Python风格规范
- google出品的各程序设计语言编码风格
- Google Guava官方教程(中文版)
- 用户界面设计风格说明下
- [C++] 编程实践之1: Google的C++代码风格3:类
- 第三方类库-Core核心库-Google Guava-2
- 【Google 应用内付】说明
- JDK8新特性:函数式接口@FunctionalInterface的使用说明
- Google-Guava-EventBus源码解读
- Google guava 集合的创建特性和只读特性
- Google C++ 风格指南 - 中文版
- Google排名和Google推广的关系简要说明
- Google 编码风格之命名规范(备忘)