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:

Java Program to Check if a Point d lies Inside or Outside a Circle Defined by Points a, b, c in a Pl...
Spring REST API + OAuth2 + Angular (using the Spring Security OAuth legacy stack)
HttpClient 4 – Send Custom Cookie
Java Program to Implement Gabow Algorithm
A Guide to Java HashMap
Java List UnsupportedOperationException
Java Program to Solve the 0-1 Knapsack Problem
Simple Single Sign-On with Spring Security OAuth2
Apache Commons Collections SetUtils
Java Program to Implement Suffix Tree
Java Program to Create the Prufer Code for a Tree
Java Program to Implement Min Heap
Java Program to Generate Random Hexadecimal Byte
Check If Two Lists are Equal in Java
Java Program to Test Using DFS Whether a Directed Graph is Strongly Connected or Not
Java Program to Perform Inorder Recursive Traversal of a Given Binary Tree
Java Program to Implement the MD5 Algorithm
Different Ways to Capture Java Heap Dumps
StringBuilder vs StringBuffer in Java
Adding Shutdown Hooks for JVM Applications
Summing Numbers with Java Streams
Java Program to Find Whether a Path Exists Between 2 Given Nodes
Java Program to Implement Circular Singly Linked List
HttpClient Timeout
Java Program to add two large numbers using Linked List
Hướng dẫn Java Design Pattern – Template Method
How to Find an Element in a List with Java
Java Program to Implement ConcurrentHashMap API
Java Program to Check for balanced parenthesis by using Stacks
Spring Security Remember Me
Creating a Custom Starter with Spring Boot
Java Program to Permute All Letters of an Input String