Post

Java) Functional Interfaces / util.function

Java) Functional Interfaces / util.function

This post was migrated from Tistory. You can find the original here.

Lambda expressions

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
33
34
35
36
37
38
39
40
41
42
43
@FunctionalInterface
interface MyFunction {
    void run();  // public abstract void run();
}

class Main {
    static void execute(MyFunction f) { // a method whose parameter type is MyFunction
        f.run();
    }

    static MyFunction getMyFunction() { // a method whose return type is MyFunction
        MyFunction f = () -> System.out.println("f3.run()");
        return f;
    }

    public static void main(String[] args) {
        // Implement MyFunction's run() with a lambda expression
        MyFunction f1 = ()-> System.out.println("f1.run()");

        // A lambda expression is an object of an anonymous class.
        // Its type must be an interface that defines a method equivalent to the lambda.
        MyFunction f2 = new MyFunction() {  // implement run() with an anonymous class
            public void run() {   // public must be specified
                System.out.println("f2.run()");
            }
        };

        MyFunction f3 = getMyFunction();

        f1.run();
        f2.run();
        f3.run();

        execute(f1);
        execute( ()-> System.out.println("run()") );
    }
}
Result
f1.run()
f2.run()
f3.run()
f1.run()
run()

Being able to treat a lambda expression as a reference variable means methods can now be passed around just like variables.
Look closely at the comment on f2 — under the hood, what’s actually being passed around is an object, not a method, so fundamentally nothing has changed.

Functional interfaces provided by java.util.function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.util.function.*;

class Main{
    public static void main(String[] args) {
        Supplier<Integer> supply = () -> 1;
        System.out.println(supply.get());

        Consumer<Integer> consumer = v -> System.out.println(v);
        consumer.accept(2);

        Function<Integer, String> func = String::valueOf;
        System.out.println(func.apply(3));

        Predicate<Integer> func2 = v-> v>5;
        System.out.println(func2.test(4));
    }
}
Result
1
2
3
false

There are also others, such as java.lang.Runnable, BiConsumer<T, U>, BiPredicate<T, U>, BiFunctionM<T, U, R>.

1
2
3
4
5
6
7
        Predicate<Integer> p = i -> i < 100;
        Predicate<Integer> q = i -> i < 200;
        Predicate<Integer> r = i -> i%2 == 0;
        Predicate<Integer> notP = p.negate(); // i >= 100

        Predicate<Integer> all = notP.and(q.or(r)); // 100<=i && (i<200 || i% 2==0)
         System.out.println(all.test(150));       // true

Predicate<T> instances can be combined.

Functional interfaces in the Collections Framework

1
2
3
4
5
6
(Collection).removeIf(Predicate<E> f);
(List).replaceAll(UnaryOperator<E> f);
(Iterable).forEach(Consumer<T> f);

(Map).forEach(BiConsumer<K,V> f);
(Map).compute(K key, BiFunction<K,V,V> f) // performs operation f on the given key

These are methods in the Collections Framework that make use of functional interfaces.

This post is licensed under CC BY-NC 4.0 by the author.