o7planning

Java Function Tutorial with Examples

  1. Function interface
  2. Function + Method reference
  3. Function + Constructor reference
  4. Function Usages
  5. Function.compose(Function before)
  6. Function.andThen(Function after)
  7. Function.identity()

1. Function interface

In Java 8, Function is a functional interface, which represents an operator that accepts an input value and returns a value.
Source code of Function interface:
Function interface
package java.util.function;

import java.util.Objects;

@FunctionalInterface
public interface Function<T, R> {
 
    R apply(T t);
 
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
 
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }
 
    static <T> Function<T, T> identity() {
        return t -> t;
    }
}
Example:
FunctionEx1.java
package org.o7planning.ex;

import java.util.function.Function;

public class FunctionEx1 {

    public static void main(String[] args) {
        
        Function<String, Integer> func = (text) -> text.length();
        
        int length = func.apply("Function interface tutorial");
        
        System.out.println("Length: " + length);
    }
}
Output:
Length: 27
Example: Processing elements of a List object to create a new List object.
FunctionEx2.java
package org.o7planning.ex;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class FunctionEx2 {

    public static void main(String[] args) {
        
        Function<String, String> func = text -> text.toUpperCase();
        
        List<String> list = Arrays.asList("Java", "C#", "Python");

        List<String> newList = map(func, list);
    
        newList.forEach(System.out::println);
    }
    
    public static <T,R> List<R> map(Function<T,R> mapper, List<T> list) {
        List<R> result = new ArrayList<R>();
        
        for(T t: list)  {
            R r = mapper.apply(t);
            result.add(r);
        }
        return result;
    }
}
Output:
JAVA
C#
PYTHON
Example: Using Function to convert a List object into a Map object:
FunctionEx3.java
package org.o7planning.ex;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

public class FunctionEx3 {

    public static void main(String[] args) {
        
        Function<String, Integer> func = text -> text.length();
        
        List<String> list = Arrays.asList("Java", "C#", "Python");

        Map<String, Integer> map = listToMap(func, list);
    
        // @see: Map.forEach(BiConsumer).
        map.forEach((t,r) -> System.out.println(t + " : " + r));
    }
    
    public static <T,R> Map<T,R> listToMap(Function<T,R> mapper, List<T> list) {
        Map<T, R> result = new HashMap<T, R>();
        
        for(T t: list)  {
            R r = mapper.apply(t);
            result.put(t, r);
        }
        return result;
    }
}
Output:
C# : 2
Java : 4
Python : 6

2. Function + Method reference

M.ref example 1:
If a static method takes a single parameter and returns a value, its reference can be considered as a Function.
Function_mref_ex1.java
package org.o7planning.ex;

import java.util.function.Function;

public class Function_mref_ex1 {

    public static void main(String[] args) {

        // A method of Math class: public static long round(double)
        Function<Double, Long> func1 = Math::round; // Method reference
        Function<Double, Long> func2 = value -> Math.round(value);

        System.out.println(func1.apply(100.7));
        System.out.println(func2.apply(100.7));
    }
}
Output:
101
101
M.ref example 2:
If a method is non-static (non-static method), takes no parameters, and returns a value, its reference can be considered as a Function.
Function_mref_ex2.java
package org.o7planning.ex;

import java.util.function.Function;

public class Function_mref_ex2 {

    public static void main(String[] args) {

        // A method of String class: public int length()
        Function<String, Integer> func1 = String::length; // Method reference
        
        Function<String, Integer> func2 = text -> text.length();

        System.out.println(func1.apply("Java")); // 4
        System.out.println(func2.apply("Java")); // 4
    }
}
M.ref example 3:
Next, take a look at CurrencyFormatter class below:
  • CurrencyFormatter.usd(double) method has a parameter of type Double and returns a String. So its reference CurrencyFormatter::usd can be considered as Function<Double,String>.
CurrencyFormatter.java
package org.o7planning.tax;

public class CurrencyFormatter {

    // Dollar
    public static String usd(double amount) {
        return "$" + amount;
    }

    // Euro
    public static String euro(double amount) {
        return "€" + amount;
    }

    // Vietnam Dong.
    public static String vnd(double amount) {
        return amount + "VND";
    }
}
TaxCalcExample.java
package org.o7planning.tax;

import java.util.function.Function;

public class TaxCalcExample {

    public static void main(String[] args) {

        double amount = 1000;

        String format = formatCurrency("VN", amount);

        System.out.println("VN: " + format);

        format = formatCurrency("US", amount);

        System.out.println("US: " + format);

        format = formatCurrency("EU", amount);

        System.out.println("EU: " + format);
    }

    public static String formatCurrency(String countryCode, double amount) {
        if ("VN".equals(countryCode)) {
            Function<Double, String> formatter = CurrencyFormatter::vnd; // Method reference
            return _formatCurrency(formatter, amount);
        }
        if ("US".equals(countryCode)) {
            return _formatCurrency(CurrencyFormatter::usd, amount);
        }
        if ("EU".equals(countryCode)) {
            return _formatCurrency(CurrencyFormatter::euro, amount);
        }
        throw new RuntimeException("No formatter for " + countryCode);
    }

    private static String _formatCurrency(Function<Double, String> formatter, double amount) {
        return formatter.apply(amount);
    }
}
Output:
VN: 1000.0VND
US: $1000.0
EU: €1000.0

3. Function + Constructor reference

As you know a constructor is used to create an object, which means it returns a value. So if the constructor has a single parameter, its reference will be considered as a Function.
Student.java
package org.o7planning.cr;

public class Student {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
ConstructorReferenceTest.java
package org.o7planning.cr;

import java.util.function.Function;

public class ConstructorReferenceTest {

    public static void main(String[] args) {
        Function<String, Student> f1 = Student::new; // Constructor Reference
        Function<String, Student> f2 = (name) -> new Student(name); // Lambda Expression

    
        System.out.println(f1.apply("Tom").getName());
        System.out.println(f2.apply("Jerry").getName());
    }
}
Output:
Tom
Jerry

4. Function Usages

Below is a list of methods in the java.util package using the Function interface:
static
<T,U extends Comparable<? super U>>
Comparator<T>
Comparator.comparing(Function<? super T,? extends U> keyExtractor)
static <T,U> Comparator<T>
Comparator.comparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)
V
Hashtable.computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
V
HashMap.computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
default V
Map.computeIfAbsent(K key, Function<? super K,? extends V> mappingFunction)
<U> Optional<U>
Optional.flatMap(Function<? super T,Optional<U>> mapper)
<U> Optional<U>
Optional.map(Function<? super T,? extends U> mapper)
default
<U extends Comparable<? super U>>
Comparator<T>
Comparator.thenComparing(Function<? super T,? extends U> keyExtractor)
default <U> Comparator<T>
Comparator.thenComparing(Function<? super T,? extends U> keyExtractor, Comparator<? super U> keyComparator)

5. Function.compose(Function before)

Here is the definition of Function.compose method:
@FunctionalInterface
public interface Function<T,R> {
    
    R apply(T t);
    
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }
    
    // Other default methods ..
}
And we rewrite this method in an easier way to understand:
@FunctionalInterface
public interface Function<T,R> {
    
    R apply(T t);
    
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        
        return (V v) -> {
            T t = before.apply(v);
            R r = this.apply(t);
            return r;
        };
    }
    
    // Other default methods ..
}
Example:
FunctionEx6.java
package org.o7planning.ex;

import java.util.function.Function;

public class FunctionEx6 {

    public static void main(String[] args) {
        
        Function<String, Integer> func = content -> content.length();
        
        Function<Article, String> before = article -> article.getContent();
        
        Article article = new Article("Java Tutorial", "Java Tutorial Content...");
        
        int contentLength = func.compose(before).apply(article);
        
        System.out.println("The length of the article content: " + contentLength);
    }
}

class Article {
    private String title;
    private String content;
 
    public Article(String title, String content) {
        this.title = title;
        this.content = content;
    }
    
    public String getTitle() {
        return title;
    }
    public String getContent() {
        return content;
    }
}
Output:
The length of the article content: 24

6. Function.andThen(Function after)

Here is the definition of Function.andThen method:
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    // Other default methods ..
}
And we rewrite this method in an easier way to understand:
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);
    
    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        
        return (T t) -> {
            R r = this.apply(t);
            V v = after.apply(r);
            return v;
        };
    }

    // Other default methods ..
}
Example:
FunctionEx7.java
package org.o7planning.ex;

import java.util.function.Function;

public class FunctionEx7 {

    public static void main(String[] args) {
        
        Function<Post, String> func = post -> post.getContent();
        
        Function<String, Integer> after = content -> content.length();
        
        Post post = new Post("Java Tutorial", "Java Tutorial Content...");
        
        int contentLength = func.andThen(after).apply(post);
        
        System.out.println("The length of the post content: " + contentLength);
    }
}

class Post {
    private String title;
    private String content;
 
    public Post(String title, String content) {
        this.title = title;
        this.content = content;
    }
    
    public String getTitle() {
        return title;
    }
    public String getContent() {
        return content;
    }
}
Output:
The length of the post content: 24

7. Function.identity()

Static method Function.identity(): Returns a function that always returns its input argument.
static <T> Function<T, T> identity() {
        return t -> t;
}
Example: Converts an array into a Set object containing non-duplicate elements.
FunctionEx8.java
package org.o7planning.ex;

import java.util.Arrays;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class FunctionEx8 {

    public static void main(String[] args) {

        String[] names = new String[] { //
                "Peter", "Martin", "John", "Peter", //
                "Vijay", "Martin", "Peter", "Arthur" };
        
        Set<String> set = Arrays.asList(names).stream() //
                .map(Function.identity()).collect(Collectors.toSet());
        
        set.forEach(System.out::println);
    }
}
Output:
Vijay
Arthur
John
Martin
Peter
The above example is equivalent to the below example:
FunctionEx8a.java
package org.o7planning.ex;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

public class FunctionEx8a {

    public static void main(String[] args) {  

        String[] names = new String[] { //
                "Peter", "Martin", "John", "Peter", //
                "Vijay", "Martin", "Peter", "Arthur" };
        
        Set<String> set = Arrays.asList(names).stream() //
                .map(t -> t).collect(Collectors.toSet());
        
        set.forEach(System.out::println);
    }
}

Java Basic

Show More