(目录)
1. 简介
本文介绍Java 8 Predicate使用.
2. 基本用法
怎么使用简单的Predicate来过滤list中的name
@Test
public void whenFilterList_thenSuccess(){
   List names = Arrays.asList("Adam", "Alexander", "John", "Tom");
   List result = names.stream()
     .filter(name -> name.startsWith("A"))
     .collect(Collectors.toList());
   assertEquals(2, result.size());
   assertThat(result, contains("Adam","Alexander"));
}
我们使用 Predicate来筛选以大写字母A开头的姓名。
name -> name.startsWith("A")

那么如果多个条件这么办?
3. 多条件过滤
@Test
public void whenFilterListWithMultipleFilters_thenSuccess(){
    List result = names.stream()
      .filter(name -> name.startsWith("A"))
      .filter(name -> name.length() < 5)
      .collect(Collectors.toList());
    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}
用两个filter传入两个 Predicate分别过滤 【以A开头的】和【姓名长度小于5】的。


4. 复杂条件
@Test
public void whenFilterListWithComplexPredicate_thenSuccess(){
    List result = names.stream()
      .filter(name -> name.startsWith("A") && name.length() < 5)
      .collect(Collectors.toList());
    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}
使用一个 filter 传入复杂的Predicate.

5. 组合使用 Predicate
Predicates可以将 Predicate.and(), Predicate.or() 和 Predicate.negate()组合起来使用
5.1. Predicate.and()
@Test
public void whenFilterListWithCombinedPredicatesUsingAnd_thenSuccess(){
    Predicate predicate1 =  str -> str.startsWith("A");
    Predicate predicate2 =  str -> str.length() < 5;
    List result = names.stream()
      .filter(predicate1.and(predicate2))
      .collect(Collectors.toList());
    assertEquals(1, result.size());
    assertThat(result, contains("Adam"));
}
两个条件都要满足

5.2. Predicate.or()
满足其中一个即可
@Test
public void whenFilterListWithCombinedPredicatesUsingOr_thenSuccess(){
    Predicate predicate1 =  str -> str.startsWith("J");
    Predicate predicate2 =  str -> str.length() < 4;
    List result = names.stream()
      .filter(predicate1.or(predicate2))
      .collect(Collectors.toList());
    assertEquals(2, result.size());
    assertThat(result, contains("John","Tom"));
}

5.3. Predicate.negate()
将此条件取反
@Test
public void whenFilterListWithCombinedPredicatesUsingOrAndNegate_thenSuccess(){
    Predicate predicate1 =  str -> str.startsWith("J");
    Predicate predicate2 =  str -> str.length() < 4;
    List result = names.stream()
      .filter(predicate1.or(predicate2.negate()))
      .collect(Collectors.toList());
    assertEquals(3, result.size());
    assertThat(result, contains("Adam","Alexander","John"));
}

5.4. 内联的方式组合使用 _Predicates
@Test
public void whenFilterListWithCombinedPredicatesInline_thenSuccess(){
    List result = names.stream()
      .filter(((Predicate)name -> name.startsWith("A"))
      .and(name -> name.length()
6. 组合 Predicates集合
在开始介绍之前,简单介绍下 reduce 函数:
`java.util.stream.Stream#reduce(T, java.util.function.BinaryOperator)
源码的注释中给出等价的写法:
     T result = identity;
     for (T element : this stream)
        result = accumulator.apply(result, element)
     return result;
即,第一个参数当做初始值,后续参数和第一个参数进行运算,最终得到结果。
接下来我们看下面 reduce 中 and 操作的例子:
@Test
public void whenFilterListWithCollectionOfPredicatesUsingAnd_thenSuccess(){
    List> allPredicates = new ArrayList>();
    allPredicates.add(str -> str.startsWith("A"));
    allPredicates.add(str -> str.contains("d"));
    allPredicates.add(str -> str.length() > 4);
    List result = names.stream()
      .filter(allPredicates.stream().reduce(x->true, Predicate::and))
      .collect(Collectors.toList());
    assertEquals(1, result.size());
    assertThat(result, contains("Alexander"));
}
注意这里初始条件是 true (如果初始条件为 false ,后续即使都满足,和初始值一起 and ,也没结果)

然后看 reduce 中使用 or 操作的例子:
@Test
public void whenFilterListWithCollectionOfPredicatesUsingOr_thenSuccess(){
    List result = names.stream()
      .filter(allPredicates.stream().reduce(x->false, Predicate::or))
      .collect(Collectors.toList());
    assertEquals(2, result.size());
    assertThat(result, contains("Adam","Alexander"));
}

Predicate::or 操作,通常会将初始值设置为 false,因为如果初始值为 true 不管后续条件是否为 true 最终结果都为 true。
7. 结论
本文介绍Java 8 Predicate。介绍了 Predicate在Stream的filter函数中的运用。讲述了复杂的Predicate或者Predicate的组合的用法。
英文原文:https://www.baeldung.com/java-predicate-chain
一、基本方法使用
1.1、test(T t) 方法:
test方法主要用于参数符不符合规则。返回值 boolean
写法如下:
 Predicate fourLetterLong1 = new Predicate() {
            @Override
            public boolean test(String s) {
                return s.length()>4 ?true:false ;
            }
        };
配合Lambda filter 使用如下:
public static void main(String[] args) {
        List names = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp","Hell","opt");
        Predicate<String> fourLetterLong1 = new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.length()>4 ? true : false ;
            }
        };
        names.stream()
                .filter(fourLetterLong1)
                .forEach((n) -> System.out.println("this is:" + n));
    }

1.2 、and(Predicate other)
 default Predicate and(Predicate other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) && other.test(t);
    }
add 方法等同于我们的逻辑与&&,存在短路特性,需要所有条件都满足
配合Lambda filter 使用如下:
public static void main(String[] args) {
        List names = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp", "Hell", "opt");
        Predicate fourLetterLong1 = new Predicate() {
            @Override
            public boolean test(String s) {
                return s.length() > 4 ? true : false;
            }
        };
        Predicate startsWith = new Predicate() {
            @Override
            public boolean test(String s) {
                return s.equals("Haskell") ? true : false;
            }
        };
        names.stream()
                .filter(fourLetterLong1.and(startsWith))
                .forEach((n) -> System.out.println("this is:" + n));
    }

1.3 、or(Predicate other)
default Predicate or(Predicate other) {
        Objects.requireNonNull(other);
        return (t) -> test(t) || other.test(t);
    }
or 等同于我们的逻辑或 || ,多个条件只要一个满足即可
配合Lambda filter 使用如下:
 public static void main(String[] args) {
        List names = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp", "Hell", "opt");
        Predicate fourLetterLong1 = new Predicate() {
            @Override
            public boolean test(String s) {
                return s.length() > 4 ? true : false;
            }
        };
        Predicate startsWith = new Predicate() {
            @Override
            public boolean test(String s) {
                return s.equals("zzz") ? true : false;
            }
        };
        names.stream()
                .filter(fourLetterLong1.or(startsWith))
                .forEach((n) -> System.out.println("this is:" + n));
    }

1.4、negate()方法
negate等同于我们的逻辑非 !
配合Lambda filter 使用如下:
 public static void main(String[] args) {
        List names = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp", "Hell", "opt");
        Predicate fourLetterLong1 = new Predicate() {
            @Override
            public boolean test(String s) {
                return s.length() > 4 ? true : false;
            }
        };
        names.stream()
                .filter(fourLetterLong1.negate())
                .forEach((n) -> System.out.println("this is:" + n));
    }

1.5、isEqual(Object targetRef)方法
static  Predicate isEqual(Object targetRef) {
        return (null == targetRef)
                ? Objects::isNull
                : object -> targetRef.equals(object);
    }
isEqual 类似于equals()区别在于:先判断对象是否为NULL,不为Null的话再使用equals()方法进行比较
配合Lambda filter 使用如下:
public static void main(String[] args) {
        List names = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp", "Hell", "opt");
        Predicate isEqual = new Predicate() {
            @Override
            public boolean test(String s) {
                return Predicate.isEqual("Java").test(s) ? true : false;
            }
        };
        names.stream()
                .filter(isEqual)
                .forEach((n) -> System.out.println("this is:" + n));
    }

二、扩展
使用Lambda 新特性和String类中的方法 多条查询
public static void main(String[] args) {
        List names = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp", "Hell", "opt");
        //长度为7
        Predicate<String> length = (n) -> n.length() == 4;
        // endsWith 方法字符串是否以指定的前缀开头。
        Predicate<String> startsWith = (n) -> n.startsWith("J");
        // endsWith 字符串是否以指定的后缀结尾。
        Predicate<String> endsWith = (n) -> n.endsWith("a");
        Predicate<String> isEqual = (n) ->Predicate.isEqual("Haskell").test(n);
        names.stream()
                .filter(length.and(startsWith).and(endsWith).or(isEqual))
                .forEach((n) -> System.out.println("this is:" + n));
    }









