Design Pattern Iterator là một trong những mẫu thiết kế thuộc nhóm Behavioral Patterns trong Java. Mục đích chính của nó là cung cấp một cách để truy cập tuần tự các phần tử trong một tập hợp (collection) mà không để lộ ra cấu trúc bên trong của tập hợp đó.
Iterator Pattern là gì?
Iterator pattern cung cấp một giao diện chuẩn để duyệt qua các phần tử của một tập hợp (collection), như List, Set, Map,..
. mà không cần biết cấu trúc cụ thể của chúng.
Cấu trúc cơ bản:
- Iterator: Interface định nghĩa các phương thức như hasNext(), next().
- ConcreteIterator: Cài đặt cụ thể của Iterator.
- Aggregate (Collection): Interface chứa phương thức để tạo Iterator.
- ConcreteAggregate: Tập hợp cụ thể triển khai Aggregate.
Coi như chưa biết các tích hợp sẵn trong java và xây dựng lại từ đầu
// Tạo giao diện Iterator
public interface MyIterator<T> { boolean hasNext(); T next();
} // Tạo giao diện Iterable (tập hợp)
public interface MyIterable<T> { MyIterator<T> iterator();
}
Thiết lập danh sách học sih
import java.util.List; public class StudentCollection implements MyIterable<String> { private List<String> students; public StudentCollection(List<String> students) { this.students = students; } @Override public MyIterator<String> iterator() { return new StudentIterator(); } private class StudentIterator implements MyIterator<String> { private int index = 0; @Override public boolean hasNext() { return index < students.size(); } @Override public String next() { return students.get(index++); } }
}
Sử dụng Iterator
import java.util.Arrays; public class Main { public static void main(String[] args) { StudentCollection students = new StudentCollection( Arrays.asList("Alice", "Bob", "Charlie") ); MyIterator<String> iterator = students.iterator(); while (iterator.hasNext()) { String student = iterator.next(); System.out.println(student); } }
} // Kết quả:
Alice
Bob
Charlie
Trong Java, java.util.Iterator chính là sự hiện thực của pattern này.
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Charlie"); Iterator<String> iterator = names.iterator(); while (iterator.hasNext()) { String name = iterator.next(); System.out.println(name);
}
Ở đây, ta không cần quan tâm đến cách danh sách được lưu trữ nội bộ (mảng, cây, ...), chỉ cần biết cách lấy phần tử tiếp theo.
Áp dụng thực tế trong Spring Boot
Trong Spring Boot, Iterator
pattern được áp dụng rất nhiều — bạn có thể không nhận ra vì nó được ẩn sau các abstraction như Iterable, Stream, Page,...
1. Iterable trong Repository
Các interface như CrudRepository
hoặc JpaRepository
của Spring Data kế thừa từ Iterable< T >:
public interface UserRepository extends CrudRepository<User, Long> {} @Autowired
private UserRepository userRepository; public void printAllUsers() { for (User user : userRepository.findAll()) { System.out.println(user.getName()); }
}
findAll() trả về Iterable< T > → bạn có thể dùng for-each
hoặc Iterator
.
2. Pagination trong Spring Data
Page<User> page = userRepository.findAll(PageRequest.of(0, 10));
for (User user : page) { // Iterator được dùng ngầm System.out.println(user.getEmail());
}
Ở đây Page
implement Iterable
, nên bạn có thể dùng vòng lặp for-each
, hoặc .iterator().
3. Custom Iterable Class
Bạn cũng có thể định nghĩa class của riêng mình để implement Iterable< T >:
public class CustomUserList implements Iterable<User> { private List<User> users; public CustomUserList(List<User> users) { this.users = users; } @Override public Iterator<User> iterator() { return users.iterator(); }
} // Sử dụng:
CustomUserList customUsers = new CustomUserList(userList);
for (User user : customUsers) { // xử lý user
}
Thật ra viết bài này đối với Java mình thấy cũng hơi thừa vì giờ có các lib sẵn rồi, thực chất pattern này cũng chỉ là duyệt tuần tự các phần tử của 1 mảng nào đó.
Stream API
Các bạn có thể tìm hiểu thêm trong Java 8+ trở lên sử dụng trong Stream API nhé (Cách hiện đại thay cho Iterator)
list.stream() .filter(x -> x.startsWith("A")) .map(String::toUpperCase) .forEach(System.out::println);
Đây là cách hiện đại và declarative để duyệt, lọc, xử lý dữ liệu — thay thế hoàn toàn cho Iterator trong phần lớn use case.
Spliterator (Java 8)
Là sự nâng cấp của Iterator hỗ trợ duyệt song song (parallel) tốt hơn.
Dùng trong Stream.parallelStream().
Spliterator<String> split = list.spliterator();
split.forEachRemaining(System.out::println);
ListIterator (Iterator hai chiều cho List)
Cho phép duyệt tiến & lùi trong List.
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) { System.out.println(lit.next());
}
while (lit.hasPrevious()) { System.out.println(lit.previous());
}
Map và Iterator
Map
không trực tiếp implement Iterator
, nhưng bạn có thể lặp qua entry set:
Map<String, String> map = new HashMap<>();
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); System.out.println(entry.getKey() + " = " + entry.getValue());
}
Giờ dùng cái nào là hiện đại nhất?
Dùng Stream API (Java 8+) trong hầu hết các trường hợp!
Ví dụ thay vì:
// Cách viết: Imperative (chỉ định cách làm)
for (String item : list) { if (item.startsWith("A")) { System.out.println(item); }
}
Hãy viết:
// Cách viết: Declarative (chỉ định mục tiêu)
list.stream() .filter(s -> s.startsWith("A")) .forEach(System.out::println);