Friday, 30 January 2015

Java Functional Interface

Java's Function and UnaryOperator provided in "java.util.function" package are two examples of functional interfaces and you can use them as a target for lambda expressions or method references, the package contains more interfaces, we will talk about them later. Let us see how they work.

If you had a chance to work with a stream of data, you have noticed what we usually do on the stream is applying some separate procedures to each packet of data or message. For example, processes like:
  • cleaning the message
  • normalizing 
  • looking up the price
  • calculating some index
  • and ...

Java 8's java.util.function package gives us some useful interfaces to facilitate this step by step processing or functional processing. Note that the processes we talked about were all accept one parameter and return one  parameter (lambda calculus like). This is not a limitation because the passed and returned parameter can always be a complex Java Class. 


So for simplicity if we consider all of the above input and output of the functions have type Message then we are going to do something like the following in Java 8:

while (message exist in stream) {
    message = clean(message);
    message = normalize(message);
    message = lookupPrice(message);
    message = calcIndex(message);
}

OK, why do we need it if we can do it this way? There are many reasons, we talked about the way Java 8 parallelStream() works before, you can use of simplicity of using lambda expressions and ... all is about functional programming and you'll see it yourself in a few minutes.

Example
Suppose you want to write a general purpose integer unary operator, you can do it in Java 8 like the following:

static int myOperator(int operand, UnaryOperator<Integer> operator) {
    operand = operator.apply(operand);
    return operand;
}

The UnaryOperator is defined in "java.util.function" and as you see we have used it as a passed parameter to myOperator function. Here is how we can use myOperator:

int aNumber = 10;
aNumber = myOperator(aNumber, v -> v * v);

or in a stream:

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
list.stream().forEach(a -> {
            a = myOperator(a, v -> v * v);
            a = myOperator(a, v -> v + 25);
            a = myOperator(a, v -> 2 * v + 152);
            System.out.println(a);
        });

As you see we pass the function to the myOperator which is somehow just an applier mechanism. Now if we want to write it, in general, data type, especially when the passed argument and the return value are not the same types we can define it as bellow:

static <T, R> R myGeneralOperator(T operand, Function<T, R> operator) {
     R r = operator.apply(operand);
    return r;
}
You still can use myGeneralOperator in the same way we used myOperator, it works for integers and any other kind data structure or operation, so you may use it as bellow:

Company company = person.load("google");
Person ceo = myGeneralOperator(company, company -> company.getCEO());