[Java Backend Zero to Hello] BÀI 2.2: LAMBDA EXPRESSION
📚 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