资讯专栏INFORMATION COLUMN

java8-谓词(predicate)

sshe / 1712人阅读

摘要:通常我们用筛选一词来表达这个概念。嘿,这两个方法只有一行不同里面高亮的那行条件。词谓词在数学上常常用来代表一个类似函数的东西,它接受一个参数值,并返回或。

传递代码

我们首先看一个例子,假设你有一个 Apple 类,它有一个getColor方法,还有一个变量inventory保存着一个Apples的列表。你可能想要选出所有的绿苹果,并返回一个列表。通常我们用筛选(filter)一词来表达这个概念。在Java 8之前,你可能会写这样一个方法 filterGreenApples :

public static List filterGreenApples(List inventory){
List result = new ArrayList<>();
for (Apple apple: inventory){
if ("green".equals(apple.getColor())) {
result.add(apple);
        }
    }
return result;
}

但是接下来,有人可能想要选出重的苹果,比如超过150克,于是你心情沉重地写了下面这
个方法,甚至用了复制粘贴:

public static List filterHeavyApples(List inventory){
List result = new ArrayList<>();
for (Apple apple: inventory){
if (apple.getWeight() > 150) {
result.add(apple);
        }      
    }
return result;
}

我们都知道软件工程中复制粘贴的危险——给一个做了更新和修正,却忘了另一个。嘿,这
两个方法只有一行不同: if 里面高亮的那行条件。如果这两个高亮的方法之间的差异仅仅是接受
的重量范围不同,那么你只要把接受的重量上下限作为参数传递给 filter 就行了,比如指定
(150, 1000) 来选出重的苹果(超过150克),或者指定 (0, 80) 来选出轻的苹果(低于80克)。
但是,我们前面提过了,Java 8会把条件代码作为参数传递进去,这样可以避免 filter 方法
出现重复的代码。现在你可以写:

public static boolean isGreenApple(Apple apple) {
    return "green".equals(apple.getColor());
}
public static boolean isHeavyApple(Apple apple) {
    return apple.getWeight() > 150;
}
static List filterApples(List inventory, Predicate p) {
    List result = new ArrayList<>();
    for (Apple apple: inventory){
        if (p.test(apple)) {
            result.add(apple);
        }
    }
    return result;
}

要用它的话,你可以写:
filterApples(inventory, Apple::isGreenApple);
或者
filterApples(inventory, Apple::isHeavyApple);
什么是谓词?

前面的代码传递了方法 Apple::isGreenApple (它接受参数 Apple 并返回一个
boolean )给 filterApples ,后者则希望接受一个 Predicate 参数。词 谓词(predicate)
在数学上常常用来代表一个类似函数的东西,它接受一个参数值,并返回 true 或 false 。你
在后面会看到,Java 8也会允许你写 Function ——在学校学过函数却没学
过谓词的读者对此可能更熟悉,但用 Predicate 是更标准的方式,效率也会更高一
点儿,这避免了把 boolean 封装在 Boolean 里面。
从传递方法到 Lambda

把方法作为值来传递显然很有用,但要是为类似于 isHeavyApple 和 isGreenApple 这种可
能只用一两次的短方法写一堆定义有点儿烦人。不过Java 8也解决了这个问题,它引入了一套新
记法(匿名函数或Lambda),让你可以写
filterApples(inventory, (Apple a) -> "green".equals(a.getColor()) );
或者
filterApples(inventory, (Apple a) -> a.getWeight() > 150 );
甚至
filterApples(inventory, (Apple a) -> a.getWeight() < 80 ||
"brown".equals(a.getColor()) );
完整的代码为:

public class FilteringApples1 {
    public static void main(String[] args) {
        List inventory = Arrays.asList(new FilteringApples1.Apple(80, "green"),
                new FilteringApples1.Apple(155, "green"),
                new FilteringApples1.Apple(120, "red"));

        List greenApples2 = filterApples(inventory, (FilteringApples1.Apple a) -> "green".equals(a.getColor()));
        System.out.println(greenApples2);

        // [Apple{color="green", weight=155}]
        List heavyApples2 = filterApples(inventory, (FilteringApples1.Apple a) -> a.getWeight() > 150);
        System.out.println(heavyApples2);

        // []
        List weirdApples = filterApples(inventory, (FilteringApples1.Apple a) -> a.getWeight() < 80 ||
                "brown".equals(a.getColor()));
        System.out.println(weirdApples);
    }


    public static List filterApples(List inventory, Predicate p) {
        List result = new ArrayList<>();
        for (FilteringApples1.Apple apple : inventory) {
            if (p.test(apple)) {
                result.add(apple);
            }
        }
        return result;
    }

    public static class Apple {
        private int weight = 0;
        private String color = "";

        public Apple(int weight, String color) {
            this.weight = weight;
            this.color = color;
        }

        public Integer getWeight() {
            return weight;
        }

        public void setWeight(Integer weight) {
            this.weight = weight;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }

        public String toString() {
            return "Apple{" +
                    "color="" + color + """ +
                    ", weight=" + weight +
                    "}";
        }
    }

}

java8中内置filter函数

static  Collection filter(Collection c, Predicate p);

这样你甚至都不需要写 filterApples 了,因为比如先前的调用

filterApples(inventory, (Apple a) -> a.getWeight() > 150 );

就可以直接调用库方法 filter :

filter(inventory, (Apple a) -> a.getWeight() > 150 );

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/73354.html

相关文章

  • Java8实战》-读书笔记第一章(01)

    摘要:依旧使用刚刚对苹果排序的代码。现在,要做的是筛选出所有的绿苹果,也许你会这一个这样的方法在之前,基本上都是这样写的,看起来也没什么毛病。但是,现在又要筛选一下重量超过克的苹果。 《Java8实战》-读书笔记第一章(01) 最近一直想写点什么东西,却不知该怎么写,所以就写写关于看《Java8实战》的笔记吧。 第一章内容较多,因此打算分几篇文章来写。 为什么要关心Java8 自1996年J...

    codeGoogle 评论0 收藏0
  • Java8之Consumer、Supplier、Predicate和Function攻略

    摘要:接口有一个方法,可以返回值。在上面的代码中,就是获取字符串的长度,然后将每个字符串的长度作为返回值返回。 今天我们还讲讲Consumer、Supplier、Predicate、Function这几个接口的用法,在 Java8 的用法当中,这几个接口虽然没有明目张胆的使用,但是,却是润物细无声的。为什么这么说呢? 这几个接口都在 java.util.function 包下的,分别是Con...

    pepperwang 评论0 收藏0
  • Java8实战》-读书笔记第二章

    摘要:但是到了第二天,他突然告诉你其实我还想找出所有重量超过克的苹果。现在,农民要求需要筛选红苹果。那么,我们就可以根据条件创建一个类并且实现通过谓词筛选红苹果并且是重苹果酷,现在方法的行为已经取决于通过对象来实现了。 通过行为参数化传递代码 行为参数化 在《Java8实战》第二章主要介绍的是通过行为参数化传递代码,那么就来了解一下什么是行为参数化吧。 在软件工程中,一个从所周知的问题就是,...

    Astrian 评论0 收藏0
  • Java 8 API 示例:字符串、数值、算术和文件

    摘要:示例字符串数值算术和文件原文译者飞龙协议大量的教程和文章都涉及到中最重要的改变,例如表达式和函数式数据流。不仅仅是字符串,正则表达式模式串也能受益于数据流。 Java 8 API 示例:字符串、数值、算术和文件 原文:Java 8 API by Example: Strings, Numbers, Math and Files 译者:飞龙 协议:CC BY-NC-SA 4.0 ...

    KavenFan 评论0 收藏0
  • Java8实用技能

    大概一年多之前,我对java8的理解还仅限一些只言片语的文章之上,后来出于对函数式编程的兴趣,买了本参考书看了一遍,然后放在了书架上,后来,当我接手大客户应用的开发工作之后,java8的一些工具,对我的效率有了不小的提升,因此想记录一下java8的一些常用场景,我希望这会成为一个小字典,能让我免于频繁翻书,但是总能找到自己想找的知识。 用于举例的model: @Data public class ...

    microcosm1994 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<