您的位置:首页 > 大数据 > 人工智能

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()
细节参见 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 提供了大量使用 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)
此外, ListenableFuture API 支持转换 listenable futures。 
Futures
 也提供转换 
AsyncFunction 
的方法,AsyncFunction 是允许异步计算数值的 
Function
 。
Futures.transform(ListenableFuture,
Function)
Futures.transform(ListenableFuture,
Function, Executor)
Futures.transform(ListenableFuture,
AsyncFunction)
Futures.transform(ListenableFuture,
AsyncFunction, Executor)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息