With the rise of lambda expression and newer features, there is an increasing necessity to review some of the functional programming concepts and how are they applied in Java.

### Currying

Currying is the process of turning a function with multiple arguments into a function with fewer arguments. For example, we can turn an addition between three numbers into a single argument function:

Function<Integer, Function<Integer, Function<Integer, Integer>>> abc = a -> b -> c -> a + b + c;

assert abc.apply(1).apply(2).apply(3) == 6;


Which is fun, but is it really useful? Definitely! Sometimes we don’t want to repeat the same argument and cannot overload the method (to simulate default parameter):

String buildUrl(String protocol, String base) {
return protocol + "://" + base;
}
//...

Function<String, String> secureUrlFun = base -> buildUrl("https", base);
Function<String, String> unsecureUrlFun = base -> buildUrl("http", base);

assert secureUrlFun.apply("adrian.md").equals("https://adrian.md");
assert unsecureUrlFun.apply("adrian.md").equals("http://adrian.md");


### Higher-order function

Function<String, String> buildSafeUrl() {
return base -> buildUrl("https", base);
}


In the previous example, buildUrl is also called first-order while buildSafeUrl - higher-order function. The definition of later one says that it should have at least one function as an argument or return a function. This opens a whole new world of possibilities, like lazy evaluation, code reuse, and function composition.

Let’s imagine we have the following structure of records / classes:

record Plug(String type) {

}

record Engine(Plug plug) {

}

record Car(Engine engine) {
}


And we are given the classic boring task of extracting type from a car object. The problem is that we might have a null at any level.

A naive engineer could slap an Optional and call it a day:

String plugType = Optional.of(new Car(null))
.map(Car::engine)
.map(Engine::plug)
.map(Plug::type)
.orElse(null);

assert plugType == null;


Spoiler alert, it’s wrong to use Optional. The only valid usage of Optional is as a return value in a method as confirmed by API note from JavaDoc. Not to mention that we didn’t create disposable wrapper objects for null check before Java 8 and there is no reason whatsoever to do these days.

We can solve this task by creating a null safe (higher-order) function:

interface NullSafeFunction<T, R> extends Function<T, R> {

default <V> NullSafeFunction<T, V> andThen(Function<? super R, ? extends V> after) {
return (T t) -> {
R result = apply(t);
if(result != null) {
return after.apply(result);
}
return null;
};
}

static <T> NullSafeFunction<T, T> identity() {
return t -> t;
}
}

//...

String nullPlugType = NullSafeFunction.<Car>identity()
.andThen(Car::engine)
.andThen(Engine::plug)
.andThen(Plug::type)
.apply(new Car(null));

assert nullPlugType == null;

String sparkPlugType = NullSafeFunction.<Car>identity()
.andThen(Car::engine)
.andThen(Engine::plug)
.andThen(Plug::type)
.apply(new Car(new Engine(new Plug("spark plug"))));

assert sparkPlugType.equals("spark plug");


Breaking down the example, we can see that NullSafeFunction::andThen returns a composed function that executes the caller first and then the argument.

To Be Continued …