Существует множество решений, которые могут подойти в зависимости от ваших потребностей.
Решение 1: просмотр в фиксированном размере
Классический способ итерации по подмножеству списка - создать более узкое представление исходного списка и выполнить итерацию по всему этому представлению. Для создания такого представления используется метод subList
.
List<Integer> l = // initialization code
int limitIndex = Math.max(l.size()-1, 0); // needed for empty list
for (int v : l.subList(0, limitIndex)) {
// your code
}
Обратите внимание, что я использовал цикл 'foreach', который является удобным способом использования итераторов. Это строго эквивалентно этому коду:
Iterator<Integer> it = l.subList(0, limitIndex).iterator();
while(it.hasNext()) {
int v = it.next();
// your code
}
Также обратите внимание, что метод subList
не создает новый список: он только создает «представление» в исходном списке. Содержимое исходного списка не копируется, и все изменения, внесенные в исходный список, видны из списка, созданного subList
.
Решение 2: пользовательский Iterator / Iterable
Если все, что вам нужно, это итератор, который всегда повторяет от 0 до n-1, вы можете определить новый Iterable
с учетом этой конкретной потребности.
public class NoLastIterable<T> implements Iterable<T> {
private final List<T> backend;
public NoLastIterable(List<T> backend) {
this.backend = backend;
}
public Iterator<T> iterator() {
return new Iterator<T>() {
private int nextIndex;
public boolean hasNext() {
return nextIndex < backend.size() -1;
}
public T next() {
return backend.get(nextIndex++);
}
public void remove() {
throw new UnsupportedOperationException("not implemented");
}
};
}
}
Этот класс используется так:
for (int v : new NoLastIterable<Integer>(l)) {
// your code
}
Раствор 3
Вы даже можете создать свой собственный вид List
, как и subList
, но с большей гибкостью.
public class NoLastList<T> extends AbstractList<T> {
private final List<T> backend;
public NoLastList(List<T> backend) {
this.backend = backend;
}
@Override
public T get(int index) {
if (index >= size()) {
throw new IndexOutOfBoundsException();
}
return backend.get(index);
}
@Override
public int size() {
return Math.max(0, backend.size()-1);
}
}
То же использование, что и в других решениях:
for (int v : new NoLastList<Integer>(l)) {
// your code
}
Преимущества этого решения можно увидеть в следующей ситуации:
- исходный список создан и инициализирован
- создается экземпляр
NoLastList
(в виде исходного списка)
- некоторые элементы добавлены в исходный список
В этой ситуации повторение по NoLastList
будет учитывать элементы, которые были добавлены в последнее время. NoLastList
всегда представляет представление элементов от 0 до n-1, даже если n (размер) изменяется.