Guava Predicate

1. 简介

Predicate<泛型>(断言,断定),是Guava中的一个基础接口,其内部只有一个方法boolean apply(T input),这个方法输入是一个泛型对象,输出是一个布尔值,非常简单,下面来看一下这个小东西能帮助我们做什么。

2. 使用

2.1 更简单的过滤

在日常开发中,可能有这种需求,当集合中的某些元素不符合条件时,想要过滤掉这些元素,这时我们通常有两种做法。 方法一:

List<Integer> intList = Lists.newArrayList(1, 2, 3, 5, 6);
Iterator<Integer> it = intList.iterator();
while (it.hasNext()) {
    Integer value = it.next();
    if (value == 3 || value == 5) {
        it.remove();
    }
}
System.out.println(intList);

方法二:

List<Integer> intList = Lists.newArrayList(1, 2, 3, 5, 6);
List<Integer> resultList = Lists.newArrayList();
for (Integer value : intList) {
    if (value != 3 && value != 5) {
        resultList.add(value);
    }
}
System.out.println(resultList);

方法一是在原集合上直接做删除操作,我们知道ArrayList实际上就是数组,而数组是连续的内存空间,当删除元素时,后面的元素都需要向前移动,当这个集合很大的时候,就会涉及到大量的移动。方法二是直接新建一个集合,将符合条件的元素添加至新集合中,这样避免了方法一的问题,但这样的写法有一点啰嗦,可以变成下面这样。

List<Integer> intList = Lists.newArrayList(1, 2, 3, 5, 6);
Predicate<Integer> predicate = new Predicate<Integer>() {
    public boolean apply(Integer value) {
        return value != 3 && value != 5;
    }
};
List<Integer> resultList = Lists.newArrayList(Iterables.filter(intList, predicate));
System.out.println(resultList);

将过滤规则抽到Predicate中,如果过滤规则发生变化时,只需修改Predicate即可。

2.2 更优雅的判断

举一个判断稍微复杂的例子,MBA的报考条件是: a) 具有国家承认的大学本科毕业学历后,有三年或三年以上工作经历者。 b) 已获硕士、博士学位,并有两年或两年以上工作经历者。 c) 获得国家承认的大专毕业学历后,有五年或五年以上工作经历。 这时需要一个方法去判断一个考生是否准许考试,方法如下:

private boolean canExam(Examinee examinee) {
    return ("大专".equals(examinee.getEducation()) && examinee.getExperience() >= 5)
            || ("本科".equals(examinee.getEducation()) && examinee.getExperience() >= 3)
            || ("研究生".equals(examinee.getEducation()) && examinee.getExperience() >= 2);
}

当我们去阅读这段代码的时候,只会感觉到一个字,乱,这时可以使用Predicate去改造。首先,将每个条件分支都抽到一个Predicate中。

private Predicate<Examinee> juniorCollege = new Predicate<Examinee>() {
    public boolean apply(Examinee examinee) {
        return "大专".equals(examinee.getEducation()) && examinee.getExperience() >= 5;
    }
};

private Predicate<Examinee> undergraduate = new Predicate<Examinee>() {
    public boolean apply(Examinee examinee) {
        return "本科".equals(examinee.getEducation()) && examinee.getExperience() >= 3;
    }
};

private Predicate<Examinee> postgraduate = new Predicate<Examinee>() {
    public boolean apply(Examinee examinee) {
        return "研究生".equals(examinee.getEducation()) && examinee.getExperience() >= 2;
    }
};

然后,使用Predicates工具将这三个Predicate用or聚合起来,调用其apply方法。

private boolean canExam(Examinee examinee) {
    return Predicates.or(juniorCollege, undergraduate, postgraduate).apply(examinee);
}

canExam变得非常简洁。

2.3 更动态的配置

根据分数返回对这个分数的评级,要求如下: 及格:[60, 70) 良好:[70, 80) 优秀:[80, 100] 可以看到,这是一个分数规则和评级的映射,分数规则是个区间(也可能更复杂),而不是一个具体的值,这时,可以使用Predicate作为key,得到一个评级的配置表。

private Map<Predicate<Double>, String> config = Maps.newHashMap();
{
    config.put(new Predicate<Double>() {
        @Override
        public boolean apply(Double score) {
            return score >= 60 && score < 70;
        }
    }, "及格");
    config.put(new Predicate<Double>() {
        @Override
        public boolean apply(Double score) {
            return score >= 70 && score < 80;
        }
    }, "良好");
    config.put(new Predicate<Double>() {
        public boolean apply(Double score) {
            return score >= 80;
        }
    }, "优秀");
}

然后写一个方法,遍历这个配置,取到符合条件的值,这段代码是统一的。

private String getLevel(Double score) {
    for (Map.Entry<Predicate<Double>, String> entry : config.entrySet()) {
        if (entry.getKey().apply(score)) {
            return entry.getValue();
        }
    }
    return "未知";
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序人生

懒惰的力量

(今天我在旧金山参加了Erlang factory 2015大会,增长了很多见识。参会的总结我过两天再写,很多思想需要时间沉淀。) 前段时间写了篇「永恒不变的魅...

3518
来自专栏AhDung

【C#】Excel舍入函数Round、RoundUp、RoundDown的C#版

本人在C#中进行小数舍入的时候常常会怀念Excel中的Round、RoundUp、RoundDown这几个函数,原因就是后者“接地气”,比较符合俺小老百姓的舍入...

832
来自专栏大数据挖掘DT机器学习

[笔记]使用Python一步一步地来进行数据分析

原文 http://www.cnblogs.com/nxld/p/6058998.html 你已经决定来学习Python,但是你之前没有编程经验。因此,你常常...

6786
来自专栏菩提树下的杨过

ruby学习笔记(4)-动态修改类的属性

动态语言之所以“动态”,最明显的特征就是:类实例的行为/属性可以在new出后,动态修改!个人觉得这种处理相对java/c#(静态语言)来说,更符合现实世界。 ...

1907
来自专栏JAVA高级架构开发

面向对象编程,再见!

作为程序员,你是使用函数式编程还是面向对象编程方式?在本文中,拥有 10 多年软件开发经验的作者从面向对象编程的三大特性——继承、封装、多态三大角度提出了自己的...

2000
来自专栏专知

【LeetCode 500】关关的刷题日记27 Keyboard Row

关关的刷题日记27 – Leetcode 500. Keyboard Row 题目 Given a List of words, return the word...

2905
来自专栏web前端教室

大周末的不多说,面试十点必看

实事求是的讲,前端新人因为时间的关系,对于JavaScript的理解确实是无法面面具到,甚至有些知识点我讲的比较深入,但因为每个人的程度不同,依然无法做到当堂理...

1935
来自专栏ACM小冰成长之路

HDU-6010-Daylight Saving Time

ACM模版 描述 ? 题解 这个题的难点在于题目不好懂,只要读懂了题目,细心一些的人都能做出来。 大致的思路是先预处理出来每年的两个时间节点,也就是每年三月份的...

2069
来自专栏HTML5学堂

只有JS基础扎实的攻城狮,才解得出的“密码”

HTML5学堂-码匠:虽然很不想面对,但是明天,的确是节后工作的开始,今天就一边解密一边“适应”一下代码吧! Tips:如下的四道题目,是基于几家公司的面试真题...

36810
来自专栏机器人网

电气技术中的文字符号和项目代号

一个电气系统或一种电气设备通常都是由各种基本件、部件、组件等组成,为了在电气图上或其他技术文件中表示这些基本件、部件、组件,除了采用各种图形符号外,还须标注一些...

3056

扫码关注云+社区