سادهترین انتخاب شما برای حلقهزدن روی عناصر یک collection استفاده از الگوی for-each است.
اجرای این کد خروجی زیر را تولید میکند:
one
two
three
این الگو بسیار کارآمد است، تا زمانی که فقط نیاز دارید عناصر collection را بخوانید. الگوی Iterator اجازه میدهد بعضی عناصر collection را هنگام حلقهزدن حذف کنید. اگر نیاز دارید این کار را انجام دهید، میخواهید از الگوی Iterator استفاده کنید.
حلقهزدن روی عناصر یک collection از یک شیء خاص، نمونهای از Interface Iterator استفاده میکند. میتوانید شیء Iterator را از هر گسترش Interface Collection دریافت کنید. متد iterator() در Interface Iterable تعریف شده که Interface Collection از آن ارثبری میکند و تمام Interfaceهای سلسلهمراتب collection بیشتر آن را گسترش میدهند.
حلقهزدن روی عناصر یک collection با استفاده از این شیء یک فرآیند دو مرحلهای است.
hasNext()next() حرکت کنید.اگر متد next() را فراخوانی کنید اما عنصر دیگری در collection نباشد، NoElementException دریافت میکنید. فراخوانی hasNext() اجباری نیست و برای کمک به شماست تا مطمئن شوید واقعاً عنصر بعدی وجود دارد.
الگو این است:
این کد خروجی زیر را تولید میکند:
one
two
Interface Iterator سومین متدی دارد: remove(). فراخوانی این متد عنصر فعلی را از collection حذف میکند. البته مواردی وجود دارد که این متد پشتیبانی نمیشود و UnsupportedOperationException ایجاد میکند. واضح است که فراخوانی remove() روی یک collection تغییرناپذیر (Immutable) نمیتواند کار کند. پیادهسازی Iteratorای که از ArrayList، LinkedList و HashSet دریافت میکنید همگی این عملیات حذف را پشتیبانی میکنند.
اگر اتفاقی محتوای collection را هنگام حلقهزدن روی آن تغییر دهید، ممکن است ConcurrentModificationException دریافت کنید. دریافت این exception ممکن است کمی گیجکننده باشد، چون این exception در برنامهنویسی همزمان (Concurrent) هم استفاده میشود. در Context коллекション Framework، ممکن است بدون دست زدن به برنامهنویسی چندهنخه (Multithreaded) هم آن را دریافت کنید.
کد زیر ConcurrentModificationException ایجاد میکند.
اگر نیاز دارید عناصر collection که یک معیار مشخص را برآورده میکنند حذف شوند، میتوانید از متد removeIf() استفاده کنید.
اکنون که دیدید Iterator در Collection Framework چیست، میتوانید یک پیادهسازی ساده از Interface Iterable بسازید.
فرض کنید نیاز دارید کلاس Rangeای بسازید که بازهای از اعداد صحیح بین دو حد را مدلسازی کند. تنها کاری که باید بکنید حلقهزدن از عدد صحیح اول تا آخرین است.
میتوانید Interface Iterable را با یک Record پیادهسازی کنید — قابلیتی که در Java SE 16 معرفی شد:
// lower bound is included, upper bound is excluded
record Range(int start, int end) implements Iterable<Integer> {
@Override
public Iterator<Integer> iterator() {
return new Iterator<>() {
private int index = start;
@Override
public boolean hasNext() {
return index < end;
}
@Override
public Integer next() {
if (index >= end) {
throw new NoSuchElementException("" + index);
}
int currentIndex = index;
index++;
return currentIndex;
}
};
}
}
میتوانید همین کار را با یک کلاس ساده انجام دهید، در صورتی که اپلیکیشن شما هنوز Java SE 16 را پشتیبانی نمیکند. توجه کنید کد پیادهسازی Iterator دقیقاً یکسان است.
class Range implements Iterable<Integer> {
private final int start;
private final int end;
public Range(int start, int end) {
this.start = start;
this.end = end;
}
@Override
public Iterator<Integer> iterator() {
return new Iterator<>() {
private int index = start;
@Override
public boolean hasNext() {
return index < end;
}
@Override
public Integer next() {
if (index >= end) {
throw new NoSuchElementException("" + index);
}
int currentIndex = index;
index++;
return currentIndex;
}
};
}
}
در هر دو حالت، میتوانید نمونهای از Range را در دستور for-each استفاده کنید، چون Iterable را پیادهسازی میکند:
اجرای این کد خروجی زیر را تولید میکند:
i = 0
i = 1
i = 2
i = 3
i = 4
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/