有很多解决方案,可以根据您的需要进行适当的调整。
解决方案 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(大小)发生变化。