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

来源:互联网 发布:c语言图形界面设计 编辑:程序博客网 时间:2024/05/22 03:26

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过滤器方法都只返回原集合对应的视图.

集合类型过滤器方法IterableIterables.filter(Iterable, Predicate)FluentIterable.filter(Predicate)IteratorIterators.filter(Iterator, Predicate)CollectionCollections2.filter(Collection, Predicate)SetSets.filter(Set, Predicate)SortedSetSets.filter(SortedSet, Predicate)MapMaps.filterKeys(Map, Predicate)Maps.filterValues(Map, Predicate)Maps.filterEntries(Map, Predicate)SortedMapMaps.filterKeys(SortedMap, Predicate)Maps.filterValues(SortedMap, Predicate)Maps.filterEntries(SortedMap, Predicate)MultimapMultimaps.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转换方法都只返回原集合对应的视图.

集合类型转换方法IterableIterables.transform(Iterable, Function)FluentIterable.transform(Function)IteratorIterators.transform(Iterator, Function)CollectionCollections2.transform(Collection, Function)ListLists.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)TableTables.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 nameListMultimap<String, String> firstNameToName = Multimaps.transformEntries(firstNameToLastNames,  new EntryTransformer<String, String, String> () {    public String transformEntry(String firstName, String lastName) {      return firstName + " " + lastName;    }  });

可以组合使用 functions 的类型包括:

OrderingOrdering.onResultOf(Function)PredicatePredicates.compose(Predicate, Function)EquivalenceEquivalence.onResultOf(Function)SupplierSuppliers.compose(Function, Supplier)FunctionFunctions.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)
0 0
原创粉丝点击