原文出处: oschina

在本系列博客的第一、二部分,我介绍了非常优秀的Google Collections和Guava包。本篇博客中我们来看看如何使用Google Collections来做到过滤和排序功能。此外,我会带你看看Google Collections是如何使Java有一点点“functional(方法化)”的进步了。

Functions, Functions, Functions!!

Google Collections给我们带来了一对非常优雅的东东,叫做:Functions and Predicates! 和你使用的scala一样有神奇的地方,现在你可以使用在no-functional 的java身上了。你可以在com.google.common.base包里找到这些(更多)。

我们将在下一部分过滤集合的时候谈到Predicates类,首先我们先看一下Function的用法!

Google collections提供了Function<F,T>接口,实际上,一个function就是从一个对象到另外一个对象的转换变形。

像Lists和Maps这类的Collection工具类给我们提供了转换的方法:

1
2
topMap
= Maps.transformValues(fromMap, function);
toList
= Lists.transform(fromList, function);

举个例子来说,假设你有一个Map,key是物品,value是对应的价格,单位是欧元。那么,你有个需求是将里面的价格都转换为美元,传统的做法是遍历整个Map,然后更新每个value值,将价格转换为美元价格,好麻烦。。。

有了Functions,世界一下子变清净了…

1
2
3
4
5
6
Map
usdPriceMap = Maps.transformValues(eurPriceMap,
new

Function() {
            double

eurToUsd =
1.4888;
            public

Double apply(
final

Double from) {
                return

from * eurToUsd;
            }
        });

好吧,你可能说匿名内部类搞的有点糟,因为 你可能想重用这个function—这里只是演示函数式的一些特点而已。

和这个类似的,我们也可以使用Functions来把一个对象转换成一个完全不同的对象,比如将一个整形转换为字符串。

我们稍后再深入Functions类,首先我们浏览一下Multimap集合以及我们如果使用一点function来转换一个集合。

使用条件过滤集合

我在Integrasco做数据工作时遇到的最常见的任务是过滤数据和对大集合进行排序。 简单起见,我们假设你有一个姓名列表想要过滤(看起来有点幼稚):

1
List<String>
names = listOf(
"Aleksander",
"Jaran",
"Integrasco",
"Guava",
"Java");

我们可以使用com.google.common.collect.Iterables和com.google.common.base.Predicates类来过滤例子中的列表,使过滤后的列表中只包含Aleksander或者Jaran:

现在我知道这听起来有点傻帽,但是你仍然可以实现自己的Predicates条件类,比如返回名字长度小于5的列表(我从codemonkeyism.com偷到了下面这个例子):

1
Iterable<String>
filtered = filter(names, or(or(equalTo(
"Aleksander"),equalTo("Jaran")),
lengthLessThan(
5)));

这个例子返回的是Aleksander,Jaran以及Java(因为Java的长度小于5)。or条件的部分读起来有点绕,但我还可以忍受。equalTo以及or条件都是Predicates自带的方法,用起来很方便。

现在我们来实现一个lengthLessThan的条件,我们只需要这么做:

1
2
3
4
5
6
7
8
9
private

static

class

LengthLessThanPredicate
implements

Predicate<String> {
        private

final

int

length;
        private

LengthLessThanPredicate(
final

int

length) {
            this.length
= length;
        }
        public

boolean

apply(
final

String s) {
            return

s.length() < length;
        }
    }

把这个实现在你的工具类里包装一下就像这样:

1
2
3
public

static

Predicate<String> lengthLessThan(
final

int

length) {
        return

new

LengthLessThanPredicate(length);
    }

关注一下 Stephan的博文   fluent
interfaces for Google Collections
 –写的相当优雅~!

对集合排序

多亏有了java Collections类,我们可以这么排序:

1
Collections.sort(List<T>,
Comparator<?
super

T>)

但有时候我们想做更复杂一些的事情,比如合并多个Comparator或者我们可能只是想要排序过的集合的一个视图,而不改变原来集合的顺序。

Google Collections给我们提供了Ordering,让我们更好地掌控排序。假如我们有两个对Person类排序的comparator,一个是根据lastName排序,一个是根据firstName排序:

1
2
3
4
5
Comparator<Person>
byLastName =
new

Comparator<Person>() {
    public

int

compare(
final

Person p1,
final

Person p2) {
        return

p1.getLastName().compareTo(p2.getLastName());
    }
}
Comparator<Person> byFirstName = new Comparator<Person>() {
    public int compare(final Person p1, final Person p2) {
        return p1.getFirstName().compareTo(p2.getFirstName());
    }
};

那么,假如我们现在想现根据last name排序,再根据first name排序,然后对排序结果反序,那我们我们需要做的是:

List<Person> sortedCopy = Ordering.from(byLastName).compound(byFirstName).reverse().sortedCopy(persons);

而且,你甚至无需创建Comparator比较器,你可以直接扩展Ordering类!

1
List<Person>
sortedCopy = orderByLastName.compound(orderByFirstName).reverse().sortedCopy(persons);

继续过滤和排序

在这个系列的第一部分,Steve提到了在Scala中,你可以这么做:

1
people.filter(_.firstName
==
"Steve").sort(_.lastName
< _.lastName)

功能是说从people这个集合中筛选出firstName为“Steve”的,并且按他们的lastName属性排序。

从语法上来看,这行代码非常优雅!那么我们也来看一下使用Google Collections时应该怎么做。Google Collections给我们提供了前面提到的Iterables类,我们可以使用Iterables类来实现过滤和转换(你可以使用Google Collections里的Collections2来实现同样的功能)。

那现在我们就来看一下如何实现和Steve的那行Scala代码一样的功能,虽然看起来没有Scala实现的那么优雅,但却是使用Predicates和Ordering类来实现上面功能的一种方式。

1
Ordering.from(byLastName).sortedCopy(filter(persons,
withFirstName(
"Steve")));

虽然跟Scala提供的语法糖有点差距(很明显我们还是需要我们的“withFirstName”条件谓词以及“byLastName”比较器),但至少这比我们不使用Google Collections接近多了!(如果采用Stephen的流式接口的话,代码会更易读)。

Kevin Bourrillion在另一篇关于使用Google
Collections编写函数式的Java
的文章中提到:

语法很烂。而且同时这在语言本身改变之前只是权宜之计,到那时我们才真正的选择最佳的语法并开始真正的函数式编程。所以我还没决定我会投入多大的努力到Function/Predicate中去(这段真的很难翻译..我去..)

在下篇也是最后一篇关于Google Collections和Guava的博文中,我们将看到如果使用Google Collections操作Set和Map,以及使用Preconditiones来做验证,而且我们带你体验一下奇妙的Multimap集合类以及如何进行切分!

拭目以待吧!

Guava 教程(3):Java 的函数式编程,通过 Google Collections 过滤和调用的更多相关文章

  1. Guava 是个风火轮之函数式编程(3)——表处理

    云栖社区> 博客列表> 正文 Guava 是个风火轮之函数式编程(3)--表处理 潘家邦 2016-01-26 13:19:21 浏览1062 评论0 java Guava 摘要: 早先学 ...

  2. paip. java的 函数式编程 大法

    paip. java的 函数式编程 大法 Java 语言中常被忽视的一个方面是它被归类为一种命令式(imperative)编程语言.命令式编程虽然由于与 Java 语言的关联而相当普及,但是并不是惟一 ...

  3. Java 8 新特性-菜鸟教程 (3) -Java 8 函数式接口

    Java 8 函数式接口 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口. 函数式接口可以被隐式转换为lambda表达式. 函数式接 ...

  4. Java Stream函数式编程案例图文详解

    导读 作者计划把Java Stream写成一个系列的文章,本文只是其中一节.更多内容期待您关注我的号! 一.什么是Java Stream? Java Stream函数式编程接口最初是在Java 8中引 ...

  5. Java Stream函数式编程图文详解(二):管道数据处理

    一.Java Stream管道数据处理操作 在本号之前发布的文章<Java Stream函数式编程?用过都说好,案例图文详解送给你>中,笔者对Java Stream的介绍以及简单的使用方法 ...

  6. Java 8 函数式编程

    今天打开Oracle Java官网一看,Java已经更新到 13 了 https://www.oracle.com/technetwork/java/javase/jdk-relnotes-index ...

  7. Scala学习教程笔记二之函数式编程、Object对象、伴生对象、继承、Trait、

    1:Scala之函数式编程学习笔记: :Scala函数式编程学习: 1.1:Scala定义一个简单的类,包含field以及方法,创建类的对象,并且调用其方法: class User { private ...

  8. Scala学习教程笔记三之函数式编程、集合操作、模式匹配、类型参数、隐式转换、Actor、

    1:Scala和Java的对比: 1.1:Scala中的函数是Java中完全没有的概念.因为Java是完全面向对象的编程语言,没有任何面向过程编程语言的特性,因此Java中的一等公民是类和对象,而且只 ...

  9. Java 之 函数式编程

    一.Lambda 的延迟执行 有些场景的代码执行后,结果不一定会被使用,从而造成性能浪费.而Lambda表达式是延迟执行的,这正好可以作为解决方案,提升性能 . 性能浪费的日志案例 注意:日志可以帮助 ...

随机推荐

  1. vue-cli搭建项目的目录结构及说明

    vue-cli基于webpack搭建项目的目录结构 build文件夹 ├── build              // 项目构建的(webpack)相关代码    │ ├── build.js   ...

  2. Linux 查看CPU温度

    安装 lm-sensors sudo apt-get install lm-sensors # 安装yes | sudo sensors-detect # 侦测所有感测器 sensors # 查看温度 ...

  3. C语言多维数组的指针传递

    在C语言中为了节省空间,提高运行速度经常使用指针来完成数组的传递. 对于一维数组而言可以直接传递首地址 而对于二维数组必须在传递时声明是二维数组的指针,并且调用时也要经过一些运算 首先是定义形参: 函 ...

  4. Go 语言循环语句

    在不少实际问题中有许多具有规律性的重复操作,因此在程序中就需要重复执行某些语句. 以下为大多编程语言循环程序的流程图: Go 语言提供了以下几种类型循环处理语句: 循环类型 描述 for 循环 重复执 ...

  5. ERROR: Cannot change version of project facet Dynamic Web Module to 3.0?

    Issue: When you create web app in eclipse with maven configuration, you may get following error. Can ...

  6. Scikit-learn:分类classification

    http://blog.csdn.net/pipisorry/article/details/53034340 支持向量机SVM分类 svm分类有多种不同的算法.SVM是非常流行的机器学习算法,主要用 ...

  7. OpenResty修改Nginx默认autoindex页面

    Nginx的autoindex 命令可以自动列出目录下的文件,一些网站用这个功能做文件下载,但是Nginx又没有提供这个页面的 自定义的功能,后来看到别人提及 ngx_openresty,才想到 bo ...

  8. Android适配难题全面总结

    支持多种屏幕 Android 可在各种具有不同屏幕尺寸和密度的设备上运行.对于 应用,Android 系统在不同设备中提供一致的开发环境, 可以处理大多数工作,将每个应用的用户界面调整为适应其显示的 ...

  9. 设子数组A[0:k]和A[k+1:N-1]已排好序(0≤K≤N-1)。试设计一个合并这2个子数组为排好序的数组A[0:N-1]的算法。

    设子数组A[0:k]和A[k+1:N-1]已排好序(0≤K≤N-1).试设计一个合并这2个子数组为排好序的数组A[0:N-1]的算法.要求算法在最坏情况下所用的计算时间为O(N),只用到O(1)的辅助 ...

  10. 让sublime总是在新选项卡打开新文件

    sublime的一个默认设置让人很不爽,比如现在选项卡里面已经打开了一个文件A,当你从左边side bar里面点击一个新文件B时,如果你不是快速的双击,且A没有处于编辑未保存状态,那么B就会覆盖A的选 ...