java程式碼之美(13)— Predicate詳解

  • 2019 年 10 月 3 日
  • 筆記

java程式碼之美(13)— Predicate詳解

遇到Predicate是自己在自定義Mybatis攔截器的時候,在攔截器中我們是通過反射機制獲取對象的所有屬性,再查看這些屬性上是否有我們自定義的UUID註解

如果有該註解,那麼就給該屬性賦值UUID隨機字元串,作為主鍵保存到資料庫。所以前提條件就是獲取帶有UUID註解的屬性,就需要用到Predicate。

//獲取所有帶UUID註解的屬性   Set<Field> allFields = ReflectionUtils.getFields(object.getClass(),x.getAnnotation(UUId.class) != null);

也想到之前自己在用steam處理集合的時候,添加的過濾條件也是用Predicate,只不過它們不在同一包下。雖然它們不在同一包下但它們的作用是一致的,就是

Predicate介面主要用來判斷一個參數是否符合要求

下面對這兩個介面分別進行說明並舉例。

一、java.util.function.Predicate

這裡類是java自帶主要廣泛用在支援lambda表達式的API中。

1、介面源碼

@FunctionalInterface  public interface Predicate<T> {      /**       * 具體過濾操作 需要被子類實現.       * 用來處理參數T是否滿足要求,可以理解為 條件A       */      boolean test(T t);      /**       * 調用當前Predicate的test方法之後再去調用other的test方法,相當於進行兩次判斷       * 可理解為 條件A && 條件B       */      default Predicate<T> and(Predicate<? super T> other) {          Objects.requireNonNull(other);          return (t) -> test(t) && other.test(t);      }      /**       * 對當前判斷進行"!"操作,即取非操作,可理解為 ! 條件A       */      default Predicate<T> negate() {          return (t) -> !test(t);      }      /**       * 對當前判斷進行"||"操作,即取或操作,可以理解為 條件A ||條件B       */      default Predicate<T> or(Predicate<? super T> other) {          Objects.requireNonNull(other);          return (t) -> test(t) || other.test(t);      }        /**       * 對當前操作進行"="操作,即取等操作,可以理解為 A == B       */      static <T> Predicate<T> isEqual(Object targetRef) {          return (null == targetRef)                  ? Objects::isNull                  : object -> targetRef.equals(object);      }  }

2、常規示例

    public static void main(String[] args) {          /**           * 1、判斷數字是否大於7           */          //設置一個大於7的過濾條件          Predicate<Integer> predicate = x -> x > 7;          System.out.println(predicate.test(10)); //輸出 true          System.out.println(predicate.test(6));  //輸出 fasle           /**            * 2、大於7並且            */          //在上面大於7的條件下,添加是偶數的條件          predicate = predicate.and(x -> x % 2 == 0);          System.out.println(predicate.test(6));  //輸出 fasle          System.out.println(predicate.test(12)); //輸出 true          System.out.println(predicate.test(13)); //輸出 fasle          /**           * 3、add or 簡化寫法           */          predicate = x -> x > 5 && x < 9;          System.out.println(predicate.test(10)); //輸出 false          System.out.println(predicate.test(6));  //輸出 true      }

3、集合Stream示例

User對象

@Data  @AllArgsConstructor  @ToString  public class User {      /**       * 姓名       */      private String name;        /**       * 性別       */      private String sex;        /**       * 年齡       */      private Integer age;       /**       * 重寫equals和hashCode       */      @Override      public boolean equals(Object obj) {          if (obj instanceof User) {              User user = (User) obj;              if (name.equals(user.name)){                  return true;              }          }              return false;          }          @Override          public int hashCode () {              return name.hashCode();          }        }

測試程式碼

    public static void main(String[] args) {          User user1 = new User("張三", "女", 1);          User user2 = new User("李四", "男", 2);          User user3 = new User("張三", "女", 3);          List<User> list = Lists.newArrayList(user1, user2, user3);           /**          * 1、獲取年齡大於2的對象          */          List<User> collect = list.stream().filter(x -> x.getAge() > 2).collect(Collectors.toList());          System.out.println("獲取年齡大於2的數量 = " + collect.size());          //輸出:獲取年齡大於2的數量 = 1            /**           * 2、去重 設置name相同即為相同對象           */          //方式1直接使用 distinct          List<User> collect1 = list.stream().distinct().collect(Collectors.toList());          System.out.println("輸出剩餘對象" + collect1);          //輸出:輸出剩餘對象[User(name=張三, sex=女, age=1), User(name=李四, sex=男, age=2)]            /**           * 3、從集合找出與該對象相同的元素 同樣name相同即為相同對象           */          User user4 = new User("張三", "男", 8);          Predicate<User> predicate =  Predicate.isEqual(user4);          List<User> collect2 = list.stream().filter(predicate).collect(Collectors.toList());          System.out.println("與該對象相同的對象有" + collect2);          //輸出:與該對象相同的對象有[User(name=張三, sex=女, age=1), User(name=張三, sex=女, age=3)]      }

運行結果

二、com.google.common.base.Predicate

這裡的Predicate是配合guava使用的。

作用

  1. 處理集合的過濾條件
  2. 反射工具類的過濾條件

如果作為集合的過濾條件,現在已經沒有必要用它了,因為JDK1.8的stream在處理集合的時候比它好用多了。

1、介面源碼

@GwtCompatible  public interface Predicate<T> {    //重寫過濾條件    @CanIgnoreReturnValue    boolean apply(@Nullable T input);    //重寫equals    boolean equals(@Nullable Object object);

在使用它的時候需要重寫兩個方法。

2、示例

自定義UUID註解

@Documented  @Retention(RetentionPolicy.RUNTIME)  @Target(ElementType.FIELD)  public @interface UUID {  }

Person

@Data  @AllArgsConstructor  @ToString  public class Person {      /**       * 姓名 在name上使用UUID註解       */      @UUID      private String name;      /**       * 性別       */      private String sex;      /**       * 年齡       */      private Integer age;  }

測試程式碼

 public static void main(String[] args) {          Person person1 = new Person("張三", "女", 1);          Person person2 = new Person("李四", "男", 2);          Person person3 = new Person("張三", "女", 3);            List<Person> list = Lists.newArrayList(person1, person2, person3);          /**           * 1、guava使用過濾 年齡大於2的           */          Predicate<Person> predicate1 = new Predicate<Person>() {              //重寫兩個方法              @Override              public boolean apply(Person input) {                  if (input.getAge() > 2) {                      return true;                  }                  return false;              }              @Override              public boolean equals(Object object) {                  return true;              }          };          list = Lists.newArrayList(Iterables.filter(list,predicate1));          System.out.println("過濾後的集合數據: "+list);          //輸出: 過濾後的集合數據: [Person(name=張三, sex=女, age=3)]            /**           * 2、配合反射工具類ReflectionUtils過濾獲取屬性           */          Person person4 = new Person("張三", "女", 1);          Set<Field> allFields = org.reflections.ReflectionUtils.getFields(person4.getClass(),x -> x != null && x.getAnnotation(UUID.class) != null);          System.out.println("帶UUID註解的屬性有 "+ allFields);          //輸出 :帶UUID註解的屬性有 [private java.lang.String com.jincou.vo.Person.name]      }

運行結果

很明顯,這裡已經獲取到了帶有UUID註解的屬性為name。

 我相信,無論今後的道路多麼坎坷,只要抓住今天,遲早會在奮鬥中嘗到人生的甘甜。抓住人生中的一分一秒,勝過虛度中的一月一年!(2)