How do I use Predicate.not() in Streams?

To use Predicate.not() in streams, you take advantage of its ability to negate an existing predicate. This can be helpful in filter operations where you want to filter out elements that match a given condition instead of including them.

Here’s how you can use Predicate.not in streams:

Basic Explanation

  1. What it does: The Predicate.not() method is a static method (added in Java 11) that creates a predicate that negates the specified predicate. Instead of writing complex logic for negation, you can directly use Predicate.not() for cleaner and more readable code.

  2. Use Case in Streams: When working with Java Streams, you often use .filter() to include elements that satisfy a condition. If you want to exclude elements that satisfy a condition, you can use Predicate.not().


Example: Using Predicate.not() in a Stream

package org.kodejava.util.function;

import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class PredicateNotExample {
    public static void main(String[] args) {
        // Define a list of integers
        List<Integer> numbers = List.of(5, 15, 8, 25, 3, 12);

        // Define a predicate to filter numbers greater than 10
        Predicate<Integer> isGreaterThan10 = number -> number > 10;

        // Use Predicate.not() to filter numbers NOT greater than 10
        List<Integer> filteredNumbers = numbers.stream()
                .filter(Predicate.not(isGreaterThan10))
                .collect(Collectors.toList());

        // Print the filtered list
        System.out.println(filteredNumbers); // Output: [5, 8, 3]
    }
}

Breakdown of the Code:

  1. Define Predicate
    A predicate is defined (isGreaterThan10) to test if a number is greater than 10.

  2. Stream Filtering

    • Using .stream() to process the list of numbers.
    • .filter(Predicate.not(isGreaterThan10)) negates the predicate, effectively including numbers less than or equal to 10.
  3. Collect Results
    The result is collected using .collect(Collectors.toList()).


Why Use Predicate.not()?

  • Improved Readability: Instead of writing a negation explicitly like x -> !isGreaterThan10.test(x), you can use Predicate.not(isGreaterThan10) for better readability.

  • Reusability: Predicate.not() can work for any predicate, making it easier to reuse your existing predicates in multiple ways.

  • Less Prone to Errors: Writing custom negation logic in lambdas may lead to errors or make the code harder to understand. Predicate.not() makes intent clear and reduces the chance of mistakes.


Notes:

  • The Predicate.not() method was introduced in Java 11. Ensure you are using Java 11 or later to use it.
  • You can apply this with any kind of predicate—numerical, string-based, or custom objects.

How do I use the Predicate functional interface in Java?

The Predicate class in Java is a functional interface introduced in Java 8 under the java.util.function package. It is used to test a condition on an input and return a boolean value (true or false). Predicates are often used in lambda expressions or method references to filter data or apply conditional logic.

Here’s how we can use the Predicate class in Java:

Basic Predicate Usage

The Predicate interface has a single abstract method:

boolean test(T t);

We implement this method to provide our condition logic.

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class PredicateExample {
    public static void main(String[] args) {
        // Create a predicate that checks if a number is greater than 10
        Predicate<Integer> isGreaterThan10 = number -> number > 10;

        // Test the condition
        System.out.println(isGreaterThan10.test(15)); // Output: true
        System.out.println(isGreaterThan10.test(8));  // Output: false
    }
}

Chaining Predicates

Predicates provide methods to combine multiple conditions:
and() – Combines two predicates with logical AND.
or() – Combines two predicates with logical OR.
negate() – Negates the predicate (logical NOT).

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class PredicateChainingExample {
    public static void main(String[] args) {
        Predicate<Integer> isEven = number -> number % 2 == 0;
        Predicate<Integer> isGreaterThan5 = number -> number > 5;

        // Chain predicates
        Predicate<Integer> isEvenAndGreaterThan5 = isEven.and(isGreaterThan5);
        Predicate<Integer> isEvenOrGreaterThan5 = isEven.or(isGreaterThan5);

        // Test
        System.out.println(isEvenAndGreaterThan5.test(8));  // Output: true
        System.out.println(isEvenAndGreaterThan5.test(3));  // Output: false
        System.out.println(isEvenOrGreaterThan5.test(3));   // Output: false
        System.out.println(isEvenOrGreaterThan5.test(7));   // Output: true
    }
}

Using Predicate in Collections

The Predicate interface is extensively used in working with Streams or filtering collections.

Example:

package org.kodejava.util.function;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;

public class PredicateWithStreams {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Carol", "Mallory");

        // Create a predicate that tests if the string length is greater than 3
        Predicate<String> lengthGreaterThan3 = name -> name.length() > 3;

        // Filter and collect using the predicate
        List<String> filteredNames = names.stream()
                .filter(lengthGreaterThan3)
                .collect(Collectors.toList());

        // Output: [Alice, Carol, Mallory]
        System.out.println(filteredNames);
    }
}

Using Predicate with Default Methods

isEqual()

This static method evaluates if an object is equal to a predefined value.

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class PredicateIsEqualExample {
    public static void main(String[] args) {
        Predicate<String> isEqualToMark = Predicate.isEqual("Alice");

        // Output: true
        System.out.println(isEqualToMark.test("Alice"));
        // Output: false
        System.out.println(isEqualToMark.test("Bob"));
    }
}

Custom Predicate Usage

We can create our own predicate and pass it around in our code.

Example:

package org.kodejava.util.function;

import java.util.function.Predicate;

public class CustomPredicateExample {
    public static void main(String[] args) {
        // A custom method accepting a predicate
        testPredicate(value -> value > 10);

        // Another predicate for custom logic
        Predicate<Integer> isOdd = value -> value % 2 != 0;
        // Output: true
        System.out.println(isOdd.test(7));
    }

    static void testPredicate(Predicate<Integer> predicate) {
        // Output: true
        System.out.println(predicate.test(15));
    }
}

Summary

  • The Predicate interface is used for conditional checks and filtering data.
  • It works seamlessly with lambda expressions and method references.
  • You can combine multiple predicates using and, or, and negate.

This makes Predicate a very powerful and convenient tool for functional programming in Java!