poyger
poyger

Reputation: 666

Predicates vs if statements

I have seen in some projects that people use Predicates instead of pure if statements, as illustrated with a simple example below:

    int i = 5;
    // Option 1
    if (i == 5) {
        // Do something
        System.out.println("if statement");
    }

    // Option 2
    Predicate<Integer> predicate = integer -> integer == 5;
    if (predicate.test(i)) {
        // Do something
        System.out.println("predicate");
    }

What's the point of preferring Predicates over if statements?

Upvotes: 27

Views: 23721

Answers (4)

Delark
Delark

Reputation: 1323

Thi is an old question, but I'll give it a try, since I am battling with it myself...

In my attempt to excuse my own usage of predicates I have made a self-rule.

I believe Predicates are useful where the "logic point" - is NOT the: leaf | corner | the end - of a: graph | tree | straight line, which would make the logic point effectively a "logic joint".

By it being a joint (aka node) it has a state, a re-usable and mutable state, that serves as a means towards an end.

In a stream, where the data is supposed to traverse a path, predicates are useful since they grant a degree of access while keeping the integrity of the stream, this is why the best predicates IMO are only method references minimizing side effects.

Even though the most common form of Predicate is newObject.equal(old), which is in itself a BiPredicate, but CAN be used with a single Predicate with side effect lambda -> lambda.equal(localCache) (so this may be an exception to the Only Method References rule).

IF, the logic serves as the output/exit point towards a different architectural design, or component, or a code that is not written by you, or even if it is written by you, one that differs on its functionality, then an if-else is my way to go.

Another benefit of predicates in the case of reactive programming is that multiple subscribers can make use of the same defined logic gate.

But if the end point of a publisher will be a single lone subscriber (which would be a case similar to your example if I'm reaching), then the logic is better done with an if-else.

Upvotes: 1

Eran
Eran

Reputation: 393841

Using a predicate makes your code more flexible.

Instead of writing a condition that always checks if i == 5, you can write a condition that evaluates a Predicate, which allows you to pass different Predicates implementing different conditions.

For example, the Predicate can be passed as an argument to a method :

public void someMethod (Predicate<Integer> predicate) {
    if(predicate.test(i)) {
        // do something
        System.out.println("predicate");
    }
    ...
}

This is how the filter method of Stream works.

Upvotes: 22

Daniel Dietrich
Daniel Dietrich

Reputation: 2272

Using if statements is the best (read: most performant) way to check binary conditions.

The switch statement may be faster for more complex situations.

A Predicate are a special form of Function. In fact the java language architect work on a way to allow generic primitive types. This will make Predicate<T> roughly equivalent to Function<T, boolean> (modulo the test vs apply method name).

If a function (resp. method) takes one or more functions as argument(s), we call it higher-order function. We say that we are passing behaviour to a function. This allows us to create powerful APIs.

String result = Match(arg).of(
        Case(isIn("-h", "--help"),    help()),
        Case(isIn("-v", "--version"), version()),
        Case($(),                     cmd -> "unknown command: " + cmd)
);

This example is taken from Javaslang, a library for object-functional programming in Java 8+.

Disclaimer: I'm the creator of Javaslang.

Upvotes: 0

Eugene
Eugene

Reputation: 120858

For the exact example that you provided, using a Predicate is a big over-kill. The compiler and then the runtime will create:

  1. a method (de-sugared predicate)
  2. a .class that will implement java.util.Predicate
  3. an instance of the class created at 2

all this versus a simple if statement.

And all this for a stateless Predicate. If your predicate is statefull, like:

 Predicate<Integer> p = (Integer j) -> this.isJGood(j); // you are capturing "this"

then every time you will use this Predicate, a new instance will be created (at least under the current JVM).

The only viable option IMO to create such a Predicate is, of course, to re-use it in multiple places (like passing as arguments to methods).

Upvotes: 23

Related Questions