0Pricing
Java Academy · บทเรียน

การสร้าง Iterator แบบกำหนดเอง

สร้างคลาส iterator แบบกำหนดเองสำหรับรายการเชื่อมโยงหรือโครงสร้างช่วงค่าอย่างง่าย

การสร้าง Iterator แบบกำหนดเอง เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

Iterator แบบกำหนดเอง

การสร้างตัววนซ้ำแบบกำหนดเองช่วยให้คุณควบคุมวิธีท่องผ่านโครงสร้างข้อมูลได้อย่างเต็มที่ บทเรียนนี้อธิบายการนำตัววนซ้ำของรายการเชื่อมโยงไปใช้ทีละขั้นตอน

คลาส Node

ขั้นแรก ให้กำหนดโครงสร้างโหนดสำหรับรายการเชื่อมโยงทางเดียว

class Node<T> {
    final T value;
    Node<T> next;

    Node(T value) {
        this.value = value;
    }
}

// Building a chain: 1 -> 2 -> 3
Node<Integer> head = new Node<>(1);
head.next = new Node<>(2);
head.next.next = new Node<>(3);

การนำ Iterator ไปใช้

สร้างคลาสภายในที่นำ Iterator<T> ไปใช้ โดยมีตัวชี้ตำแหน่งชี้ไปยังโหนดปัจจุบัน

import java.util.Iterator;
import java.util.NoSuchElementException;

class LinkedList<T> implements Iterable<T> {
    private Node<T> head;
    private int size;

    private class LinkedListIterator implements Iterator<T> {
        private Node<T> current = head; // cursor

        @Override
        public boolean hasNext() {
            return current != null;
        }

        @Override
        public T next() {
            if (!hasNext()) throw new NoSuchElementException();
            T value = current.value;
            current = current.next;
            return value;
        }
    }

    @Override
    public Iterator<T> iterator() {
        return new LinkedListIterator();
    }
}

addFirst และ LinkedList ฉบับสมบูรณ์

เพิ่มความสามารถในการนำโหนดมาต่อไว้ด้านหน้า และดูคลาสที่ทำงานได้อย่างสมบูรณ์

class LinkedList<T> implements Iterable<T> {
    private Node<T> head;
    private int size;

    public void addFirst(T value) {
        Node<T> node = new Node<>(value);
        node.next = head;
        head = node;
        size++;
    }

    public void addLast(T value) {
        Node<T> node = new Node<>(value);
        if (head == null) { head = node; }
        else {
            Node<T> curr = head;
            while (curr.next != null) curr = curr.next;
            curr.next = node;
        }
        size++;
    }

    public int size() { return size; }

    @Override
    public Iterator<T> iterator() {
        return new LinkedListIterator();
    }
}

การใช้ Iterator แบบกำหนดเอง

เมื่อนำอินเทอร์เฟซ Iterable ไปใช้แล้ว รายการเชื่อมโยงจะทำงานกับลูปวนซ้ำสมาชิกและ forEach ได้

LinkedList<String> list = new LinkedList<>();
list.addLast("Alice");
list.addLast("Bob");
list.addLast("Charlie");

// For-each loop works!
for (String name : list) {
    System.out.println(name);
}
// Alice
// Bob
// Charlie

// Stream also works (Java 8+)
list.forEach(name -> System.out.println("Hello, " + name));

ตัววนซ้ำช่วง

ตัวอย่างที่ง่ายกว่า: ตัววนซ้ำเหนือลำดับตัวเลข โดยไม่ต้องมีโครงสร้างข้อมูลรองรับ

class IntRange implements Iterable<Integer> {
    private final int start, end, step;

    IntRange(int start, int end, int step) {
        this.start = start; this.end = end; this.step = step;
    }
    IntRange(int start, int end) { this(start, end, 1); }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            int current = start;
            public boolean hasNext() { return current < end; }
            public Integer next() {
                if (!hasNext()) throw new NoSuchElementException();
                int val = current;
                current += step;
                return val;
            }
        };
    }
}

for (int n : new IntRange(0, 10, 2)) System.out.print(n + " ");
// 0 2 4 6 8

ตัววนซ้ำแบบท่องตามลำดับกลางของต้นไม้

การนำตัววนซ้ำแบบท่องตามลำดับกลางของ BST ไปใช้โดยใช้สแตกอย่างชัดแจ้ง ซึ่งแสดงให้เห็นว่าตัววนซ้ำสามารถแทนที่การท่องแบบเรียกซ้ำได้อย่างไร

import java.util.*;

class BinaryTree<T extends Comparable<T>> {
    private record TreeNode<T>(T val, TreeNode<T> left, TreeNode<T> right) {}

    private TreeNode<T> root;

    public Iterator<T> inorderIterator() {
        Deque<TreeNode<T>> stack = new ArrayDeque<>();
        pushLeft(root, stack);
        return new Iterator<>() {
            public boolean hasNext() { return !stack.isEmpty(); }
            public T next() {
                TreeNode<T> node = stack.pop();
                pushLeft(node.right(), stack);
                return node.val();
            }
        };
    }

    private void pushLeft(TreeNode<T> node, Deque<TreeNode<T>> stack) {
        while (node != null) { stack.push(node); node = node.left(); }
    }
}

ตัววนซ้ำแบบประเมินค่าเมื่อจำเป็น

ตัววนซ้ำสามารถสร้างค่าเมื่อจำเป็นได้ โดยสร้างเฉพาะเมื่อเรียก next() เหมาะสำหรับลำดับที่ไม่มีที่สิ้นสุด

class FibonacciIterator implements Iterator<Long> {
    private long a = 0, b = 1;

    @Override public boolean hasNext() { return true; } // infinite!

    @Override public Long next() {
        long result = a;
        long next = a + b;
        a = b;
        b = next;
        return result;
    }
}

Iterator<Long> fib = new FibonacciIterator();
for (int i = 0; i < 10; i++) System.out.print(fib.next() + " ");
// 0 1 1 2 3 5 8 13 21 34

ตัววนซ้ำแบบกรอง

ตัววนซ้ำแบบตัวตกแต่งที่ห่อตัววนซ้ำอื่นและข้ามสมาชิกที่ไม่ตรงตามเงื่อนไขคัดเลือก

import java.util.*;
import java.util.function.*;

class FilterIterator<T> implements Iterator<T> {
    private final Iterator<T> source;
    private final Predicate<T> predicate;
    private T next;
    private boolean hasNext;

    FilterIterator(Iterator<T> source, Predicate<T> predicate) {
        this.source = source; this.predicate = predicate;
        advance();
    }

    private void advance() {
        hasNext = false;
        while (source.hasNext()) {
            T candidate = source.next();
            if (predicate.test(candidate)) { next = candidate; hasNext = true; break; }
        }
    }

    public boolean hasNext() { return hasNext; }
    public T next() { T val = next; advance(); return val; }
}

List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);
Iterator<Integer> evens = new FilterIterator<>(nums.iterator(), n -> n % 2 == 0);
while (evens.hasNext()) System.out.print(evens.next() + " ");
// 2 4 6 8 10

การเชื่อมต่อ Iterator กับ Stream

สามารถปรับตัววนซ้ำแบบกำหนดเองให้ใช้กับสตรีมได้ด้วย Spliterators.spliteratorUnknownSize()

import java.util.*;
import java.util.stream.*;

Iterator<Integer> rangeIt = new IntRange(1, 6).iterator();

Stream<Integer> stream = StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(rangeIt, Spliterator.ORDERED),
    false // not parallel
);

int sum = stream.mapToInt(Integer::intValue).sum();
System.out.println(sum); // 15

การนำสมาชิกออกระหว่างการวนซ้ำ

เมธอดทางเลือก remove() ของ Iterator จะนำสมาชิกที่คืนค่าจากการเรียก next() ครั้งล่าสุดออก และต้องนำไปใช้อย่างชัดแจ้งในตัววนซ้ำแบบกำหนดเอง

class MutableLinkedList<T> implements Iterable<T> {
    // ... (full implementation)

    // Iterator with remove support
    private class RemovableIterator implements Iterator<T> {
        private Node<T> prev = null;
        private Node<T> current = head;

        public boolean hasNext() { return current != null; }
        public T next() {
            prev = (prev == null) ? null : current;
            T val = current.value;
            current = current.next;
            return val;
        }

        public void remove() {
            // Remove the last returned node
            if (prev == null) head = current;
            else prev.next = current;
            size--;
        }
    }
}

รายการตรวจสอบ Iterator

เมื่อนำ Iterator แบบกำหนดเองไปใช้:

  • เรียก hasNext() ก่อน next() เสมอ
  • เมื่อไม่มีสมาชิกเหลืออยู่ ให้ next() โยน NoSuchElementException แทนการคืนค่า null
  • ทำให้ตัววนซ้ำไม่มีสถานะที่ขึ้นกับคอลเลกชัน โดยอย่าเก็บขนาดของคอลเลกชันไว้ในแคช
  • ใช้ modCount เพื่อตรวจจับการแก้ไขพร้อมกันหากจำเป็น

ตรวจสอบความเข้าใจอย่างรวดเร็ว

เมื่อไม่มีสมาชิกเหลืออยู่ next() ควรโยนอะไร

ทบทวน: การนำ Iterator แบบกำหนดเองไปใช้

ประเด็นสำคัญ:

  • นำ Iterator ไปใช้ด้วย hasNext(), next() และ remove() ซึ่งเป็นทางเลือก
  • เก็บฟิลด์ตัวชี้ตำแหน่งไว้ในตัววนซ้ำ โดยให้ชี้ไปยังสมาชิกถัดไป
  • ให้ next() โยน NoSuchElementException เมื่อ hasNext() เป็น false
  • สร้างอินสแตนซ์ตัววนซ้ำใหม่สำหรับการเรียก iterator() แต่ละครั้ง เพื่อให้ตัวชี้ตำแหน่งเป็นอิสระต่อกัน
  • ตัววนซ้ำแบบประเมินค่าเมื่อจำเป็นจะสร้างค่าตามคำขอ เหมาะสำหรับลำดับที่ไม่มีที่สิ้นสุด
  • ห่อตัววนซ้ำด้วย StreamSupport.stream() เพื่อเชื่อมต่อกับ Stream API

คำถามที่พบบ่อย

บทเรียน “การสร้าง Iterator แบบกำหนดเอง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การสร้าง Iterator แบบกำหนดเอง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การสร้าง Iterator แบบกำหนดเอง”

สร้างคลาส iterator แบบกำหนดเองสำหรับรายการเชื่อมโยงหรือโครงสร้างช่วงค่าอย่างง่าย คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การสร้าง Iterator แบบกำหนดเอง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. สัญญาของ Iterable และ Iterator
  2. การสร้าง Iterator แบบกำหนดเอง
  3. ListIterator และการวนดูแบบสองทิศทาง
  4. Iterator แบบหยุดเร็วกับแบบปลอดภัย
← กลับไปที่ Java Academy