1. Overview

In this article, we’ll define a TriFunction FunctionalInterface that represents a function that accepts three arguments and computes the result. Later on, we’ll also see an example using the built-in Function3 of the Vavr library.

2. Creating Our Own TriFunction Interface

Since version 8, Java defines the BiFunction FunctionalInterface. It represents a function that accepts two arguments and computes its result. To allow function composition, it also provides an andThen() method that applies another Function to the result of the BiFunction.

Similarly, we’ll define our TriFunction interface and give it the andThen() method:

@FunctionalInterface
public interface TriFunction<T, U, V, R> {

    R apply(T t, U u, V v);

    default <K> TriFunction<T, U, V, K> andThen(Function<? super R, ? extends K> after) {
        Objects.requireNonNull(after);
        return (T t, U u, V v) -> after.apply(apply(t, u, v));
    }
}

Let’s see how we can use this interface. We’ll define a function that takes three Integers, multiply the two first operands and then add the last operand:

static TriFunction<Integer, Integer, Integer, Integer> multiplyThenAdd = (x, y, z) -> x * y + z;

Let’s note that the result of this method will be accurate only if the product of the two first operands is lower than the Integer maximum value.

As an example, we can use the andThen() method to define a TriFunction that:

  • first, applies multiplyThenAdd() to the arguments
  • then, applies a Function that computes the quotient of the Euclidian division of an Integer by 10 to the result of the previous step
static TriFunction<Integer, Integer, Integer, Integer> multiplyThenAddThenDivideByTen = multiplyThenAdd.andThen(x -> x / 10);

We can now write some quick tests to check that our TriFunctions behave as expected:

@Test
void whenMultiplyThenAdd_ThenReturnsCorrectResult() {
    assertEquals(25, multiplyThenAdd.apply(2, 10, 5));
}

@Test
void whenMultiplyThenAddThenDivideByTen_ThenReturnsCorrectResult() {
    assertEquals(2, multiplyThenAddThenDivideByTen.apply(2, 10, 5));
}

As a last note, the operands of the TriFunction can be of various types. For instance, we can define a TriFunction that converts an Integer to a String or returns another given String depending on a Boolean condition:

static TriFunction<Integer, String, Boolean, String> convertIntegerOrReturnStringDependingOnCondition = (myInt, myStr, myBool) -> {
    if (Boolean.TRUE.equals(myBool)) {
        return myInt != null ? myInt.toString() : "";
    } else {
        return myStr;
    }
};

3. Using Vavr’s Function3

The Vavr library already defines a Function3 interface that has the behavior we want. First, let’s add the Vavr dependency to our project:

<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.10.4</version>
</dependency>

We can now redefine the multiplyThenAdd() and multiplyThenAddThenDivideByTen() methods with it:

static Function3<Integer, Integer, Integer, Integer> multiplyThenAdd = (x, y, z) -> x * y + z;

static Function3<Integer, Integer, Integer, Integer> multiplyThenAddThenDivideByTen = multiplyThenAdd.andThen(x -> x / 10);

Using Vavr can be a good choice if we need to define functions with up to 8 arguments. Function4, Function5, Function8 are indeed already defined in the library.

4. Conclusion

In this tutorial, we’ve implemented our own FunctionalInterface for a function that accepts 3 arguments. We’ve also highlighted that the Vavr library contains an implementation of this kind of function.

As always, the code is available over on GitHub.

Course – LS (cat=Java)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.