我正在迁移一段代码以使用泛型。这样做的一个理由是,for循环比跟踪索引或使用显式迭代器干净得多。

在大约一半的情况下,列表(ArrayList)通过使用索引以相反的顺序迭代。

谁能建议一种更干净的方法来做到这一点(因为我不喜欢索引for循环时使用集合),尽管它确实有效?

 for (int i = nodes.size() - 1; i >= 0; i--) {
    final Node each = (Node) nodes.get(i);
    ...
 }

注意:我不能在JDK之外添加任何新的依赖项。


当前回答

选项1:你有没有想过用Collections#reverse()反转列表,然后使用foreach?

当然,您可能还想重构代码,使列表的顺序正确,这样就不必反转它,这会占用额外的空间/时间。


编辑:

选项2:或者,您可以使用Deque而不是数组列表吗?它将允许您向前和向后迭代


编辑:

选项3:正如其他人建议的那样,你可以编写一个Iterator,它将反向遍历列表,下面是一个例子:

import java.util.Iterator;
import java.util.List;

public class ReverseIterator<T> implements Iterator<T>, Iterable<T> {

    private final List<T> list;
    private int position;

    public ReverseIterator(List<T> list) {
        this.list = list;
        this.position = list.size() - 1;
    }

    @Override
    public Iterator<T> iterator() {
        return this;
    }

    @Override
    public boolean hasNext() {
        return position >= 0;
    }

    @Override
    public T next() {
        return list.get(position--);
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

}


List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");

for (String s : new ReverseIterator<String>(list)) {
    System.out.println(s);
}

其他回答

如何使用DeQue:

  var queue = new ArrayDeque<>(list);
  while (!queue.isEmpty()) {
    var first = reversed ? queue.removeLast() : queue.removeFirst();
    var second = reversed ? queue.peekLast() : queue.peekFirst();
    if (second != null) {
      //your code goes here
    }
  }
Valid for Java 9+

List<String> strList = List.of("a", "b", "c", "d", "e");

IntStream.iterate(strList.size() - 1, i -> i >= 0, i -> --i)
         .mapToObj(strList::get)
         .forEach(System.out::println);

选项1:你有没有想过用Collections#reverse()反转列表,然后使用foreach?

当然,您可能还想重构代码,使列表的顺序正确,这样就不必反转它,这会占用额外的空间/时间。


编辑:

选项2:或者,您可以使用Deque而不是数组列表吗?它将允许您向前和向后迭代


编辑:

选项3:正如其他人建议的那样,你可以编写一个Iterator,它将反向遍历列表,下面是一个例子:

import java.util.Iterator;
import java.util.List;

public class ReverseIterator<T> implements Iterator<T>, Iterable<T> {

    private final List<T> list;
    private int position;

    public ReverseIterator(List<T> list) {
        this.list = list;
        this.position = list.size() - 1;
    }

    @Override
    public Iterator<T> iterator() {
        return this;
    }

    @Override
    public boolean hasNext() {
        return position >= 0;
    }

    @Override
    public T next() {
        return list.get(position--);
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException();
    }

}


List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");

for (String s : new ReverseIterator<String>(list)) {
    System.out.println(s);
}

正如至少两次建议的那样,您可以将descent iterator用于Deque,特别是用于LinkedList。如果你想使用for-each循环(即拥有一个Iterable),你可以构造并使用这样的包装器:

import java.util.*;

public class Main {

    public static class ReverseIterating<T> implements Iterable<T> {
        private final LinkedList<T> list;

        public ReverseIterating(LinkedList<T> list) {
            this.list = list;
        }

        @Override
        public Iterator<T> iterator() {
            return list.descendingIterator();
        }
    }

    public static void main(String... args) {
        LinkedList<String> list = new LinkedList<String>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");

        for (String s : new ReverseIterating<String>(list)) {
            System.out.println(s);
        }
    }
}

代码如下所示:

List<Item> items;
...
for (Item item : In.reverse(items))
{
    ...
}

把这段代码放到一个名为“In.java”的文件中:

import java.util.*;

public enum In {;
    public static final <T> Iterable<T> reverse(final List<T> list) {
        return new ListReverseIterable<T>(list);
    }

    class ListReverseIterable<T> implements Iterable<T> {
        private final List<T> mList;

        public ListReverseIterable(final List<T> list) {
            mList = list;
        }

        public Iterator<T> iterator() {
            return new Iterator<T>() {
                final ListIterator<T> it = mList.listIterator(mList.size());

                public boolean hasNext() {
                    return it.hasPrevious();
                }
                public T next() {
                    return it.previous();
                }
                public void remove() {
                    it.remove();
                }
            };
        }
    }
}