0

[Java Backend Zero to Hello] BÀI 2.2: LAMBDA EXPRESSION

Java Backend Zero to Hello

📚 Bài viết thuộc series Java Backend Zero to Hello 📌 Phần: Phase 2: Java Core Nâng Cao | Bài 17/86


BÀI 2.2: LAMBDA EXPRESSION

Mục tiêu

  • Hiểu Functional Interface
  • Viết Lambda Expression
  • Sử dụng Method Reference
  • Áp dụng vào Collection và Stream

1. FUNCTIONAL INTERFACE

Interface chỉ có đúng 1 abstract method (có thể có default/static).

@FunctionalInterface
public interface Calculator {
    int calculate(int a, int b);
}

Các Functional Interface phổ biến trong java.util.function

Interface Method Mô tả
Runnable void run() Không tham số, không trả về
Supplier<T> T get() Không tham số, trả về T
Consumer<T> void accept(T t) Có tham số, không trả về
Function<T,R> R apply(T t) T → R
BiFunction<T,U,R> R apply(T t, U u) (T, U) → R
Predicate<T> boolean test(T t) T → boolean
BiPredicate<T,U> boolean test(T t, U u) (T, U) → boolean
UnaryOperator<T> T apply(T t) T → T
BinaryOperator<T> T apply(T t, T u) (T, T) → T

2. LAMBDA EXPRESSION

Lambda là cách viết ngắn gọn cho implementation của Functional Interface.

2.1 Cú pháp

(parameters) -> { body }

2.2 Ví dụ cơ bản

// Không tham số
Runnable r1 = () -> System.out.println("Hello");
r1.run();

// 1 tham số
Consumer<String> c1 = (s) -> System.out.println(s);
Consumer<String> c2 = s -> System.out.println(s);  // Bỏ ngoặc đơn

// Nhiều tham số
Comparator<Integer> cmp = (a, b) -> Integer.compare(a, b);

// Body đơn giản - không cần return và {}
Function<Integer, Integer> square = x -> x * x;

// Body phức tạp - cần {} và return
Function<Integer, Integer> factorial = n -> {
    int result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
};

2.3 So sánh với Anonymous Class

// Anonymous class - dài dòng
Runnable r1 = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello");
    }
};

// Lambda - ngắn gọn
Runnable r2 = () -> System.out.println("Hello");

3. METHOD REFERENCE

Cú pháp ngắn hơn nữa khi lambda chỉ gọi một method có sẵn.

3.1 Các loại Method Reference

Loại Cú pháp Ví dụ
Static method Class::staticMethod Math::max
Instance method (object cụ thể) instance::method System.out::println
Instance method (kiểu) Class::instanceMethod String::length
Constructor Class::new ArrayList::new

3.2 Ví dụ

// Static method
Function<Integer, Integer> abs = Math::abs;
abs.apply(-5);  // 5

// Instance method - object cụ thể
Consumer<String> printer = System.out::println;
printer.accept("Hello");

// Instance method - kiểu
Function<String, Integer> length = String::length;
length.apply("Hello");  // 5

// Constructor
Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> list = listSupplier.get();

3.3 So sánh Lambda vs Method Reference

// Lambda
Function<String, Integer> len1 = s -> s.length();

// Method Reference
Function<String, Integer> len2 = String::length;

4. SỬ DỤNG VỚI COLLECTION

4.1 forEach

List<String> names = Arrays.asList("An", "Bình", "Châu");

// forEach + Lambda
names.forEach(name -> System.out.println(name));

// forEach + Method Reference
names.forEach(System.out::println);

4.2 sort với Comparator

List<String> names = Arrays.asList("Châu", "An", "Bình");

// Lambda
names.sort((a, b) -> a.compareTo(b));

// Method Reference
names.sort(String::compareTo);

4.3 removeIf

List<Integer> numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6));
numbers.removeIf(n -> n % 2 == 0);  // [1, 3, 5]

5. SỬ DỤNG VỚI MAP

Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);

// forEach
map.forEach((k, v) -> System.out.println(k + " = " + v));

// compute
map.compute("A", (k, v) -> v == null ? 0 : v * 2);  // A = 2

// merge
map.merge("A", 10, Integer::sum);  // A = 12

// replaceAll
map.replaceAll((k, v) -> v * 10);  // A=20, B=20, C=30

6. CUSTOM FUNCTIONAL INTERFACE

@FunctionalInterface
public interface Validator<T> {
    boolean validate(T value);

    default Validator<T> and(Validator<T> other) {
        return value -> this.validate(value) && other.validate(value);
    }

    default Validator<T> or(Validator<T> other) {
        return value -> this.validate(value) || other.validate(value);
    }
}

// Sử dụng
Validator<String> notNull = s -> s != null;
Validator<String> notEmpty = s -> !s.isEmpty();
Validator<String> validator = notNull.and(notEmpty);

boolean valid = validator.validate("Hello");  // true

7. VARIABLE CAPTURE

Lambda có thể truy cập biến bên ngoài nhưng phải là effectively final.

int multiplier = 3;
Function<Integer, Integer> multiply = n -> n * multiplier;  // OK

// multiplier = 5;  // ❌ Lambda đã capture multiplier, không thể thay đổi

8. BÀI TẬP THỰC HÀNH

Bài 1: Sử dụng các Functional Interface

// Supplier - tạo UUID
Supplier<String> uuidSupplier = () -> UUID.randomUUID().toString();
String id = uuidSupplier.get();

// Consumer - in thông tin
Consumer<User> printUser = user -> System.out.println(user.getName());

// Function - chuyển User thành String
Function<User, String> getName = User::getName;

// Predicate - kiểm tra
Predicate<Integer> isEven = n -> n % 2 == 0;

Bài 2: Sort danh sách

List<User> users = getUsers();
users.sort(Comparator.comparing(User::getName));
users.sort(Comparator.comparingInt(User::getAge).reversed());

Bài 3: Filter và Transform

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

List<Integer> evenSquares = numbers.stream()
    .filter(n -> n % 2 == 0)
    .map(n -> n * n)
    .collect(Collectors.toList());
// [4, 16, 36, 64, 100]

Bài 4: Custom Validator

Tạo Validator<User> kiểm tra email hợp lệ, tuổi >= 18.


9. TÓM TẮT

Khái niệm Cú pháp Mục đích
Functional Interface Interface 1 abstract method Nền tảng cho Lambda
Lambda (params) -> body Viết ngắn gọn implementation
Method Reference Class::method Ngắn hơn Lambda
Consumer void accept(T) Xử lý, không trả về
Supplier T get() Cung cấp giá trị
Function R apply(T) Biến đổi
Predicate boolean test(T) Kiểm tra điều kiện

Bài tiếp theo: 2.3 Stream API


🧭 Điều Hướng Series

⬅️ Bài trước: BÀI 2.1: GENERIC

📋 Lộ trình tổng quan: Xem Toàn Bộ Series

➡️ Bài tiếp theo: BÀI 2.3: STREAM API


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí