# Java 谓词

原文：http://zetcode.com/java/predicate/

Java 谓词教程展示了如何在 Java 中使用谓词。 使用谓词，我们可以创建更清晰易读的代码。 谓词还有助于创建更好的测试。

## 谓词

谓词的一般含义是对正确或错误的陈述。 在编程中，谓词表示返回布尔值的单个参数函数。

## Java 谓词

Java 中的谓词通过接口实现。 `Predicate<T>`是表示单个参数函数的通用函数接口，该函数返回布尔值。 它位于`java.util.function`包中。 它包含`test(T t)`方法，该方法求值给定参数上的谓词。

在 Java 中，我们没有独立的函数。 此外，方法不是一等公民。 （不能将它们添加到集合中或作为参数传递给方法。）因此，我们定义接口并从这些接口创建对象。 然后可以将此类对象传递给`Iterables.filter()`之类的方法。 使用 Java lambda，使用谓词要容易得多。

## Java 谓词示例

以下示例创建一个简单的 Java 谓词。

`com/zetcode/JavaPredicateEx.java`

```java
package com.zetcode;

import java.util.List;
import java.util.function.Predicate;

class BiggerThanFive<E> implements Predicate<Integer> {

    @Override
    public boolean test(Integer v) {

        Integer five = 5;

        return v > five;
    }
}

public class JavaPredicateEx {

    public static void main(String[] args) {

        List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);

        BiggerThanFive<Integer> btf = new BiggerThanFive<>();
        nums.stream().filter(btf).forEach(System.out::println);
    }
}

```

在示例中，谓词用于过滤整数。

```java
class BiggerThanFive<E> implements Predicate<Integer> {

    @Override
    public boolean test(Integer v) {

        Integer five = 5;

        return v > five;
    }
}

```

这是实现`Predicate<Integer>`接口的 Java 类。 对于大于 5 的值，其`test()`方法返回 true。

```java
List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);

```

我们有一个整数值列表。

```java
BiggerThanFive<Integer> btf = new BiggerThanFive<>();

```

实例化了`BiggerThanFive`。

```java
nums.stream().filter(btf).forEach(System.out::println);

```

谓词对象将传递给`filter()`方法，以从列表中获取所有大于 5 的值。

```java
6
7
8
9
12

```

这是输出。

## 使用 lambda 和谓词

Java lambda 表达式简化了 Java 谓词的创建。

`com/zetcode/JavaPredicateEx2.java`

```java
package com.zetcode;

import java.util.List;
import java.util.function.Predicate;

public class JavaPredicateEx2 {

    public static void main(String[] args) {

        List<Integer> nums = List.of(2, 3, 1, 5, 6, 7, 8, 9, 12);

        Predicate<Integer> btf = n -> n > 5;

        nums.stream().filter(btf).forEach(System.out::println);
    }
}

```

该示例过滤整数值； 这次我们使用 Java lambda 表达式，这使代码更短。

```java
Predicate<Integer> btf = n -> n > 5;

```

这是创建谓词的单一语言。

## Java 谓词示例 II

下一个示例使用具有两个条件的谓词。

`com/zetcode/Country.java`

```java
package com.zetcode;

public class Country {

    private String name;
    private int population;

    public Country(String name, int population) {
        this.name = name;
        this.population = population;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    @Override
    public String toString() {
        return "Country{" + "name=" + name + 
                ", population=" + population + '}';
    }
}

```

我们有一个`Country`类； 它具有`name`和`population`属性。

`com/zetcode/JavaPredicateEx3.java`

```java
package com.zetcode;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class JavaPredicateEx3 {

    public static void main(String[] args) {

        List<Country> countries = new ArrayList<>();

        countries.add(new Country("Iran", 80840713));
        countries.add(new Country("Hungary", 9845000));
        countries.add(new Country("Poland", 38485000));
        countries.add(new Country("India", 1342512000));
        countries.add(new Country("Latvia", 1978000));
        countries.add(new Country("Vietnam", 95261000));
        countries.add(new Country("Sweden", 9967000));
        countries.add(new Country("Iceland", 337600));
        countries.add(new Country("Israel", 8622000)); 

        Predicate<Country> p1 = c -> c.getName().startsWith("I") && 
                c.getPopulation() > 10000000;

        countries.stream().filter(p1).forEach(System.out::println);
    }
}

```

在示例中，我们创建了一个国家列表。 我们按国家名称和人口过滤列表。

```java
Predicate<Country> p1 = c -> c.getName().startsWith("I") && 
        c.getPopulation() > 10000000;

```

对于以`"I"`开头且人口超过一千万的国家，该谓词返回正确。

```java
Country{name=Iran, population=80840713}
Country{name=India, population=1342512000}

```

名单中有两个国家满足条件：伊朗和印度。

## Java `IntPredicate`

`IntPredicate`表示一个`int`值自变量的谓词。 这是`Predicate<E>`的`int`消耗型原始类型特化。

`com/zetcode/IntPredicateEx.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.function.IntPredicate;

public class IntPredicateEx {

    public static void main(String[] args) {

        int[] nums = { 2, 3, 1, 5, 6, 7, 8, 9, 12 };

        IntPredicate p = n -> n > 5;

        Arrays.stream(nums).filter(p).forEach(System.out::println);
    }
}

```

该示例使用`filter()`和`IntPredicate`过滤`int`值数组。

```java
int nums[] = { 2, 3, 1, 5, 6, 7, 8, 9, 12 };

```

我们定义一个整数数组。

```java
IntPredicate p = n -> n > 5;

```

创建了`IntPredicate`； 如果`int`值大于 5，则返回`true`。

```java
Arrays.stream(nums).filter(p).forEach(System.out::println);

```

我们从数组创建一个流并过滤元素。 `filter()`方法接收谓词作为参数。

## 组合谓词

使用`and()`和`or()`方法，我们可以用 Java 编写谓词。

`com/zetcode/JavaPredicateCompose.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.function.IntPredicate;

public class JavaPredicateCompose {

    public static void main(String[] args) {

        int[] nums = {2, 3, 1, 5, 6, 7, 8, 9, 12};

        IntPredicate p1 = n -> n > 3;
        IntPredicate p2 = n -> n < 9;

        Arrays.stream(nums).filter(p1.and(p2)).forEach(System.out::println);

        System.out.println("**********");

        IntPredicate p3 = n -> n == 6;
        IntPredicate p4 = n -> n == 9;

        Arrays.stream(nums).filter(p3.or(p4)).forEach(System.out::println);
    }
}

```

该示例使用`IntPredicates`的组成过滤数据。

```java
IntPredicate p1 = n -> n > 3;
IntPredicate p2 = n -> n < 9;

Arrays.stream(nums).filter(p1.and(p2)).forEach(System.out::println);

```

我们将两个谓词与`and()`方法结合使用； 我们得到大于 3 且小于 9 的整数。

```java
IntPredicate p3 = n -> n == 6;
IntPredicate p4 = n -> n == 9;

Arrays.stream(nums).filter(p3.or(p4)).forEach(System.out::println);

```

使用`or()`方法，我们得到的值等于 6 或 9。

```java
5
6
7
8
**********
6
9

```

这是输出。

## 否定谓词

`negate()`方法返回一个谓词，该谓词表示给定谓词的逻辑非。

`com/zetcode/JavaPredicateNegate.java`

```java
package com.zetcode;

import java.util.Arrays;
import java.util.function.IntPredicate;

public class JavaPredicateNegate {

    public static void main(String[] args) {

        int[] nums = {2, 3, 1, 5, 6, 7, 8, 9, 12};

        IntPredicate p = n -> n > 5;

        Arrays.stream(nums).filter(p).forEach(System.out::println);

        System.out.println("**********");

        Arrays.stream(nums).filter(p.negate()).forEach(System.out::println);
    }
}

```

该示例演示了`negate()`方法的用法。

```java
IntPredicate p = n -> n > 5;

```

我们有一个谓词，对于大于 5 的值返回`true`。

```java
Arrays.stream(nums).filter(p).forEach(System.out::println);

```

我们过滤所有大于 5 的整数。

```java
Arrays.stream(nums).filter(p.negate()).forEach(System.out::println);

```

使用`negate()`方法，我们得到相反的结果：值小于或等于 4。

```java
6
7
8
9
12
**********
2
3
1
5

```

这是示例的输出。

## Java 谓词作为方法参数

谓词可以作为方法参数传递。

`com/zetcode/PredicateMethodParam.java`

```java
package com.zetcode;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class PredicateMethodParam {

    public static void main(String args[]) {

        List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 7,
                8, 9, 10, 11, 12);

        List<Integer> all = eval(list, n -> true);
        System.out.println(all);

        List<Integer> evenValues = eval(list, n -> n % 2 == 0);
        System.out.println(evenValues);

        List<Integer> greaterThanSix = eval(list, n -> n > 6);
        System.out.println(greaterThanSix);
    }

    private static List<Integer> eval(List<Integer> values,
                                        Predicate<Integer> predicate) {
        return values.stream().filter(predicate)
                .collect(Collectors.toList());
    }
}

```

在示例中，我们将谓词函数作为第二个参数传递给`eval()`方法。

在本教程中，我们使用了 Java 谓词。 您可能也对相关教程感兴趣： [Java 教程](/lang/java/)， [Java 中的`HashMap`迭代](/java/hashmapiterate/)， [Java `ArrayList`教程](/java/arraylist/)， [Java `HashSet`教程](/java/hashset)， [Java `static`关键字](/java/statickeyword/)， [Java8 `forEach`教程](/articles/java8foreach/)，[读取 Java 中的文本文件](/java/readtext/)和[读取和写入 Java 中的 ICO 图像](/articles/javaico/)。

列出[所有 Java 教程](/all/#java)。