Java Function Passing

In Java, passing a function as parameter is not directly supported because no constructs like lambda exist in the Java programming language (they do since Java 8, see the last section). But there are alternatives, and in this post I will describe some of them.


Interfaces / Strategy Pattern


With an interface, it is possible to mimic function passing in Java. An example:
    /**
     * returns the added results of func. Func recieves [0..times-1].
     */

    private int accumulate(Function func, int times) {
        int result = 0;
        for (int i = 0; i < times; i++) {
            result += func.calc(i);
        }
        return result;
    }

    /**
     * A function interface.
     */

    interface Function {
        int calc(int x);
    }
We can now use this structure to calculate various things:
    /**
     * adds all the numbers from 1 to the given number.
     */

    public int addNumbersTo(int limit) {
        return accumulate(new Function() {

            @Override
            public int calc(int x) {
                return x + 1;
            }
        }, limit);
    }

    /*
     * adds up the first X even numbers.
     */

    public int addFirstXEvenNumbers(int x) {
        return accumulate(new Function() {

            @Override
            public int calc(int x) {
                return (2 * x) + 2;
            }
        }, x);
    }
It is also possible that the calc function accepts an unknown number of arguments by using a list.

Basically, this is the Strategy Pattern without context and with anonymous implementations of the interfaces.

Advantages:
I hope the advantage of doing this becomes clear: We can extract code that is used by a whole lot of functions to make the code cleaner and easier to maintain.

Disadvantages:
The code is quite verbose in Java.
Speed: it is slower than writing all functions individually. There are two reasons for this: the general overhead from function calling (which can generally be neglected) and the fact that the Java compiler is not able to perform a lot of optimizations. Most of the time, the speed difference will not matter though.


Template Method Pattern


In some situations it makes more sense to use the template method pattern.
public abstract class Accumulator {

    /**
     * returns the added results of this accumulator.
     */

    public int accumulate(int times) {
        int result = 0;
        for (int i = 0; i < times; i++) {
            result += getNextNumber(i);
        }
        return result;
    }

    /**
     * returns the i'th number.
     */

    abstract int getNextNumber(int i);
}

public class AllNumberAcc extends Accumulator {

    @Override
    int getNextNumber(int i) {
        return i + 1;
    }
}

public class EvenNumberAcc extends Accumulator {
   
    @Override
    int getNextNumber(int i) {
        return (2 * i) + 2;
    }
}
And use it like this:
EvenNumberAcc ena = new EvenNumberAcc();
ena.accumulate(10);
Advantages:
It is more flexible than the approach described above

Disadvantages:
It is more work to add a new function and if too many are needed, the many classes may get confusing.


Think about alternatives


If the code is only used by some functions which do nearly the same think about how the function can be changed (sometimes it is enough to add an extra boolean parameter to the signature and an if clause to the method body).

If for example you can be sure that anything you will ever accumulate are numbers up to ten or the first ten even numbers, the above example could look like this:
    /**
     * returns the added results of func. Func receives [0..times-1].
     */

    private int accumulate(boolean allNumbers, int times) {
        int result = 0;
        for (int i = 0; i < times; i++) {
            if (allNumbers) {
                result += (i + 1);
            } else {
                result += ((2 * i) + 2);
            }
        }
        return result;
    }

    /**
     * adds all the numbers from 1 to 10 (result will always be 55).
     */

    public int addNumbersToTen() {
        return accumulate(true, 10);
    }

    /*
     * adds up the first ten even numbers.
     */

    public int addFirstTenEvenNumbers() {
        return accumulate(false, 10);
    }
If you have for example three different cases you could use an Enum and a switch statement. But if the cases become too many, this can get ugly quite quickly.
Also, there is a performance loss as the if statement has to be executed each time. But again, in most cases this can be neglected.

The above solution is fine for smaller programs, but Java is an object oriented programming language, so that is what should generally be used (most of the time it is a bad idea to fight against the way a language was designed).


Using Lambda to pass a function in Java


So Java now finally offers lambda, which makes passing a function easier (but it is not nearly perfect).

With Lamdba, the code would look similar to the strategy pattern described above. But instead of having to define a new (anonymous) class, we can just pass a function. The accumulate function and Function class look the same, but here is how they are called:
    /**
     * adds all the numbers from 1 to the given number.
     */

    public int addNumbersTo(int limit) {
        return accumulate((int i) -> i + 1, limit);
    }

    /*
     * adds up the first X even numbers.
     */

    public int addFirstXEvenNumbers(int x) {
        return accumulate((int i) -> (2 * i) + 2, x));
    }
So what are we doing here? We are saying that we have a function, and it takes an integer as input. We name that integer i. And every time it is called, it will return i + 1.

This is a lot shorter than the strategy pattern used to pass a function in Java. And once you get used to it, also a lot more readable.


The ways to mimic function passing in Java are quite similar, but they are not the same. It depends on the situation which one to use (or if it would be better to use something entirely different).

Leave a Reply

Your email address will not be published.