Functional Interfaces in Java
Before moving to examples, do read the blog Functional programming in Java - What and Why? to get more context on what is functional programming.
There are few other ways apart from lambdas, that uses the concept of functional programming and they are:
- Functional Interfaces
- Monads - Jump to Monads section
Functional Interfaces
Functional interfaces is an interface with one abstract method which can be used to implement different use cases. Below are some use cases that might be useful.
Case 1: Single Parameter T and result R
Function<T, R>
and apply()
Given a list of names, find the number the names in the list.
1
2
Function<List<String>, Integer> sizeOfList = (value) -> value.size();
logger.debug("Number of names : {}", sizeOfList.apply(names));
Case 1.1: Nested functions
Function<T, R>
, andThen
and apply()
Given a list of names, find the number the names that starts with A.
1
2
3
4
5
6
7
8
9
10
// Function 1
Function<List<String>, List<String>> startsWithA = (value) -> value.stream()
.filter(name -> name.startsWith("A"))
.collect(Collectors.toList());
// Function 2
Function<List<String>, Integer> sizeOfList = (value) -> value.size();
// Nesting : Function 1 andThen Function 2
Function<List<String>, List<String>> numberOfNamesStartsWithA = startsWithA.andThen(startsWithA);
logger.debug("Number of names that starts with A : {}", numberOfNamesStartsWithA.apply(names);
Case 1.2: Function as parameter and result R
Function<T, R>
, compose()
and apply()
Given a number, add 10 to it and multiply by 20.
1
2
3
4
5
6
7
// Function 1
Function<Integer, Integer> multiplyBy20 = (value) -> value * 20;
// Function 2
Function<Integer, Integer> add10 = (value) -> value + 10;
// Function 2 instance passed as parameter to Function 1
Function<Integer, Integer> add10ThenMultiplyBy20 = multiplyBy20.compose(add10);
logger.debug(add10ThenMultiplyBy20.apply(30)); // (30 + 10) * 20 = 800
Case 1.3: Two parameters (A and B) and result R
BiFunction<A, B, R>
and apply()
Given two numbers, find the sum of the numbers.
1
2
BiFunction<Integer, Integer, Integer> addTwoNumbers = (a, b) -> a + b;
logger.debug(addTwoNumbers.apply(30, 10)); // (30 + 10) = 40
Case 1.4: Three parameters (A, B and C) and result R
TriFunction<A, B, C, R>
and apply()
Given three numbers, find the sum of the numbers.
1
2
TriFunction<Integer, Integer> addThreeNumbers = (a, b, c) -> a + b + c;
logger.debug(addThreeNumbers.apply(30, 10, 40)); // (30 + 10+ 40) = 80
Case 2: Single Parameter T and boolean result
Predicate<T>
and test()
Given a number, find if the number is greater than 100 or not.
1
2
3
Predicate<Integer> isNumberGreaterThan100 = value -> (value > 100);
logger.debug(isNumberGreaterThan100.test(10)); // false
logger.debug(isNumberGreaterThan100.test(200)); // true
Case 3: Single Parameter T and no result
Consumer<T>
and accept()
Given list of names, display all the names in the list.
1
2
Consumer<List<String>> displayNames = values -> values.stream().forEach(a -> logger.debug("{} ", name));
displayNames.accept(names);
Case 3.1: Nesting of Functions with single Parameter T and no result
Consumer<T>
, andThen()
and accept()
Given list of names, display all the names in the list followed by the number of names.
1
2
3
Consumer<List<String>> displayNames = values -> values.stream().forEach(a -> logger.debug("{} ", name));
Consumer<Integer> printSizeOfList = values -> logger.debug("Total number of names : {}", values.size);
displayNames.andThen(printSizeOfList).accept(names);
Case 4: No Parameters and result R
Supplier<T>
and get()
Print a random number.
1
2
Supplier<Double> findRandomValue = () -> Math.random();
logger.debug(findRandomValue.get());
Monads
This post is licensed under CC BY 4.0 by the author.