Chapter 7 -- Functional
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变种.
Chapter 7 -- Functional的更多相关文章
- a primary example for Functional programming in javascript
background In pursuit of a real-world application, let’s say we need an e-commerce web applicationfo ...
- C# 第十版
地址: https://files.cnblogs.com/files/blogs2014/%E9%AB%98%E7%BA%A7%E7%BC%96%E7%A8%8B%28%E7%AC%AC11%E7% ...
- Java 8 实战 P4 Beyond Java 8
目录 Chapter 13. Thinking functionally Chapter 14. Functional programming techniques Chapter 15. compa ...
- Functional Programming without Lambda - Part 2 Lifting, Functor, Monad
Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...
- Chapter 5: Container
Chapter 5: Container A container is a module that processes the requests for a servlet and populates ...
- JavaScript- The Good Parts Chapter 5 Inheritance
Divides one thing entire to many objects;Like perspectives, which rightly gazed uponShow nothing but ...
- JavaScript- The Good Parts Chapter 4
Why, every fault’s condemn’d ere it be done:Mine were the very cipher of a function. . .—William Sha ...
- JVM Specification 9th Edition (3) Chapter 2. The Structure of the Java Virtual Machine
Chapter 2. The Structure of the Java Virtual Machine 内容列表 2.1. The class File Format (class文件的格式) 2. ...
- FunDA(0)- Functional Data Access accessible to all
大数据.多核CPU驱动了函数式编程模式的兴起.因为函数式编程更适合多线程.复杂.安全的大型软件编程.但是,对许多有应用软件开发经验的编程者来说,函数式编程模式是一种全新的.甚至抽象的概念,可能需要很长 ...
随机推荐
- Spark优化之gc
对于官方Programming Guides的GC优化一节做了阅读. 在这里记录一下我的理解,可能记录的比较混乱没有条理: 我理解其实GC优化的主要目的就是在你的任务执行中使用更少的内存,进行更少的g ...
- linux学习笔记-13.进程控制
1.查看用户最近登录情况 lastlastlog 2.查看硬盘使用情况 df 3.查看文件大小 du 4.查看内存使用情况 free 5.查看文件系统 /proc 6.查看日志 ls /var/log ...
- Codeforces-1084C
title: Codeforces-1084C date: 2018-12-13 16:02:04 tags: acm 刷题 categories: Codeforces 概述 好久没写博客了,,,最 ...
- 【python学习-2】python起步必备
1.python缩进 python 缩进是tab,还是空格呢?都可以,可以是一个tab,也可以是4个空格,但是最重要的是整个python脚本的缩进必须统一,否则会报错. 2.代码注释 python注释 ...
- Ⅳ.Catalan数
Catalan数首先是由Euler在精确计算对凸n边形的不同的对角三角形剖分的个数问题时得到的,它经常出现在组合计数问题中. 问题的提出:在一个凸n边形中,通过不相交于n边形内部的对角线,把n ...
- 开源的在线评测系统——Vakuum
项目地址 http://code.google.com/p/vakuum-oj/ https://github.com/BYVoid/vakuum 简介 Vakuum是一个基于Linux+PHP的在线 ...
- URAL 1962 In Chinese Restaurant 数学
In Chinese Restaurant 题目连接: http://acm.hust.edu.cn/vjudge/contest/123332#problem/B Description When ...
- Linux——线程
线程 我们都知道一个程序的执行是由进程来完成的,而进程里真正执行代码却是由线程来完成,它是真正的执行流.通常将一个程序⾥里一个执行路线就叫做线程(thread).对它更准确的定义是:线程是“一个进程内 ...
- POP3_收取QQ邮箱邮件的问题
今天纠结了一天的时间,使用pop3协议收取qq邮箱中邮件时,因为一个特别坑爹的问题重新写n次,最后发现是因为qq邮箱设置了独立邮箱密码,必须的用独立邮箱密码登陆才行,/(ㄒoㄒ)/~~!!!! 但今天 ...
- 李善友《认知升级之第一性原理》--507张PPT全解!_搜狐科技_搜狐网
http://www.sohu.com/a/151470602_733114