สัญญาของ Iterable และ Iterator
ทำความเข้าใจอินเทอร์เฟซ Iterable และ Iterator รวมถึงวิธีทำงานภายในของลูป for-each
สัญญาของ Iterable และ Iterator เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
Iterable และ Iterator
Iterable<T> และ Iterator<T> คืออินเทอร์เฟซที่ขับเคลื่อนลูปวนซ้ำสมาชิกของ Java การทำความเข้าใจทั้งสองแบบช่วยให้คุณสร้างโครงสร้างข้อมูลของตนเองที่ใช้กับลูปวนซ้ำสมาชิกได้
อินเทอร์เฟซ Iterable
Iterable<T> มีหนึ่งเมธอดคือ iterator() ซึ่งคืนค่าเป็น Iterator<T> คลาสใดก็ตามที่นำ Iterable ไปใช้สามารถใช้กับลูปวนซ้ำสมาชิกได้
// java.lang.Iterable<T>
interface Iterable<T> {
Iterator<T> iterator();
// default: forEach, spliterator (Java 8+)
}
// Any class implementing Iterable<T> works in for-each:
class Range implements Iterable<Integer> {
private final int start, end;
Range(int start, int end) { this.start = start; this.end = end; }
public Iterator<Integer> iterator() {
return new RangeIterator(); // defined separately
}
}อินเทอร์เฟซ Iterator
Iterator<T> มีสามเมธอด ได้แก่ hasNext(), next() และ remove() ซึ่งเป็นเมธอดทางเลือก
// java.util.Iterator<T>
interface Iterator<T> {
boolean hasNext(); // true if more elements
T next(); // returns next element, advances cursor
default void remove() { throw new UnsupportedOperationException(); }
}
// How for-each desugars internally:
// for (T item : iterable) { use(item); }
// becomes:
Iterator<T> it = iterable.iterator();
while (it.hasNext()) {
T item = it.next();
// use(item)
}การคลี่รูปของลูปวนซ้ำสมาชิก
ลูปวนซ้ำสมาชิกเป็นเพียงรูปแบบไวยากรณ์ย่อของรูปแบบ Iterable/Iterator การทำความเข้าใจเรื่องนี้ช่วยให้คุณเขียน Iterable แบบกำหนดเองได้อย่างถูกต้อง
List<String> names = List.of("Alice", "Bob", "Charlie");
// For-each (readable way)
for (String name : names) {
System.out.println(name);
}
// Equivalent explicit form
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
System.out.println(name);
}สถานะตัวชี้ตำแหน่งของ Iterator
Iterator รักษาตัวชี้ตำแหน่ง ซึ่งเป็นตำแหน่งหนึ่งในลำดับ การเรียก next() จะเลื่อนตัวชี้ตำแหน่งไปข้างหน้า เมื่ออ่านครบแล้ว ตัววนซ้ำจะไม่สามารถเริ่มต้นใหม่ได้
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> it = nums.iterator();
System.out.println(it.hasNext()); // true
System.out.println(it.next()); // 1
System.out.println(it.next()); // 2
System.out.println(it.next()); // 3
System.out.println(it.hasNext()); // false
try {
it.next(); // NoSuchElementException
} catch (java.util.NoSuchElementException e) {
System.out.println("No more elements!");
}ConcurrentModificationException
การแก้ไขคอลเลกชันขณะวนซ้ำด้วยตัววนซ้ำที่เรียกใช้อย่างชัดแจ้ง โดยไม่ใช้ Iterator.remove() จะทำให้เกิด ConcurrentModificationException
List<String> list = new ArrayList<>(List.of("a", "b", "c", "d"));
// BAD: modifying collection during for-each
try {
for (String s : list) {
if ("b".equals(s)) list.remove(s); // ConcurrentModificationException!
}
} catch (java.util.ConcurrentModificationException e) {
System.out.println("Cannot modify during iteration!");
}
// GOOD: use Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("b".equals(it.next())) it.remove(); // safe
}
System.out.println(list); // [a, c, d]Iterator หลายตัว
การเรียก iterator() แต่ละครั้งจะคืนค่าตัววนซ้ำใหม่ที่เป็นอิสระต่อกัน ตัววนซ้ำหลายตัวสามารถทำงานพร้อมกันกับคอลเลกชันเดียวกันได้
List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> a = nums.iterator();
Iterator<Integer> b = nums.iterator();
System.out.println(a.next()); // 1
System.out.println(b.next()); // 1 (independent cursor)
System.out.println(a.next()); // 2
System.out.println(b.next()); // 2Iterable กับ Iterator
ความแตกต่างสำคัญ:
- Iterable: แหล่งข้อมูลที่สร้างตัววนซ้ำได้ และสามารถวนซ้ำได้หลายครั้ง
- Iterator: ตัวชี้ตำแหน่งเหนือลำดับ ใช้ได้ครั้งเดียวและมีสถานะ
// Iterable: reusable
List<String> list = List.of("x", "y");
for (String s : list) {} // OK
for (String s : list) {} // OK again — new iterator each time
// Iterator: single-use
Iterator<String> it = list.iterator();
while (it.hasNext()) it.next();
// for (String s : it) {} // compile error — Iterator is not Iterable!เชิงปฏิบัติ: Iterable สำหรับบรรทัดในไฟล์แบบกำหนดเอง
ตัวอ่านไฟล์ที่นำ Iterable ไปใช้ เพื่อให้สามารถใช้ลูปวนซ้ำสมาชิกกับบรรทัดต่าง ๆ ในไฟล์ได้
import java.io.*;
import java.util.*;
class FileLines implements Iterable<String>, Closeable {
private final BufferedReader reader;
FileLines(String path) throws IOException {
this.reader = new BufferedReader(new FileReader(path));
}
public Iterator<String> iterator() {
return new Iterator<>() {
private String nextLine = readNext();
private String readNext() {
try { return reader.readLine(); }
catch (IOException e) { return null; }
}
public boolean hasNext() { return nextLine != null; }
public String next() {
String curr = nextLine;
nextLine = readNext();
return curr;
}
};
}
public void close() throws IOException { reader.close(); }
}เมธอดเริ่มต้น forEach
Java 8 เพิ่มเมธอดเริ่มต้น forEach(Consumer) ให้กับ Iterable ซึ่งเป็นทางเลือกที่สะดวกแทนการเขียนลูปอย่างชัดแจ้ง
List<String> cities = List.of("New York", "London", "Tokyo");
// for-each loop
for (String city : cities) System.out.println(city);
// forEach with lambda
cities.forEach(city -> System.out.println(city));
// forEach with method reference (most concise)
cities.forEach(System.out::println);
// For transforming: use stream
cities.stream()
.map(String::toUpperCase)
.forEach(System.out::println);รูปแบบ Iterator ในการใช้งานจริง
สรุปกรณีที่ควรนำ Iterable/Iterator ไปใช้:
- โครงสร้างข้อมูลแบบกำหนดเอง เช่น ต้นไม้, Graph และรายการเชื่อมโยง
- ลำดับแบบประเมินค่าเมื่อจำเป็น ซึ่งสร้างสมาชิกตามคำขอ
- ลำดับที่อิงทรัพยากร เช่น บรรทัดในไฟล์ ตัวชี้ตำแหน่งฐานข้อมูล และคิวข้อความ
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ข้อยกเว้นใดจะเกิดขึ้นเมื่อแก้ไขคอลเลกชันขณะวนซ้ำด้วยลูปวนซ้ำสมาชิก
ทบทวน: ข้อกำหนดของ Iterable และ Iterator
ประเด็นสำคัญ:
- Iterable
มีหนึ่งเมธอดคือ iterator() ซึ่งทำให้รองรับลูปวนซ้ำสมาชิก - Iterator
มี hasNext(), next() และ remove() ซึ่งเป็นทางเลือก - ลูปวนซ้ำสมาชิกเป็นรูปแบบไวยากรณ์ย่อของรูปแบบ Iterable/Iterator
- เรียก iterator() หลายครั้งเพื่อรับตัวชี้ตำแหน่งใหม่ที่เป็นอิสระต่อกัน
- อย่าแก้ไขคอลเลกชันระหว่างลูปวนซ้ำสมาชิก ให้ใช้ Iterator.remove() แทน
- นำ Iterable ไปใช้กับโครงสร้างข้อมูลแบบกำหนดเองเพื่อรองรับลูปวนซ้ำสมาชิก
คำถามที่พบบ่อย
บทเรียน “สัญญาของ Iterable และ Iterator” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “สัญญาของ Iterable และ Iterator” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “สัญญาของ Iterable และ Iterator”
ทำความเข้าใจอินเทอร์เฟซ Iterable และ Iterator รวมถึงวิธีทำงานภายในของลูป for-each คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “สัญญาของ Iterable และ Iterator” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- สัญญาของ Iterable และ Iterator
- การสร้าง Iterator แบบกำหนดเอง
- ListIterator และการวนดูแบบสองทิศทาง
- Iterator แบบหยุดเร็วกับแบบปลอดภัย