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驱动了函数式编程模式的兴起.因为函数式编程更适合多线程.复杂.安全的大型软件编程.但是,对许多有应用软件开发经验的编程者来说,函数式编程模式是一种全新的.甚至抽象的概念,可能需要很长 ...
随机推荐
- 常用的服务发现对比(Consul、zookeeper、etcd、eureka)
这里就平时经常用到的服务发现的产品进行下特性的对比,首先看下结论: Feature Consul Zookeeper Etcd Eureka 服务健康检查 服务状态,内存,硬盘等 (弱)长连接 ...
- PHP获取访问者公网IP
if(!empty($_SERVER["HTTP_CLIENT_IP"])){ $cip = $_SERVER["HTTP_CLIENT_IP"]; } el ...
- CUDA安装出现图形驱动程序安装失败
win7安装cuda9时出现图形驱动程序安装失败,解决办法是右键计算机>管理>服务和应用程序>服务>找到“Windows Installer”,右键选择“启动” 参考自http ...
- 013.Zabbix的Items(监控项)
一 Items简介 Items是从主机里面获取的所有数据,可以配置获取监控数据的方式.取值的数据类型.获取数值的间隔.历史数据保存时间.趋势数据保存时间.监控key的分组等. 通常情况下item由ke ...
- 001.NTP简介
一 NTP简介 ntp服务器顾名思义就是时间同步服务器(Network Time Protocol),时间同步对于计划备份.入侵检测记录.分布式任务调度或者事务订单管理来说都是非常有必要的日常任务. ...
- RPO漏洞学习
不能直接复制markdown上来真的是痛苦,图片还要手动上传. 算了,不贴了. 这是PDF版https://files.cnblogs.com/files/r00tuser/RPO%E6%BC%8F% ...
- Orleans介绍
一.介绍 Orleans是一个框架,提供了一个直接的方法来构建分布式高规模计算应用程序 默认可扩展 -> Orleans处理构建分布式系统的复杂性,使您的应用程序能够扩展到数百台服务器.低延迟 ...
- Android-Activity的切换效果
Android-Activity的切换效果 Android-Activity的切换效果 Activity有一个默认的切换效果,但是有时候单一的切换效果未免单调,Activity的切换效果也是我们可以自 ...
- Tecnomatix Process Designer & Process Simulate用法
1. 删除项目 在AdminConsole->Project Action中,点击Delete project即可.
- 条件随机场(crf)及tensorflow代码实例
对于条件随机场的学习,我觉得应该结合HMM模型一起进行对比学习.首先浏览HMM模型:https://www.cnblogs.com/pinking/p/8531405.html 一.定义 条件随机场( ...