Functional Utilities
Caveats
Java 8 包含 java.util.function
与 java.util.stream
包, 它取代了 Guava 的函数式编程用于该语言级别的项目。
虽然Guava 的函数式工具可以再Java 8之前的版本上使用,但是没有Java 8的函数式编程就需要使用笨拙且冗长的匿名类。
过度使用Guava的功能性编程语句会导致冗长、混乱、不可读和低效的代码。到目前为止,这些是Guava中最容易被滥用的部分(也是最常见),并且当你为了让你的代码成为“一行程序”而费尽心机时,Guava团队会流泪。
Compare the following code:
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.javaUpperCase().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(new Predicate<String>() {
public boolean apply(String string) {
return CharMatcher.javaUpperCase().matchesAllOf(string);
}
}) .transform(new Function<String, Integer>() {
public Integer apply(String string) {
return string.length();
}
}));
with:
Multiset<Integer> lengths = HashMultiset.create();
for (String string : strings) {
if (CharMatcher.javaUpperCase().matchesAllOf(string)) {
lengths.add(string.length());
}
}
即使使用静态导入,即使和谓词声明的功能被移动到不同的文件中,第一个实现更简洁,可读性下降,效率较低。
命令式代码应该是默认的,是Java 7的首选。你不应该使用功能性语句,除非你绝对确信下列之一:
- 使用函数式语句会节省整个项目的代码行。在上面的示例中,“功能”版本使用了11行,即命令版本6。把函数的定义移到另一个文件,或常数,是没有帮助的。
-
为了提高效率,您需要转换后的集合的惰性计算视图,并且不能满足于显式计算的集合。此外,您已经阅读并重读了有效的Java,项目55,并且除了遵循这些指令之外,您还进行了基准测试以证明该版本更快,并且可以引用数字来证明它。
请确保,当使用Guava的功能实用程序时,传统的命令式的做事方式是不可读的。试着把它写出来。那么糟糕吗?这比你要尝试的笨拙的功能性方法更可读吗?
Functions and Predicates
本文仅讨论那些直接涉及Function
和Predicate
的Guava 特征。其他一些实用程序与“函数样式”相关联,比如连接和其他在恒定时间内返回视图的方法。 尝试查看集合实用工具文章。
Guava 提供两个基础的"functional" 接口:
Function<A, B>
, 只有一个单独的B apply(A input)
方法.Function
实例通常被认为是透明的--无副作用 -- 以及一致性等价, ,a.equals(b)
相当于function.apply(a).equals(function.apply(b))
.-
Predicate<T>
, 只有一个boolean apply(T input)
方法.Predicate
的实例一般预期是无副作用的,并且与equal一致。
Special predicates
字符获得他们自己的Predicate
专业版本, CharMatcher
, 这通常是更有效和更有用的那些需求。CharMatcher
已经实现了Predicate<Character>
, 并且可以相应地使用, 当 Predicate
转换为 CharMatcher
时可以使用CharMatcher.forPredicate
. 细节请参考CharMatcher
article .
此外,对于可比类型和基于比较的谓词,大多数需求都可以使用实现不可变间隔的Range类型来满足。范围类型实现谓词,在范围内测试包容。例如,Ranges.atMost(2)
是一个完全有效的Predicate<Integer>
。关于使用范围的更多细节可以在范围文章中找到。
Manipulating Functions and Predicates
Simple Function
construction and manipulation methods are provided in Functions
, including
Consult the Javadoc for details.
There are considerably more construction and manipulation methods available in Predicates
, but a sample includes:
instanceOf(Class)
assignableFrom(Class)
contains(Pattern)
in(Collection)
isNull()
alwaysFalse()
,alwaysTrue()
equalTo(Object)
compose(Predicate, Function)
and(Predicate...)
,or(Predicate...)
,not(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 classes Iterables
, Lists
, Sets
, Maps
, Multimaps
, and the like.
Predicates
The most basic use of predicates is to filter collections. All Guava filter methods return views.
Collection type | Filter methods |
---|---|
Iterable | Iterables.filter(Iterable, Predicate) FluentIterable.filter(Predicate) |