تطبيق Iterator مخصص
أنشئ فئة Iterator مخصصة لقائمة مترابطة بسيطة أو لبنية نطاق
تطبيق Iterator مخصص درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.
Iterator مخصص
يمنحك إنشاء Iterator مخصص تحكمًا كاملًا في كيفية اجتياز بنية البيانات. يشرح هذا الدرس تطبيق 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، تعمل القائمة المرتبطة في حلقات for-each ومع 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));Iterator للنطاق
مثال أبسط: Iterator على نطاق رقمي دون بنية بيانات داعمة.
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 8Iterator للمرور الوسطي في شجرة
تطبيق Iterator للمرور الوسطي في 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(); }
}
}Iterator كسول
يمكن للمكرّرات توليد القيم بشكل كسول — أي عند استدعاء 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 34Iterator للتصفية
Iterator مزخرف يغلّف Iterator آخر ويتجاوز العناصر التي لا تطابق مسندًا.
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
يمكن تكييف المكرّرات للعمل مع Streams باستخدام 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() - اطرح
NoSuchElementExceptionمنnext()عند عدم وجود عناصر، ولا تُعِد null - اجعل المكرّر عديم الحالة بالنسبة إلى المجموعة (لا تخزّن حجم المجموعة مؤقتًا)
- استخدم modCount لاكتشاف التعديل المتزامن عند الحاجة
تحقق سريع
ما الذي ينبغي أن يطرحه next() عند عدم وجود عناصر أخرى؟
مراجعة: تطبيق Iterator مخصص
أهم النقاط:
- طبّق Iterator
باستخدام hasNext() وnext() وremove() الاختياري - احتفظ بحقل مؤشر في المكرّر يشير إلى العنصر التالي
- اطرح NoSuchElementException من next() عندما تكون hasNext() تساوي false
- أنشئ مثيل Iterator جديدًا لكل استدعاء لـ iterator() للحصول على مؤشرات مستقلة
- تولّد المكرّرات الكسولة القيم عند الطلب — وهو مفيد للتسلسلات اللانهائية
- غلّف المكرّرات في StreamSupport.stream() لربطها بواجهة Stream البرمجية
الأسئلة الشائعة
هل درس «تطبيق Iterator مخصص» مجاني؟
نعم — نص درس «تطبيق Iterator مخصص» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.
ماذا ستتعلم في «تطبيق Iterator مخصص»؟
أنشئ فئة Iterator مخصصة لقائمة مترابطة بسيطة أو لبنية نطاق تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟
لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.
كم من الوقت يستغرق درس «تطبيق Iterator مخصص»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟
نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- عقود Iterable وIterator
- تطبيق Iterator مخصص
- ListIterator والتنقل ثنائي الاتجاه
- المكررات Fail-Fast مقابل Fail-Safe