عقود 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()); // 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 للسماح بالتكرار على أسطره باستخدام حلقة 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 يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- عقود Iterable وIterator
- تطبيق Iterator مخصص
- ListIterator والتنقل ثنائي الاتجاه
- المكررات Fail-Fast مقابل Fail-Safe