Google Guava - FunctionalExplained(Guava函数式风格说明)

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 操作集合的工具方法. 通常出现在如下工具类中:IterablesListsSetsMapsMultimaps...

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)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值