Functions in Java

Functions in Java

Introduction

Unlike methods, functions are first-class citizens in Java. It means functions can be passed as arguments, or be returned. Here is a method in Java:

1
2
3
public static int square(int x) {
return x * x;
}

We can replace this method with a function:

1
Function<Integer, Integer> square = x -> x * x;

And we can call this function using the following code:

1
square.apply(4);// the result is 4 * 4 = 16

Here’s some other simple examples:

1
2
3
4
5
Function<Integer, Boolean> isPositive = x -> x > 0;
System.out.println(isPositive.apply(-4));

BiFunction<Integer, Integer, Boolean> biFunction = (x, y) -> x > y;
System.out.println(biFunction.apply(1,2));

Build filter using functional programming

Let’s look at a more complicate case, in this case we can implement filtering function using functional programming:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Function;

public class FilterDemo {
public static void main(String[] args) {

ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(-2);
list.add(-3);
list.add(4);

Function<Integer, Boolean> function = x -> x > 0;// We can specify different filtering rules.
System.out.println(filter(list, function));

}

public static ArrayList<Integer> filter(ArrayList<Integer> list, Function<Integer, Boolean> function) {

ArrayList<Integer> filteredList = new ArrayList<>();

for (int element: list) {
if(function.apply(element)) {
filteredList.add(element);
}
}

return filteredList;
}

}

As shown in the above code, we can define different functions to filter out the results we want.

Function interface in Java

In Java, interfaces are abstract, which means we can not create an instance of an interface. For example, here is an interface:

1
2
3
public interface I {
void f();
}

If we instantiate I using I i = new I();, the compiler will produce an error. And if we want to have an “instance” of interface I, we should firstly build a class which implements I, then create an instance of this class:

1
2
3
4
5
6
7
8
9
10
11
12
public class A implements I {
public A() {

}
public void f() {

}
}

public static void main(String... args) {
I i = new A();
}

However, in our previous examples(such as Function<Integer, Integer> funcition = x -> x * x; ), we instantiate a Function interface, why there is no error? What is x -> x * x on earth?

In Java, x -> x * x is a lambda expression. To figure out what is lambda exprssion, we can look at the following code:

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.function.Function;

public class LambdaDemo {
public static void main(String[] args) {
Function<Integer, Boolean> function = x -> x > 0;
System.out.println(function.apply(4));
System.out.println(function.getClass());
System.out.println(function.getClass().getSuperclass());
System.out.println(function.getClass().getInterfaces().length);
System.out.println(function.getClass().getInterfaces()[0]);
}
}

The output result is:

lambdademo_output

From the result we can see, function is a object LambdaDemo$$Lambda$1/303563356, which is created by the compiler at runtime. And this object’s super class is java.lang.Object. More importantly, this object implements the java.util.function.Function interface, which is same as the case of interface I and class A. That is why we can “instantiate” a Function interface.