0Pricing
Java Academy · درس

عقود Iterable وIterator

افهم واجهتي Iterable وIterator وكيف تعمل حلقات for-each داخليًا

عقود Iterable وIterator درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.

Iterable وIterator

إن الواجهتين Iterable<T> وIterator<T> هما اللتان تدعمان حلقة for-each في Java. ويسمح لك فهمهما بجعل هياكل البيانات الخاصة بك متوافقة مع الحلقات.

واجهة Iterable

تحتوي Iterable<T> على أسلوب واحد هو iterator()، يعيد Iterator<T>. ويمكن استخدام أي فئة تطبّق Iterable في حلقة for-each.

// 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)
}

تحويل حلقة for-each إلى صيغتها الأساسية

حلقة for-each هي صياغة نحوية مختصرة لنمط 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 صريح (باستثناء 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() مكرّرًا جديدًا مستقلًا. ويمكن تفعيل عدة مكرّرات في الوقت نفسه على المجموعة ذاتها.

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()); // 2

Iterable مقابل 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 للسماح بالتكرار على أسطره باستخدام حلقة for-each.

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:

  • هياكل البيانات المخصصة (الشجرة والرسم البياني والقائمة المرتبطة)
  • التسلسلات الكسولة التي تولّد العناصر عند الطلب
  • التسلسلات القائمة على الموارد (أسطر الملفات ومؤشر قاعدة البيانات وطابور الرسائل)

تحقق سريع

ما الاستثناء الذي يُطرح عند تعديل مجموعة أثناء التكرار باستخدام حلقة for-each؟

مراجعة: عقود Iterable وIterator

أهم النقاط:

  • يحتوي Iterable على أسلوب واحد: iterator() — لتمكين دعم حلقة for-each
  • يحتوي Iterator على hasNext() وnext() وremove() الاختياري
  • حلقة for-each هي صياغة نحوية مختصرة لنمط Iterable/Iterator
  • استدعِ iterator() عدة مرات للحصول على مؤشرات جديدة ومستقلة
  • لا تعدّل مجموعة أثناء حلقة for-each — استخدم Iterator.remove() بدلًا من ذلك
  • طبّق Iterable على هياكل البيانات المخصصة لدعم حلقات for-each

الأسئلة الشائعة

هل درس «عقود Iterable وIterator» مجاني؟

نعم — نص درس «عقود Iterable وIterator» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «عقود Iterable وIterator»؟

افهم واجهتي Iterable وIterator وكيف تعمل حلقات for-each داخليًا تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «عقود Iterable وIterator»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. عقود Iterable وIterator
  2. تطبيق Iterator مخصص
  3. ListIterator والتنقل ثنائي الاتجاه
  4. المكررات Fail-Fast مقابل Fail-Safe
← العودة إلى Java Academy