Caveats
说明
As of Java 7, functional programming in Java can only be approximated through awkward and verbose use of anonymous classes. This is expected to change in Java 8, but Guava is currently aimed at users of Java 5 and above.
在Java7中, 只能通过笨拙且啰嗦的使用匿名类来模拟函数式编程.在Java 8中这些亟待改变, 但Guava现在的目标是Java5及以上用户.
Excessive use of Guava's functional programming idioms can lead to verbose, confusing, unreadable, and inefficient code. These are by far the most easily (and most commonly) abused parts of Guava, and when you go to preposterous lengths to make your code "a one-liner," the Guava team weeps.
过多的使用Guava的函数式编程方言会导致啰嗦, 难懂, 可读性差以及低效的代码.这是迄今为止Guava中最容易被滥用的部分, 如果你开始使用一个可笑的长度的单行代码, Guava开发组就哭了!.
Compare the following code:
比较如下代码
Function<String,Integer> lengthFunction =new Function<String,Integer>(){
publicInteger apply(String string){
return string.length();
}
};
Predicate<String> allCaps = new Predicate<String>(){
public boolean apply(Stringstring){
return CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string);
}
};
Multiset<Integer> lengths =HashMultiset.create(
Iterables.transform(Iterables.filter(strings, allCaps), lengthFunction));
or the FluentIterable version
Multiset<Integer> lengths =HashMultiset.create(
FluentIterable.from(strings)
.filter(newPredicate<String>(){
publicboolean apply(Stringstring){
returnCharMatcher.JAVA_UPPER_CASE.matchesAllOf(string);
}
})
.transform(newFunction<String,Integer>(){
publicInteger apply(Stringstring){
returnstring.length();
}
}));
with:
Multiset<Integer> lengths =HashMultiset.create();
for(Stringstring: strings){
if(CharMatcher.JAVA_UPPER_CASE.matchesAllOf(string)){
lengths.add(string.length());
}
}
Even using static imports, even if the Function and the Predicate declarations are moved to a different file, the first implementation is less concise, less readable, and less efficient.
就算使用静态引入, 就算Function和Predicate的声明都放到一个不同的文件里, 第一种实现也不简介,可读性不好,且更低效
Imperative code should be your default, your first choice as of Java 7. You should not use functional idioms unless you are absolutely sure of one of the following:
命令式的代码应该是你的默认选择, 你的第一选择是Java 7. 除非你能够保证如下几点, 否则不应该使用函数式风格:
- Use of functional idioms will result in net savings of lines of code for your entire project. In the example above, the "functional" version used 11 lines, the imperative version 6. Moving the definition of a function to another file, or a constant, does not help.
- 使用函数式风格可以简化你整个项目的代码行. 在上面的例子中, 函数式版本使用了11行, 命令式是6行. 将函数的定义移动到另一个文件, 或者使用常量, 都是没有用的.
- For efficiency, you need a lazily computed view of the transformed collection and cannot settle for an explicitly computed collection. Additionally, you have read and reread Effective Java, item 55, and besides following those instructions, you have actually done benchmarking to prove that this version is faster, and can cite numbers to prove it.
- 为了效率, 你应该使用转换集合的懒计算视图, 并且不能接受一个显式计算的集合. 另外, 你已经一读再读 Effective Java, 第55条, 除了下面那些指令, 你真正做了基准测试来说明那个版本更快, 并且可以引用数字来证明它
Please be sure, when using Guava's functional utilities, that the traditional imperative way of doing things isn't more readable. Try writing it out. Was that so bad? Was that more readable than the preposterously awkward functional approach you were about to try?
请确定, 当使用Guava的functional工具类时, 传统的方法比使用这些工具类后更加不可读. 尝试把它写出来, 是不是有这么糟糕? 他不是不是比你想尝试的荒谬冗长的函数是方法更具有可读性.
Functions and Predicates
This article discusses only those Guava features dealing directly with Function and Predicate. Some other utilities are associated with the "functional style," such as concatenation and other methods which return views in constant time. Try looking in the collection utilities article.
这篇文章只讨论直接使用Function个Predicate的特性. 一些别的工具类也和函数风格编程有关, 例如常量和在常熟时间返回视图的其他方法.尝试看看collection utilities的文章.
Guava provides two basic "functional" interfaces:
Guava提供了两种基础的函数式接口:
- Function<A, B>, which has the single method B apply(A input). Instances of Function are generally expected to be referentially transparent -- no side effects -- and to be consistent with equals, that is, a.equals(b) implies thatfunction.apply(a).equals(function.apply(b)).
- Function<A, B>, 只有一个方法 B apply(A input). Function的实例通常被认为是参考透通性的 -- 没有副作用 -- 并且和equals一致, 就是说 a.equals(b)
- Predicate<T>, which has the single method boolean apply(T input). Instances of Predicate are generally expected to be side-effect-free and consistent with equals.
- Predicate<T>, 只有一个boolean apply(T input) 方法. Predicate的实例通常被认识无副作用且和equals一致
Special predicates
Characters get their own specialized version of Predicate, CharMatcher, which is typically more efficient and more useful for those needs.CharMatcher already implements Predicate<Character>, and can be used correspondingly, while conversion from a Predicate to aCharMatcher can be done using CharMatcher.forPredicate. Consult the CharMatcher article for details.
Characters有他们自己特殊的Predicate版本, CharMatcher, 他更有效率且对于某些方面更有作用. CharMatcher 已经实现了Predicate<Character>, 可以和predicate一样的使用, 将Predicate转换为CharMatcher可以使用CharMatcher.forPredicate完成.查阅the CharMatcher article 查看更多细节
Additionally, for comparable types and comparison-based predicates, most needs can be fulfilled using the Range type, which implements an immutable interval. The Range type implements Predicate, testing containment in the range. For example, Ranges.atMost(2) is a perfectly valid Predicate<Integer>. More details on using ranges can be found in the corresponding article.
另外, 对于可比较类型和基于比较的predicate, 大多数就需求可以通过使用Range类来满足, 它实现了一个不可变步长.Range类实现了Predicate, 可以进行范围测试. 例如, Ranges.atMost(2) 是一个完美验证的Predicate<Integer>. 跟多使用ranges的细节可以在in the corresponding article这里找到.
Manipulating Functions and Predicates
Simple Function construction and manipulation methods are provided in Functions, including
简单的Function构造和操作方法由Functions提供, 包括
apply(E e)返回key对应的val | compose(Function<B, C>, Function<A, B>) 返回一个组合两个Function的ComposeFunction, 他的C apply(A a)可以完成A->B->C的转换 | 返回一个apply(E e)返回常量T的Function | 返回一个apply(E e)会返回e本身的Function | 返回一个apply(E e)会返回e.toString()的方法 |
Consult the Javadoc for details.
细节请查阅Javadoc
There are considerably more construction and manipulation methods available in Predicates, but a sample includes:
在Predicates中有相当多的构造方法和操作方法, 下面是一些例子
apply判断当前元素是否是Class类型的实例 | apply判断当前元素是否给定Class的同类型和子类型 | apply判断当前元素是否包含给定Pattern | apply判断当前元素是否在给定集合中 |
apply判断元素是否为空 | apply永远为false | apply永远为true | apply判断当前元素是否与给定Object.equals |
apply先用Function转换在用Predicate判断 | 将多个Predicate使用and规则串联 | 将多个Predicate使用or规则串联 | apply返回原Predicate的非规则判断 |
Consult the Javadoc for details.
Using
Guava provides many tools to manipulate collections using functions and predicates. These can typically be found in the collection utility classesIterables, Lists, Sets, Maps, Multimaps, and the like.
Guava提供了非常多工具来使用functions和predicates来操作集合.这些可以在集合工具类 Iterables, Lists, Sets, Maps, Multimaps 等等中找到.
Predicates
The most basic use of predicates is to filter collections. All Guava filter methods return views.
predicates最基础的应用是用来过滤集合. 所有Guava过滤方法都返回视图, 以下所有方法都是通过Predicate过滤集合元素:
* A filtered List view is omitted, because operations such as get(int) could not be supported efficiently. Instead, useLists.newArrayList(Collections2.filter(list, predicate)) to make a copy.
List的过滤视图被省略了,因为get(int)操作不能被有效率的支持.替代的是, 使用 Lists.newArrayList(Collections2.filter(list, predicate))来生成一个副本
Other than simple filtering, Guava provides a number of additional utilities to manipulate iterables with predicates -- typically in the Iterablesutility class, and as "fluent" methods on a FluentIterable.
不同于简单的过滤, Guava提供了一些列额外的工具配合predicates处理这些可遍历的内容 -- 典型的是在 Iterables 工具类中, 还有带有 "fluent" 方法的FluentIterable.
Iterables Signature | Explanation | See also |
boolean all(Iterable, Predicate) | Do all the elements satisfy the predicate? Lazy: if it finds an element failing the predicate, doesn't iterate further. 判断是否所有元素都满足这个predicate? 懒执行: 如果它找到一个不符合predicate的元素, 就不会继续遍历了 | Iterators.all(Iterator, Predicate) FluentIterable.allMatch(Predicate) |
boolean any(Iterable, Predicate) | Do any of the elements satisfy the predicate? Lazy: only iterates until it finds an element satisfying the predicate. 是否存在满足predicate的元素? 懒执行: 如果找到符合的元素则不会继续遍历 | Iterators.any(Iterator, Predicate) FluentIterable.anyMatch(Predicate) |
T find(Iterable, Predicate) | Finds and returns an element satisfying the predicate, or throws a NoSuchElementException. 找到并返回一个满足predicate的元素,否则抛出一个NoSuchElementException的异常. | Iterators.find(Iterator, Predicate) Iterables.find(Iterable, Predicate, T default) Iterators.find(Iterator, Predicate, T default) |
Optional<T> tryFind(Iterable, Predicate) | Returns an element satisfying the predicate, or Optional.absent(). 返回一个满足predicate的元素,否则返回Optional.absent() | Iterators.tryFind(Iterator, Predicate) FluentIterable.firstMatch(Predicate) Optional |
indexOf(Iterable, Predicate) | Returns the index of the first element of the iterable satisfying the predicate, or -1 if no such element could be found. 返回第一个满足predicate的元素的坐标, 否则返回-1 | Iterators.indexOf(Iterator, Predicate) |
removeIf(Iterable, Predicate) | Removes all elements satisfying the predicate, using the Iterator.remove() method. 移除所有满足predicate的元素,使用的是Iterator.remove()方法 | Iterators.removeIf(Iterator, Predicate) |
Functions
By far the most common use of functions is transforming collections. All Guava transform methods return views of the original collection.
functions的常见用法是用来转换集合,所有的Guava的转换方法都会返回原始集合的视图.
* Map and Multimap have special methods that accept an EntryTransformer<K, V1, V2>, which associates keys with a new value computed from both the original value and the key, instead of just the value.
Map和Multimap有特殊的方法, 他们接收一个EntryTransformer<K, V1, V2>参数, 他将key和一个新的value关联起来,这个新value使用原始的k,v计算得到, 它用来代替旧的value
** A transform operation for Set is omitted, since an efficient contains(Object) operation could not be supported. Instead, useSets.newHashSet(Collections2.transform(set, function)) to create a copy of a transformed set.
对Set的转换操作被省略了, 因为不能有效的支持contains(Object)方法.代替的是使用 Sets.newHashSet(Collections2.transform(set, function))来创建一个转换set的副本
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,
newEntryTransformer<String,String,String>(){
publicString transformEntry(String firstName,String lastName){
return firstName +" "+ lastName;
}
});
Types that can be "composed" with functions include:
可以组合Function的类包括:
Ordering | Ordering.onResultOf(Function) |
Predicate | Predicates.compose(Predicate, Function) |
Equivalence | Equivalence.onResultOf(Function) |
Supplier | Suppliers.compose(Function, Supplier) |
Function | Functions.compose(Function, Function) |
Additionally, the ListenableFuture API supports transforming listenable futures. Futures also provides methods accepting an AsyncFunction, a variation on Function that allows values to be computed asynchronously.
另外, ListenableFutrure API支持转换listenable futures. Futures也提供一个接收AsyncFunction的方法, 一个允许异步计算值的Function变种.