Java Function
last modified July 7, 2024
In this article we show how to work with the Function interface in Java. The
interface is located in the java.util.function
package.
Function definition
Function is a Java functional interface which represents a function that accepts one argument and produces a result. It is an interface with a single abstract method that takes input(s), performs a specific task, and optionally returns an output.
Since Java does not support plain functions, the interface was introduced in
order to overcome this limitation. In fact, the compiler creates behind the
scenes an object from each Function
.
The Function
is used to create small plain functions outside a
class and anomymous expressions, especially in the functional programming
paradigm.
Simple Function example
The following is a simple example that uses Function
.
import java.util.function.Function; import java.util.List; Function<Integer, Integer> doubleNum = n -> n * 2; void main() { var vals = List.of(1, 2, 3, 4, 5 ); for (var e: vals) { int res = doubleNum.apply(e); System.out.println(res); } }
We define a function that multiplies a value by two.
Function<Integer, Integer> doubleNum = n -> n * 2;
The function declares two types. The first is the type of the input to the
function and the second is the type of the result of the function. The variable
following the equals character is the input variable. The result of the
expression after ->
is the function return value. Note that we
have defined a function outside of a class.
var vals = List.of(1, 2, 3, 4, 5 ); for (var e: vals) { int res = doubleNum.apply(e); System.out.println(res); }
We go over the list of integers and apply the function on each element.
$ java Main.java 2 4 6 8 10
In the next example, we use Function
to define a greeter.
import java.util.List; import java.util.function.Function; Function<String, String> greet = name -> String.format("Hello %s!", name); void main() { var names = List.of("Peter", "Lucia", "Jozef", "Martin"); for (var name : names) { String greeting = greet.apply(name); System.out.println(greeting); } }
The function in the example takes a name as a parameter and returns a greeting.
Function<String, String> greet = name -> String.format("Hello %s!", name);
We use template string to construct the greeting from the "Hello" literal and
the name
input variable.
$ java Main.java Hello Peter! Hello Lucia! Hello Jozef! Hello Martin!
Removing duplicates
In the next example, we remove duplicates from a list of integers.
import java.util.function.Function; import java.util.stream.Collectors; import java.util.List; Function<List<Integer>, List<Integer>> remDup = vals -> vals.stream() .distinct() .collect(Collectors.toList()); void main() { var nums = List.of(1, 2, 1, 2, 3, 4, 5, 1, 0, -1 ); var nums2 = remDup.apply(nums); System.out.println(nums2); }
We have a list of integers. We define the remDup
function to remove
the duplicate values.
Function<List<Integer>, List<Integer>> remDup = vals -> vals.stream() .distinct() .collect(Collectors.toList());
The function takes a list of integers as input and retuns a list of integers.
In its body it uses the distinct
method to do the job.
$ java Main.java [1, 2, 3, 4, 5, 0, -1]
Function in a filter
The stream
filter
method expects a predicate function.
We have a special type of a function called Predicate
. But
we can also use Function
.
import java.util.function.Function; import java.util.List; Function<Integer, Boolean> isEven = n -> n % 2 == 0; void main() { var vals = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9); vals.stream().filter(isEven::apply).forEach(System.out::println); }
We define the isEven
function which returns true if the number is
an even number.
vals.stream().filter(isEven::apply).forEach(System.out::println);
We pass the reference to the function's apply
method.
$ java Main.java 2 4 6 8
The predicate function would be defined as follows:
Predicate<Integer> isEven = n -> n % 2 == 0;
Calculating age
The following example uses a function to calculate the age of a user.
import java.time.LocalDate; import java.time.Period; import java.util.List; import java.util.function.Consumer; import java.util.function.Function; Function<LocalDate, Integer> findAge = dob -> Period.between(dob, LocalDate.now()).getYears(); Consumer<User> action = u -> System.out.printf("%s is %d years old%n", u.name, findAge.apply(u.dob)); void main() { List<User> users = List.of( User.of("John Doe", "gardener", LocalDate.of(1956, 11, 12)), User.of("Roger Roe", "driver", LocalDate.of(1976, 11, 12)), User.of("John Doe", "teacher", LocalDate.of(1967, 1, 7)), User.of("John Doe", "gardener", LocalDate.of(1998, 5, 22))); users.forEach(action); } record User(String name, String occupation, LocalDate dob) { static User of(String name, String occupation, LocalDate dob) { return new User(name, occupation, dob); } }
We have a list of users. Each user has a date of birth as a field. We calculate the user's age in a function from this field.
Function<LocalDate, Integer> findAge = dob -> Period.between(dob, LocalDate.now()).getYears();
The function uses a simple expression in which the age is calculated using
Period.between
method.
Consumer<User> action = u -> System.out.printf("%s is %d years old%n", u.name, findAge.apply(u.dob));
We define a consumer that prints the message for each element.
$ java Main.java John Doe is67 years old Roger Roe is47 years old John Doe is57 years old John Doe is25 years old
Categorizing age
The next example uses a function with a switch expression.
import java.util.function.Function; import java.util.function.Consumer; import java.util.List; Function<Integer, String> ageCategory = age -> switch (age) { case Integer n when n < 18 && n > 0 -> "minor"; case Integer n when n >= 18 && n < 64 -> "adult"; case Integer n when n > 64 -> "senior"; default -> "n/a"; }; Consumer<String> action = System.out::println; void main() { List<Integer> ages = List.of(11, 18, 17, 19, 21, 55, 86, 99, 43, 65, 63); ages.stream().map(age -> ageCategory.apply(age)).forEach(action); }
We have a list of age values. We put each of the values into a category: minor, adult, and senior.
$ java Main.java minor adult minor adult adult adult senior senior adult senior adult
Key extractor Function
We define a function that serves as a key extractor for a comparator.
import java.util.function.Function; import java.util.Comparator; import java.util.List; Function<String, Integer> strLen = String::length; void main() { var words = List.of("peculiar", "up", "blue", "atom", "by", "nice", "storm", "edible", "sky", "bookworm", "stronghold"); words.forEach(System.out::println); System.out.println("----------------------"); var sorted = words.stream().sorted(Comparator.comparing(strLen)).toList(); sorted.forEach(System.out::println); }
We have a list of words. We sort the words by their length.
Function<String, Integer> strLen = String::length;
The function returns the string length of the passed value. It serves as a key for the comparator object.
var sorted = words.stream().sorted(Comparator.comparing(strLen)).toList();
We pass our key-extractor function to Comparator.comparing
, which
generates a comparator for the sorted
method.
$ java Main.java peculiar up blue atom by nice storm edible sky bookworm stronghold ---------------------- up by sky blue atom nice storm edible peculiar bookworm stronghold
Function composition
Functions can be composed with the compose
and andThen
methods. The difference is the order in which the functions are called.
import java.util.function.Function; void main() { Function<String, String> upperFun = String::toUpperCase; Function<String, String> reverseFun = val -> new StringBuilder(val).reverse().toString(); var res = upperFun.compose(reverseFun).apply("falcon"); System.out.println(res); }
The compose
function aplies the reverseFun
and the
upperFun
on the parameter.
$ java Main.java NOCLAF
Sometimes, the order in which the functions are composed matters.
import java.util.function.Function; void main() { Function<Double, Double> half = a -> a / 2; Function<Double, Double> square = a -> a * a; Function<Double, Double> squareAndThenHalf = square.andThen(half); Double res1 = squareAndThenHalf.apply(3d); System.out.println(res1); Function<Double, Double> squareComposeHalf = square.compose(half); Double res2 = squareComposeHalf.apply(3d); System.out.println(res2); }
We have two methods half
and square
.
Function<Double, Double> squareAndThenHalf = square.andThen(half); Double res1 = squareAndThenHalf.apply(3d);
The andThen
method first squares and then halves.
Function<Double, Double> squareComposeHalf = square.compose(half); Double res2 = squareComposeHalf.apply(3d);
The compose
method first halves and then squares.
$ java Main.java 4.5 2.25
In the next example, we combine three functions.
import java.util.function.Function; Function<Integer, Integer> fn1 = n -> n + 1; Function<Integer, Integer> fn2 = n -> n * 2; Function<Integer, Integer> fn3 = n -> n * n; Function<Integer, Integer> cfn1 = fn1.andThen(fn2).andThen(fn3); Function<Integer, Integer> cfn2 = fn1.compose(fn2).compose(fn3); void main() { Integer res = cfn1.apply(10); System.out.println(res); Integer res2 = cfn2.apply(10); System.out.println(res2); }
First, we compose the three functions with andThen
and then with
compose
.
$ java Main.java 484 201
Passing Function as a parameter
In the following example, we pass the defined Function
to another
function as a parameter.
import java.util.ArrayList; import java.util.List; import java.util.function.Function; void main() { List<String> words = List.of("coin", "pen", "Monday", "NASA", "Moscow", "cup", "notebook", "class"); Function<String, String> uf = String::toUpperCase; Function<String, String> lf = String::toLowerCase; var res = modify(words, uf); System.out.println(res); var res2 = modify(words, lf); System.out.println(res2); } List<String> modify(List<String> data, Function<String, String> f) { var uppered = new ArrayList<String>(); for (var e : data) { uppered.add(f.apply(e)); } return uppered; }
In the program we have a list of words. We define the modify
method
which takes a function as a parameter. The function transforms the array
elements and returns a new list of modified strings.
Function<String, String> uf = String::toUpperCase; Function<String, String> lf = String::toLowerCase;
We have two functions. They uppercase and lowercase the passed word.
List<String> modify(List<String> data, Function<String, String> f) {
The modify
function takes a function as the second parameter.
$ java Main.java [COIN, PEN, MONDAY, NASA, MOSCOW, CUP, NOTEBOOK, CLASS] [coin, pen, monday, nasa, moscow, cup, notebook, class]
Source
Java Function - language reference
In this article we have worked with Java Function interface.
Author
List all Java tutorials.