1.Predicate接口簡述
@FunctionalInterface
public interface Predicate<T> {boolean test(T t);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);}static <T> Predicate<T> isEqual(Object targetRef) {return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);}
}
- Predicate接口使用了注解@FunctionalInterface,表示該接口只包含一個抽象方法,可以被當做函數式接口使用
- 該接口定義了一個抽象方法test,表示一個參數的布爾判斷。這使得 Predicate 非常適用于過濾操作
- 該接口還提供了and()、or()、negate()默認方法來進行復合使用,分別表示與、或、非的含義
2.Predicate功能:過濾后保留符合條件的元素
filter()函數接收一個Predicate類型的參數,用于過濾。這是filter的簽名:
public interface Stream<T> extends BaseStream<T, Stream<T>> {...Stream<T> filter(Predicate<? super T> predicate);...
}
下面是Predicate的使用實例,使用 Predicate 過濾非空且非空字符串的名稱:
List<String> names = Arrays.asList("Alice", "Bob", "", "Charlie", null, "David");List<String> filteredNames = names.stream().filter(Objects::nonNull) // 使用方法引用檢查非空.filter(name -> !name.isEmpty()) // 使用 lambda 表達式檢查非空字符串.filter(((Predicate<String>) s -> s.length() <= 3).or(s -> s.length() >= 7)) //復合使用Predicate.collect(Collectors.toList()); //收集所有通過過濾的元素
System.out.println("輸出最終結果: " + filteredNames);//日志log:
輸出最終結果: [Bob, Charlie]
3.分析上面的 Objects::nonNull
- Predicate 是一個函數式接口,它定義了一個抽象方法boolean test(T t)。這意味著任何具有相同參數和返回類型的方法都可以用作Predicate 類型的實例。
- Objects.nonNull(Object obj) 是一個靜態方法,它接受一個 Object 類型的參數,并返回一個 boolean 值。如果傳入的對象不是 null,它返回 true;否則返回 false。因為它的簽名(接受一個參數并返回一個布爾值)與 Predicate 接口的 test 方法相匹配,因此該方法可以被視為實現了 Predicate 接口的一個實例
public final class Objects {...public static boolean nonNull(Object obj) {return obj != null;}...
}
- Objects::nonNull 這里雙冒號 :: 是方法引用,這是 Java 8 引入的一種簡化 lambda 表達式的方式,用于提供一種更簡潔、更清晰的編碼風格。
4.正則表達式模式轉Predicate
可以將一個正則表達式Pattern,轉為Predicate,這樣子可以在Stream利用該Predicate來進行過濾,本質上是調用Matcher.find()
Pattern->
public Predicate<String> asPredicate() //將正則表達式模式轉換為一個謂詞(Predicate),本質上是Matcher.find()
使用:
//過濾得到包含數字的字符串
public static List<String> filterContainsNumber(List<String> inputStrList) {Pattern pattern = Pattern.compile("\\d"); //包含數字Predicate<String> predicate = pattern.asPredicate(); //將一個正則表達式模式轉換為一個謂詞(Predicate),本質是Matcher.find()List<String> filteredStrings = inputStrList.stream() //先將List轉為流.filter(predicate) //只留下包含數字字符串.collect(Collectors.toList());return filteredStrings;
}//調用
List<String> list = Arrays.asList("apple", "banana1", "orange2", "grape", "melon3");
System.out.println("過濾得到包含數字的字符串: " + filterContainsNumber(list));//log日志
過濾得到包含數字的字符串: [banana1, orange2, melon3]