devstory

Le Tutoriel de Java Function

View more Tutorials:

Site d'apprentissage des langues gratuit:
Suivez-nous sur notre fanpage pour recevoir des notifications chaque fois qu'il y a de nouveaux articles. Facebook

1- Function interface

Dans Java 8, Function est une functional interface, laquelle représente un opérateur qui accepte une valeur d'entrée et renvoie une autre.
Le code source de l'interface Function:
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;
    }
}
Par exemple:
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
Exemple: Le traitement des éléments d'un objet List pour créer un nouvel objet List.
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
Exemple: L'utilisation de Function pour convertir un objet List en objet Map:
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:
Si une méthode statique prend un seul paramètre et renvoie une valeur, sa référence peut être considérée comme une 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:
Si une méthode n'est pas statique (méthode non statique), ne prend aucun paramètre et renvoie une valeur, sa référence peut être considérée comme une 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:
Ensuite, observer la classe CurrencyFormatter ci-dessous:
  • La méthode CurrencyFormatter.usd(double) a un paramètre de type Double et renvoie une chaîne. Ainsi, sa référence CurrencyFormatter::usd peut être considérée comme 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

Comme vous le savez, un constructeur est utilisé pour créer un objet, ce qui signifie qu'il renvoie une valeur. Donc, si le constructeur a un seul paramètre, sa référence sera considérée comme une 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

Ci-dessous une liste de méthodes dans le package java.util utilisant l'interface Function:
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)
Voir plus:

5- Function.compose(Function before)

Ci-dessous la définition de la méthode Function.compose:

@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 ..
}
Et on réécrit cette méthode de manière plus facile à comprendre:

@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 ..
}
Par exemple:
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)

Ci-dessous la définition de la méthode Function.andThen:

@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 ..
}
Et on réécrit cette méthode de manière plus facile à comprendre:

@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 ..
}
Exemple:
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()

Méthode statique Function.identity(): renvoie une fonction qui renvoie toujours son argument d'entrée.

static <T> Function<T, T> identity() {
        return t -> t;
}
Exemple: Convertir un tableau en un objet Set contenant des éléments non dupliqués.
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
L'exemple ci-dessus est l'équivalent de l'exemple suivant:
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);
    }
}

View more Tutorials: