一文学会 Java 8 的Predicates

在这份详细的指南中,您将了解 Java Predicates,这是 Java 8 中一个新颖且有用的特性。本文解释了 Java Predicates 是什么以及如何在各种情况下使用它们。

在这份详尽的指南中,您将深入了解 Java Predicates,这是 Java 8 中引入的一项新颖且实用的功能。本文不仅阐释了 Java Predicates 的本质,还展示了如何在多种场景下灵活运用它们。

通过本指南,您将掌握过滤数据、链接 Predicates 以及规避常见错误的全部技巧。借助 Java Predicates,您不仅能显著提升 Java 编程技艺,还能将您的应用程序推向新的高度。

Predicates 是什么?

在 Java 8 中,Predicate 作为功能接口在 java.util.function 包中被引入。它代表一种布尔值函数,接受一个参数并返回真或假。Predicate 接口定义了一个名为 test() 的单一抽象方法,专门用于评估布尔条件。

@FunctionalInterface
public interface Predicate<T> {
  boolean test(T t);
}

通常,Predicate 是过滤或评估集合中元素的得力工具。

入门指南

Java Predicate 作为一种功能接口,可以通过 lambda 表达式轻松定义。以下是一个简单的 Predicate 示例,用于判断字符串的长度是否为偶数:

Predicate<String> startWithLetterN = s -> s.startsWith("N");

在这段代码中,startWithLetterN 是一个 Predicate,它接受一个字符串 s 并检查其是否以字母 N 开头。我们通过 lambda 表达式 s -> s.startsWith(“N”) 来实现这一逻辑。

一旦定义了 Predicate,我们便可以利用其 test() 方法来评估数据。

Boolean result = startWithLetterN.test("Mateo");

@Test
void verify() {
    assertThat(result).isFalse();
}

链接 Predicates

对Predicate进行链接操作非常简单,可以通过在第一个Predicate上调用 and 方法并将第二个Predicate作为参数传递来实现。

Predicate<String> startWithLetterP = s -> s.startsWith("P");
Predicate<String> lengthGreaterThan5 = s -> s.length() > 5;
Predicate<String> startWithPAndGreaterThan5 = startWithLetterP.and(lengthGreaterThan5);

@Test
void check() {
    assertThat(startWithPAndGreaterThan5.test("Penelope")).isTrue();
}

使用 Predicate 过滤数据

谓词常用于过滤数据。例如,您可以使用它们来过滤符合特定条件的集合项。以下是一个使用 Predicate 过滤数字列表的示例:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

Predicate<Integer> isGreaterThan4 = n -> n > 4;
Predicate<Integer> isEven = n -> n % 2 == 0;
List<Integer> matchingNumbers = numbers.stream()
        .filter(isEven.and(isGreaterThan4))
        .collect(Collectors.toList());

@Test
void check() {
    assertThat(matchingNumbers).hasSize(3).containsExactly(6, 8, 10);
}

您可以使用不同的谓词方法来满足您的所有用例。

Java Predicates 提供了一些优势,它们更加灵活,因为它们可以作为参数传递并在方法中作为结果返回。它们还可以在不同的上下文中组合和重用。

例如,一旦我们有了一个像 startWithLetterN 这样的 Predicate,我们就可以在代码的多个地方使用它。这是在循环内部或 Stream 的 filter() 方法中定义的条件无法实现的。

总之,虽然循环和 Streams 可以用于在 Java 中过滤数据,但 Predicates 提供了更灵活和可重用的方法,特别是对于复杂条件和大型应用程序。

需要避免的坑

使用 Java Predicates 时存在潜在的陷阱。最常见的是使用方法引用时的 NullPointerExceptions。这通常发生在处理包含空值的集合时。

List<String> categories = Arrays.asList("Culture", "Entertainment", null);
Predicate<String> isShortWord = s -> s.length() < 4;

@Test
void check() {
    categories.stream()
        .filter(isShortWord)
        .forEach(System.out::println);
}

在这个例子中,我们试图过滤一个字符串列表,只检索那些包含短单词的字符串。然而,我们的列表包含一个空值,这在我们尝试对其调用 length() 方法时会导致 NullPointerException。

为了避免这个问题,您可以在 Predicate 中添加另一个检查以忽略空值:

List<String> categories = Arrays.asList("Culture", "Entertainment", null);
Predicate<String> isShortWord = s -> Objects.nonNull(s) && s.length() < 4;

@Test
void check() {
    categories.stream()
        .filter(isShortWord)
        .forEach(System.out::println);
}

另一个需要避免的陷阱是使用 Predicate 进行链接操作的顺序。当使用 and()、or() 和 negate() 链接 Predicates 时,请记住操作顺序会影响结果。

例如,在处理空值时,and() 操作不具有交换性:

总结

本文作为您掌握 Java Predicates 的综合指南。您已经深入了解了它们的工作原理、在 Java 编程中的重要性以及如何在代码中巧妙地运用它们。

通过阅读本指南,您不仅熟悉了 Java Predicates 的基础知识,还掌握了一些高级技巧,使您能够在项目中自信而娴熟地应用这些知识。

请登录后发表评论

    没有回复内容