Function trong Java 8

1. Giới thiệu Function<T, R>

Java 8 cung cấp sẵn cho chúng ta rất nhiều Functional Interface và Function<T, R> là một trong số đó. Cũng giống như những functional interface khác, Function<T, R> có thể sử dụng cho lambda expression hoặc method reference cho một mục đích cụ thể nào đó. Function<T,R> chỉ có một method trừu tượng duy nhất chấp nhận một tham số đầu vào, và method trả về một đối tượng khác.

Mục đích chính của Function là giúp chúng ta dễ dàng chuyển một đối tượng từ kiểu dữ liệu này sang kiểu dữ liệu khác.

Interface Function được khai báo trong package java.util.function như sau:

Trong đó:

  • R apply(T t) : là một phương thức trừu tượng có thể được sử dụng với lambda expression hoặc method reference cho một mục đích cụ thể nào đó.
  • Phương thức apply() thực hiện một hành động cụ thể trên đối số đã cho và trả về một đối khác.

Interface Function còn cung cấp một phương thức mặc định (default method) sau:

  • Function<V, R> compose(Function<? super V, ? extends T> before) : phương thức này trả về một function gộp mà nó đã áp dụng before Function lên đối số đầu vào, sau đó áp dụng function lên dữ liệu đầu ra.
  • Function<T, V> andThen(Function<? super R, ? extends V> after) : phương thức này trả về một Function gộp mà nó đã áp dụng function lên dữ liệu đầu vào và sau đó áp dụng tiếp after function lên kết quả đầu ra.
  • Function<T, T> identity() : phương thức này trả về một function luôn trả về đối số đầu vào của nó.

2. Một số ví dụ

2.1. Sử dụng R apply(T t)

package com.maixuanviet.function;
 
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.function.Function;
 
public class FunctionExample1 {
 
    public static void main(String[] args) {
 
        Function<String, Integer> numberConverter = (str) -> Integer.parseInt(str);
        System.out.println(numberConverter.apply("1")); // 1
 
        Function<LocalDate, String> dateConverter = (d) -> d.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
        System.out.println(dateConverter.apply(LocalDate.now())); // 27/05/2018
    }
}

Trong ví dụ trên tôi đã tạo 2 Function:

  • Function numberConverter : chấp nhận đối số đầu vào là một chuỗi (String), kết quả đầu ra là một số (Integer).
  • Function dateConverter : chấp nhận đối số đầu vào là một LocalDate, kết quả đầu ra là một chuỗi (String) của Date đã được format.

Để nhận được kết quả của Function, chúng ta cần gọi phương thức apply().

2.2. Chuyển một đối tượng này sang một đối tượng khác (object to object)

package com.maixuanviet.function;
 
import java.util.function.Function;
 
class User {
    String name;
    String email;
    String password;
 
    public User(String name, String email, String password) {
        this.name = name;
        this.email = email;
        this.password = password;
    }
}
 
class Member {
    String name;
    String email;
 
    public Member(String name, String email) {
        this.name = name;
        this.email = email;
    }
 
    @Override
    public String toString() {
        return "Member [name=" + name + ", email=" + email + "]";
    }
}
 
public class FunctionExample2 {
 
    public static void main(String[] args) {
 
        Function<User, Member> mapUserToMember = u -> new Member(u.name, u.email);
 
        User user = new User("maixuanviet", "maixuanvietvn@gmail.com", "123");
        Member member = mapUserToMember.apply(user);
        System.out.println(member);
    }
}

Output của chương trình trên:

Member [name=VietMX, email=maixuanviet.com@gmail.com]

2.3. Chuyển một danh sách đối tượng này sang một danh sách đối tượng khác (list object to list object)

package com.maixuanviet.function;
 
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
 
public class FunctionExample3 {
 
    public static void main(String[] args) {
         
        List<User> users = Arrays.asList( // 
            new User("maixuanviet1", "maixuanvietvn1@gmail.com", "123"), // 
            new User("maixuanviet2", "maixuanvietvn2@gmail.com", "124"), // 
            new User("maixuanviet3", "maixuanvietvn3@gmail.com", "125") //  
        );
 
        Function<User, Member> mapUserToMember = u -> new Member(u.name, u.email);
 
        List<Member> members = users.stream()
                .map(mapUserToMember)
                .collect(Collectors.toList());
    }
}

2.4. Sử dụng phương thức mặc định andThen() và compose()

Phương thức andThen() : phương thức này trả về một Function thực hiện hai hành động theo thứ tự, trước tiên là hành động của Function mà phương thức được gọi và theo sau bởi hành động của Function được truyền vào đối số.

Phương thức compose() : phương thức này trả về một Function thực hiện hai hành động theo thứ tự, trước tiên là hành động của Function mà được truyền vào đối số và theo sau bởi hành động của Function gọi phương thức.

Phương thức identity() : phương thức này trả về một Function thực hiện trả về kết quả đúng bằng với đối số được truyền vào.

@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;
    }
}

Ví dụ:

package com.maixuanviet.function;
 
import java.util.function.Function;
 
public class FunctionExample4 {
 
    public static void main(String[] args) {
 
        Function<Integer, Integer> times2 = n -> n * 2;
        Function<Integer, Integer> squared = n -> n * n;
 
        Function<Integer, Integer> andThen = times2.andThen(squared);
        System.out.println("Using andThen: " + andThen.apply(5)); // 100
 
        Function<Integer, Integer> compose = times2.compose(squared);
        System.out.println("Using compose: " + compose.apply(5)); // 50
    }
}

2.5. Sử dụng Function với các lớp cho kiểu dữ liệu nguyên thủy (primitive type)

Java 8 cung cấp một số Interface Function cho các wrapper class của kiểu dữ liệu nguyên thủy như sau:

  • IntFunction : chấp nhận một đối số đầu vào kiểu int và kết quả đầu ra là kiểu bất kỳ.
  • LongFunction : chấp nhận một đối số đầu vào kiểu long và kết quả đầu ra là kiểu bất kỳ.
  • DoubleFunction : chấp nhận một đối số đầu vào kiểu double và kết quả đầu ra là kiểu bất kỳ.
@FunctionalInterface
public interface IntFunction<R> {
    R apply(int value);
}
 
@FunctionalInterface
public interface LongFunction<R> {
    R apply(long value);
}
 
@FunctionalInterface
public interface DoubleFunction<R> {
    R apply(double value);
}

Ví dụ:

package com.maixuanviet.function;
 
import java.util.function.DoubleFunction;
import java.util.function.IntFunction;
import java.util.function.LongFunction;
 
public class FunctionExample5 {
 
    public static void main(String[] args) {
 
        IntFunction<String> ifunc = (x) -> Integer.toString(x * x);
        LongFunction<String> lfunc = (x) -> Long.toString(x * x);
        DoubleFunction<String> dfunc = (x) -> Double.toString(x * x);
 
        System.out.println(ifunc.apply(3)); // 9
        System.out.println(lfunc.apply(5)); // 25
        System.out.println(dfunc.apply(10)); // 100.0
    }
}

2.6. Sử dụng Function 2 đối số với BiFunction

Như đã nói ở phần trên Function chỉ chấp nhận 1 đối số đầu vào, để có thể sử dụng Function với 2 đối số đầu vào chúng ta sử dụng Interface BiFunction.

Về cơ bản, interface BiFunction  không khác biệt so với Function , ngoại trừ nó chấp nhận 2 đối số đầu vào.

Ví dụ:

package com.maixuanviet.function;
 
import java.util.function.BiFunction;
import java.util.function.Function;
 
public class BiFunctionExample {
 
    public static void main(String[] args) {
 
        BiFunction<String, String, String> function1 = (s1, s2) -> s1 + s2;
        System.out.println(function1.apply("maixuanviet", ".com")); // maixuanviet.com
 
        BiFunction<Integer, Integer, Integer> function2 = (a, b) -> a + b;
        System.out.println(function2.apply(1, 2)); // 3
 
        BiFunction<Integer, Integer, Integer> times2 = (a, b) -> a + b;
        Function<Integer, Integer> squared = (n) -> n * n;
 
        BiFunction<Integer, Integer, Integer> andThen = times2.andThen(squared);
        System.out.println("Using andThen: " + andThen.apply(5, 2)); // 49
    }
}

Related posts:

Java Program to Represent Graph Using Adjacency List
Comparing Two HashMaps in Java
Java Program to Find the Minimum Element of a Rotated Sorted Array using Binary Search approach
The Registration Process With Spring Security
How to Read HTTP Headers in Spring REST Controllers
Comparing Strings in Java
Java Program to Find k Numbers Closest to Median of S, Where S is a Set of n Numbers
Spring AMQP in Reactive Applications
Java Program to implement Bit Set
Assertions in JUnit 4 and JUnit 5
Java Program to Solve the Fractional Knapsack Problem
Introduction to Liquibase Rollback
Java Program to Perform Complex Number Multiplication
Java Program to Check if an UnDirected Graph is a Tree or Not Using DFS
Java Program to Implement RoleUnresolvedList API
Mapping a Dynamic JSON Object with Jackson
Spring Security Registration – Resend Verification Email
Using Java Assertions
The HttpMediaTypeNotAcceptableException in Spring MVC
A Comparison Between Spring and Spring Boot
Java CyclicBarrier vs CountDownLatch
Java Program to Check if a Matrix is Invertible
Validate email address exists or not by Java Code
Java Program to Perform Cryptography Using Transposition Technique
Java – Write an InputStream to a File
Giới thiệu Google Guice – Dependency injection (DI) framework
Sử dụng JDBC API thực thi câu lệnh truy vấn dữ liệu
Spring Cloud AWS – RDS
Spring’s RequestBody and ResponseBody Annotations
Converting Strings to Enums in Java
Java Program to Find Whether a Path Exists Between 2 Given Nodes
Toán tử trong java

2 Trackbacks / Pingbacks

  1. Sắp xếp trong Java 8 - Blog của VietMX
  2. Refactoring Design Pattern với tính năng mới trong Java 8 - Blog của VietMX

Comments are closed.