Lesson 3
Working with Predicates
Predicates in Functional Programming

Welcome to the lesson on Predicates. As we continue our exploration of functional interfaces, we will now focus on Predicate interfaces. Building on the foundational knowledge from previous lessons, this lesson will teach you how to leverage predicates for conditional checks and decision-making in your Java applications.

What You'll Learn

By the end of this lesson, you will understand:

  • The basic syntax and usage of the Predicate interface.
  • Combining predicates for complex conditional checks.
  • Negating predicates to reverse their logic.
  • Using isEqual for equality checks.

These key concepts will help you effectively use predicates for conditional logic in your Java applications.

Introduction to Predicates

Similar to the Consumer and Supplier interfaces you’ve learned about, the Predicate interface is another powerful tool in functional programming. It represents a boolean-valued function of one argument, allowing you to perform checks and match conditions succinctly.

Functional Interface Overview

The Predicate interface is annotated with @FunctionalInterface, indicating that it has exactly one abstract method. This structure makes it ideal for use with lambda expressions, enabling more concise and readable code. Here’s what the Predicate interface looks like:

Java
1@FunctionalInterface 2public interface Predicate<T> { 3 boolean test(T t); 4}

Methods in the Predicate Interface

  • test(T t): Takes an input of type T and returns a boolean value.
  • and(Predicate<? super T> other): Combines this predicate with another using logical AND.
    • The <? super T> syntax allows you to combine predicates that operate on T or any of its superclasses, providing flexibility.
  • or(Predicate<? super T> other): Combines this predicate with another using logical OR.
  • negate(): Returns a predicate that represents the logical negation of this predicate.
  • isEqual(Object targetRef): Returns a predicate that tests if two arguments are equal.

These methods allow you to create complex and reusable conditions in a functional programming style.

Basic Usage of Predicate

Let's start with a simple example that demonstrates the use of Predicate to check if a number is even:

Java
1Predicate<Integer> isEven = n -> n % 2 == 0; 2System.out.println(isEven.test(4)); // Outputs true 3System.out.println(isEven.test(5)); // Outputs false

This Predicate checks if a given integer is even by returning true if the number is divisible by 2 and false otherwise. The lambda expression n -> n % 2 == 0 is used to define the predicate logic. The test method is then called to evaluate the condition.

Combining Predicates

Predicates can be combined to form more complex conditions using methods like and, or, and negate. For example, you can check if a number is even and greater than ten:

Java
1Predicate<Integer> isEvenAndGreaterThanTen = isEven.and(n -> n > 10); 2System.out.println(isEvenAndGreaterThanTen.test(12)); // Outputs true 3System.out.println(isEvenAndGreaterThanTen.test(8)); // Outputs false

The and method combines the original isEven predicate with another condition n -> n > 10. The resulting predicate evaluates to true only if both conditions are satisfied.

Negating a Predicate

You can reverse the logic of a predicate using the negate method. For instance, you can create a predicate that checks if a number is odd by negating the isEven predicate:

Java
1Predicate<Integer> isOdd = isEven.negate(); 2System.out.println(isOdd.test(4)); // Outputs false 3System.out.println(isOdd.test(5)); // Outputs true

The negate method inverts the result of the isEven predicate. If isEven.test(n) returns true, then isOdd.test(n) returns false, and vice versa.

Using isEqual for Equality Checks

The Predicate interface also provides a useful static method isEqual for checking equality. You can use it to create a predicate that tests if an input value is equal to a specified value:

Java
1Predicate<Integer> isEqualToTen = Predicate.isEqual(10); 2System.out.println(isEqualToTen.test(10)); // Outputs true 3System.out.println(isEqualToTen.test(5)); // Outputs false

The isEqual method returns a predicate that checks if its input is equal to the specified value (10 in this case). This is particularly useful for simple equality checks.

Why It Matters

Understanding the Predicate interface in Java is essential for:

  • Efficient Condition Checking: Using concise and readable predicates for evaluating conditions.
  • Complex Logic Handling: Combining simple predicates to handle complex conditions without lengthy if-else statements.
  • Reusability: Defining reusable predicates for common conditions, improving code maintainability.
  • Functional Programming: Embracing functional programming techniques, making your Java code more expressive and modular.

By mastering Predicate interfaces, you can write cleaner and more robust Java applications that efficiently handle various conditions and decision-making logic.

With these basics in place, you are well-prepared to dive into practice. Understanding predicates is key to making your Java code more functional and expressive. Let's get started!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.