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 条评论
登录 后参与评论

相关文章

来自专栏chafezhou

学习Python,怎能不懂点PEP呢?

作者:豌豆花下猫,某985高校毕业生, 兼具极客思维与人文情怀 。公众号Python猫, 专注python技术、数据科学和深度学习,力图创造一个有趣又有用的学习...

1301
来自专栏机器人网

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

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

3276
来自专栏程序人生

懒惰的力量

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

3608
来自专栏owent

POJ PKU 3277 City Horizon 解题报告

题目链接:http://acm.pku.edu.cn/JudgeOnline/problem?id=3277

843
来自专栏AhDung

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

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

1012
来自专栏HTML5学堂

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

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

39810
来自专栏web前端教室

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

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

2005
来自专栏写代码的海盗

坐忘峰 golang入坑系列

告别昨日梦,今朝艳阳天。 大道通四方,车影舞翩翩。 不做旁观者,去向应了然。 白云绕远树,飞燕春汛传。 天下万千景,彩绘壮河山。 我辈当努力,敢把宏图展。 迈步...

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

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

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

2117
来自专栏智能大石头

分析midea0978的《一个C#算法分析求解》(一)

最近碰到这样一个算法,过程并不复杂,但是思考了很久也没有找到对应的逆运算算法,这里发布出来,希望有高人能够提供思路, 如果有具体的代码实现就最好了。 实现...

1798

扫码关注云+社区

领取腾讯云代金券