Java 8 基础教程 - Predicate

Predicate的源码:

public interface Predicate<T> {
    /**
     * Evaluates this predicate on the given argument.
     */
    boolean test(T t);

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * AND of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code false}, then the {@code other}
     * predicate is not evaluated.
     */
    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    /**
     * Returns a predicate that represents the logical negation of this
     * predicate.
     */
    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    /**
     * Returns a composed predicate that represents a short-circuiting logical
     * OR of this predicate and another.  When evaluating the composed
     * predicate, if this predicate is {@code true}, then the {@code other}
     * predicate is not evaluated.
     */
    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

    /**
     * Returns a predicate that tests if two arguments are equal according
     * to {@link Objects#equals(Object, Object)}.
     */
    static <T> Predicate<T> isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
}

Predicate是个断言式接口其参数是<T,boolean>,也就是给一个参数T,返回boolean类型的结果。跟Function一样,Predicate的具体实现也是根据传入的lambda表达式来决定的。

boolean test(T t);

接下来我们看看Predicate默认实现的三个重要方法and,or和negate

    default Predicate<T> and(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }

    default Predicate<T> negate() {
        return (t) -> !test(t);
    }

    default Predicate<T> or(Predicate<? super T> other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }

这三个方法对应了java的三个连接符号&&、||和!,基本的使用十分简单,我们给一个例子看看:

int[] numbers= {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
List<Integer> list=new ArrayList<>();
for(int i:numbers) {
    list.add(i);
}
Predicate<Integer> p1=i->i>5;
Predicate<Integer> p2=i->i<20;
Predicate<Integer> p3=i->i%2==0;
List test=list.stream().filter(p1.and(p2).and(p3)).collect(Collectors.toList());
System.out.println(test.toString());
/** print:[6, 8, 10, 12, 14]*/

我们定义了三个断言p1,p2,p3。现在有一个从1~15的list,我们需要过滤这个list。上述的filter是过滤出所有大于5小于20,并且是偶数的列表。

假如突然我们的需求变了,我们现在需要过滤出奇数。那么我不可能直接去改Predicate,因为实际项目中这个条件可能在别的地方也要使用。那么此时我只需要更改filter中Predicate的条件。

List test=list.stream().filter(p1.and(p2).and(p3.negate())).collect(Collectors.toList());
/** print:[7, 9, 11, 13, 15]*/

我们直接对p3这个条件取反就可以实现了。是不是很简单?

isEqual这个方法的返回类型也是Predicate,所以我们也可以把它作为函数式接口进行使用。我们可以当做==操作符来使用。

List test=list.stream()
    .filter(p1.and(p2).and(p3.negate()).and(Predicate.isEqual(7)))
    .collect(Collectors.toList());
/** print:[7] */

下面看一些看复杂点的例子。

public class Employee {

    private Integer id;
    private Integer age;
    private String gender;
    private String firstName;
    private String lastName;
    
    public Employee(Integer id, Integer age, String gender, String firstName, String lastName) {
        this.id = id;
        this.age = age;
        this.gender = gender;
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    // getter, setter

    @Override
    public String toString() {
        return "Employee [id=" + id + ", age=" + age + ", gender=" + gender + ", firstName=" + firstName + ", lastName="
                + lastName + "]";
    }

}

下面定义多个 Predicate,对应多个筛选条件,病开始使用这些断言。

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

public class EmployeePredicates {

    public static Predicate<Employee> isAdultMale() {
        return p -> p.getAge() > 21 && p.getGender().equalsIgnoreCase("M");
    }
    
    public static Predicate<Employee> isAdultFemale() {
        return p -> p.getAge() > 18 && p.getGender().equalsIgnoreCase("F");
    }
    
    public static Predicate<Employee> isAgeMoreThan(Integer age) {
        return p -> p.getAge() > age;
    }
    
    public static List<Employee> filterEmployee(List<Employee> employees, Predicate<Employee> predicate) {
        return employees.stream().filter(predicate).collect(Collectors.toList());
    }
    
    public static void main(String[] args) {
        Employee e1 = new Employee(1,23,"M","Rick","Beethovan");
        Employee e2 = new Employee(2,13,"F","Martina","Hengis");
        Employee e3 = new Employee(3,43,"M","Ricky","Martin");
        Employee e4 = new Employee(4,26,"M","Jon","Lowman");
        Employee e5 = new Employee(5,19,"F","Cristine","Maria");
        Employee e6 = new Employee(6,15,"M","David","Feezor");
        Employee e7 = new Employee(7,68,"F","Melissa","Roy");
        Employee e8 = new Employee(8,79,"M","Alex","Gussin");
        Employee e9 = new Employee(9,15,"F","Neetu","Singh");
        Employee e10 = new Employee(10,45,"M","Naveen","Jain");
        
        List<Employee> employees = 
                Arrays.asList(new Employee[]{e1, e2, e3, e4, e5, e6, e7, e8, e9, e10});
        System.out.println(filterEmployee(employees, isAdultMale()));
        System.out.println(filterEmployee(employees, isAdultFemale()));
        System.out.println(filterEmployee(employees, isAgeMoreThan(35)));
    }
    
}

输出:

[1 - 23, 3 - 43, 4 - 26, 8 - 79, 10 - 45]
[5 - 19, 7 - 68]
[3 - 43, 7 - 68, 8 - 79, 10 - 45]
[1 - 23, 2 - 13, 4 - 26, 5 - 19, 6 - 15, 9 - 15]

正则表达式表示为Predicate

可以通过Pattern.compile().asPredicate()将正则表达式转换为Predicate。 在Java 8之前,从一个数组中找出符合正则规则的字符串的方法是

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class RegexPredicate {

    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("^(.+)@example.com$");
        // Input list
        List<String> emails = Arrays.asList("alex@example.com", "bob@yahoo.com",
                            "cat@google.com", "david@example.com");
        for (String email : emails) {
            Matcher matcher = pattern.matcher(email);
            if(matcher.matches()) {
                System.out.println(email);
            }
        }
        
        System.out.println("---------------------------");
        
        // 使用 lambda predicate
        Predicate<String> emailFilter = pattern.asPredicate();
        List<String> desireEmails = emails.stream()
                                          .filter(emailFilter)
                                          .collect(Collectors.toList());
        desireEmails.forEach(System.out::println);
    }
    
    
}

本文转自

  1. 探索Java8:(三)Predicate接口的使用

  2. Java 8 基础教程 - Predicate

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值