Consumer trong Java 8

1. Giới thiệu Consumer<T>

Trong Java 8, Consumer<T> là một functional interface và do đó nó có thể được sử dụng với lambda expression hoặc method reference cho một mục đích cụ thể nào đó. Consumer<T> chấp nhận một tham số đầu vào, và method này không trả về gì cả.

Mục tiêu chính của Interface Consumer là thực hiện một thao tác trên đối số đã cho.

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

Trong đó:

  • void accept(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 accept() thực hiện một hành động cụ thể trên đối số đã cho.

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

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

2. Một số ví dụ

2.1. Tạo consumer

package com.maixuanviet.consumer;
 
import java.util.function.Consumer;
 
public class ConsumerExample1 {
 
    static void printValue(int val) {
        System.out.println(val);
    }
 
    public static void main(String[] args) {
        // Create Consumer interface
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String name) {
                System.out.println("Hello, " + name);
            }
        };
        // Calling Consumer method
        consumer.accept("maixuanviet"); // Hello, maixuanviet
 
        // Create Consumer interface with lambda expression
        Consumer<String> consumer1 = (name) -> System.out.println("Hello, " + name);
        // Calling Consumer method
        consumer1.accept("maixuanviet"); // Hello, maixuanviet
 
        // Create Consumer interface with method reference
        Consumer<Integer> consumer2 = ConsumerExample1::printValue;
        // Calling Consumer method
        consumer2.accept(12); // 12
    }
}

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

  • consumer1 : được tạo bằng cách sử dụng lambda expression.
  • consumer2 : được tạo bằng cách sử dụng method reference.

Để thực thi consumer, chúng ta gọi phương thức mặc định accept() được cung cấp trong Interface Consumer. Phương thức này sẽ thực thi đoạn code được cài đặt thông qua lambda expression hoặc method reference.

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

package com.maixuanviet.consumer;
 
import java.util.function.Consumer;
 
public class ConsumerAndThenExample {
 
    public static final int TEST_NUMBER = 5;
 
    public static void main(String[] args) {
        Consumer<Integer> times2 = (e) -> System.out.println(e * 2);
        Consumer<Integer> squared = (e) -> System.out.println(e * e);
        Consumer<Integer> isOdd = (e) -> System.out.println(e % 2 == 1);
 
        // perform every consumer
        times2.accept(TEST_NUMBER); // 10
        squared.accept(TEST_NUMBER); // 25
        isOdd.accept(TEST_NUMBER); // true
 
        // perform 3 methods in sequence
        Consumer<Integer> combineConsumer = times2.andThen(squared).andThen(isOdd);
        combineConsumer.accept(TEST_NUMBER); // 10 25 true
    }
}

Trong phương thức trên, tôi đã tạo 3 consumer. Thay vì gọi phương thức accept() lần lượt cho từng consumer, tôi đã kết hợp chúng thông qua phương thức mặc định andThen(), để thực thi tất cả các consumer đó, chúng ta chỉ việc gọi một combineConsumer duy nhất.

2.3. Sử dụng Consumer với forEach loop

Như chúng ta đã biết, phương thức foreach là một phương thức mặc định(default method) được định nghĩa trong interface Iterable và Stream. Các lớp Collection extends từ interface Iterable có thể sử dụng vòng lặp forEach() để duyệt các phần tử. Phương thức này chấp nhận một đối số đầu vào là Consumer. Do đó chúng ta có thể viết theo một trong các cách sau:

  • Tạo một consumer và truyền như đối số đầu vào.
  • Sử dụng trực tiếp Method referenece như đối số đầu vào.
  • Sử dụng trực tiếp Lambda expression như đối số đầu vào.
package com.maixuanviet.consumer;
 
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
 
class Programing {
    public String language;
    public int experience;
 
    public Programing(String language, int experience) {
        this.language = language;
        this.experience = experience;
    }
 
    public void print() {
        System.out.println("Language: " + language + " - Experience: " + experience);
    }
}
 
public class ConsumerExample2 {
 
    public static void main(String[] args) {
 
        List<Programing> list = new ArrayList<>();
        list.add(new Programing("Java", 5));
        list.add(new Programing("PHP", 2));
        list.add(new Programing("C#", 1));
 
        // Creating instance of Consumer functional interface
        Consumer<Programing> consumer = (p) -> System.out.println(
                "Name: " + p.language + " - Experience: " + p.experience);
 
        System.out.println("Using Consumer: ");
        list.forEach(consumer);
 
        System.out.println("\nUsing Method Reference: ");
        list.forEach(Programing::print);
 
        System.out.println("\nUsing Lambda Expression: ");
        list.forEach(s -> s.print());
    }
}

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

Using Consumer: 
Name: Java - Experience: 5
Name: PHP - Experience: 2
Name: C# - Experience: 1
 
Using Method Reference: 
Language: Java - Experience: 5
Language: PHP - Experience: 2
Language: C# - Experience: 1
 
Using Lambda Expression: 
Language: Java - Experience: 5
Language: PHP - Experience: 2
Language: C# - Experience: 1

2.4. Sử dụng Consumer 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 Consumer cho các wrapper class của kiểu dữ liệu nguyên thủy như sau:

  • IntConsumer : chấp nhận một giá trị kiểu Int duy nhất.
  • LongConsumer : chấp nhận một giá trị kiểu Long duy nhất.
  • DoubleConsumer : chấp nhận một giá trị kiểu Double duy nhất.
package com.maixuanviet.consumer;
 
import java.util.Arrays;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.LongConsumer;
 
public class ConsumerExample3 {
 
    public static void main(String[] args) {
 
        System.out.print("IntConsumer: ");
        int[] intNumbers = { 3, 5, 6, 2, 1 };
        IntConsumer intConsumer = i -> System.out.print(i + " ");
        Arrays.stream(intNumbers).forEach(intConsumer);
 
        System.out.print("\nLongConsumer: ");
        long[] longNumbers = { 3, 5, 6, 2, 1 };
        LongConsumer longConsumer = l -> System.out.print(l + " ");
        Arrays.stream(longNumbers).forEach(longConsumer);
 
        System.out.print("\nDoubleConsumer: ");
        double[] dbNumbers = { 3.2, 5.1, 6.3, 2.5, 1.0 };
        DoubleConsumer dbConsumer = d -> System.out.print(d + " ");
        Arrays.stream(dbNumbers).forEach(dbConsumer);
    }
}

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

IntConsumer: 3 5 6 2 1
LongConsumer: 3 5 6 2 1
DoubleConsumer: 3.2 5.1 6.3 2.5 1.0

2.5. Sử dụng Consumer 2 đối số với BiConsumer

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

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

Ví dụ:

package com.maixuanviet.consumer;
 
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;
 
public class BiConsumerExample {
 
    public static void main(String[] args) {
 
        Map<String, Integer> map = new HashMap<>();
        map.put("Java", 5);
        map.put("PHP", 2);
        map.put("C#", 1);
         
        BiConsumer<String, Integer> biConsumer = 
                (key, value) -> System.out.println("Key: " + key + " - Value: " + value);
        map.forEach(biConsumer);
    }
}

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

Key: C# - Value: 1
Key: Java - Value: 5
Key: PHP - Value: 2

Related posts:

Hướng dẫn Java Design Pattern – Composite
Java Program to Check Whether a Given Point is in a Given Polygon
Getting Started with Custom Deserialization in Jackson
Chuyển đổi Array sang ArrayList và ngược lại
JUnit5 Programmatic Extension Registration with @RegisterExtension
Dynamic Proxies in Java
A Guide to System.exit()
Guide to Java 8 groupingBy Collector
Java Program to Generate All Possible Subsets with Exactly k Elements in Each Subset
Java Program to Implement Rolling Hash
Java Program to Implement Circular Singly Linked List
Login For a Spring Web App – Error Handling and Localization
Java Program to Implement Double Ended Queue
Java Program to Find Nearest Neighbor for Static Data Set
Guide to the Synchronized Keyword in Java
HashSet trong java
Java Program to Find Nearest Neighbor Using Linear Search
Spring RestTemplate Error Handling
Spring Security Custom AuthenticationFailureHandler
Java Program to Create a Random Linear Extension for a DAG
New Features in Java 13
Java Program to Implement Gale Shapley Algorithm
Removing all duplicates from a List in Java
Java Program to Implement TreeMap API
Java Program to Check Cycle in a Graph using Topological Sort
Java Program to Check the Connectivity of Graph Using DFS
Tạo ứng dụng Java RESTful Client với thư viện OkHttp
Java Program to Implement Min Heap
Java Program to Show the Duality Transformation of Line and Point
Java Program to Implement the Schonhage-Strassen Algorithm for Multiplication of Two Numbers
HashSet trong Java hoạt động như thế nào?
Bootstrap a Web Application with Spring 5