给定Iterator<Element>,我们如何方便地将Iterator转换为List<Element>,以便我们可以对其使用List的操作,如get(index), add(element)等。
Iterator<Element>
Iterator
List<Element>
List
get(index)
add(element)
你可以像这样复制一个迭代器到一个新列表:
Iterator<String> iter = list.iterator(); List<String> copy = new ArrayList<String>(); while (iter.hasNext()) copy.add(iter.next());
这是假设列表中包含字符串。实际上没有更快的方法从迭代器中重新创建列表,您只能手动遍历它,并将每个元素复制到合适类型的新列表中。
编辑:
下面是一个以类型安全的方式将迭代器复制到新列表的泛型方法:
public static <T> List<T> copyIterator(Iterator<T> iter) { List<T> copy = new ArrayList<T>(); while (iter.hasNext()) copy.add(iter.next()); return copy; }
像这样使用它:
List<String> list = Arrays.asList("1", "2", "3"); Iterator<String> iter = list.iterator(); List<String> copy = copyIterator(iter); System.out.println(copy); > [1, 2, 3]
List result = new ArrayList(); while (i.hasNext()){ result.add(i.next()); }
在这种情况下,如果你想要最快的方法,那么for loop更好。
for loop
样本容量为10,000 runs的迭代器的参数为40 ms,而for循环的参数为2 ms
10,000 runs
40 ms
2 ms
ArrayList<String> alist = new ArrayList<String>(); long start, end; for (int i = 0; i < 1000000; i++) { alist.add(String.valueOf(i)); } ListIterator<String> it = alist.listIterator(); start = System.currentTimeMillis(); while (it.hasNext()) { String s = it.next(); } end = System.currentTimeMillis(); System.out.println("Iterator start: " + start + ", end: " + end + ", delta: " + (end - start)); start = System.currentTimeMillis(); int ixx = 0; for (int i = 0; i < 100000; i++) { String s = alist.get(i); } System.out.println(ixx); end = System.currentTimeMillis(); System.out.println("for loop start: " + start + ", end: " + end + ", delta: " + (end - start));
这是假设列表中包含字符串。
最好使用番石榴这样的库:
import com.google.common.collect.Lists; Iterator<Element> myIterator = ... //some iterator List<Element> myList = Lists.newArrayList(myIterator);
另一个番石榴的例子:
ImmutableList.copyOf(myIterator);
或Apache Commons Collections:
import org.apache.commons.collections.IteratorUtils; Iterator<Element> myIterator = ...//some iterator List<Element> myList = IteratorUtils.toList(myIterator);
使用谷歌番石榴 !
Iterable<String> fieldsIterable = ... List<String> fields = Lists.newArrayList(fieldsIterable);
++
你也可以使用Apache commons-collections中的IteratorUtils,尽管它不支持泛型:
IteratorUtils
List list = IteratorUtils.toList(iterator);
非常简洁的解决方案与普通Java 8使用java.util.stream:
java.util.stream
public static <T> ArrayList<T> toArrayList(final Iterator<T> iterator) { return StreamSupport .stream( Spliterators .spliteratorUnknownSize(iterator, Spliterator.ORDERED), false) .collect( Collectors.toCollection(ArrayList::new) ); }
在Java 8中,你可以使用添加到Iterator接口的新forEachRemaining方法:
forEachRemaining
List<Element> list = new ArrayList<>(); iterator.forEachRemaining(list::add);
注意在Iterable和Iterator之间有一个区别。
Iterable
如果你有一个Iterable,那么在Java 8中你可以使用这个解决方案:
Iterable<Element> iterable = createIterable(); List<Element> array = StreamSupport .stream(iterable.spliterator(), false) .collect(Collectors.toList());
据我所知,Collectors.toList()创建ArrayList实例。
Collectors.toList()
ArrayList
return StreamSupport.stream(iter.spliterator(), false).collect(Collectors.toList());
试试Cactoos中的StickyList:
StickyList
List<String> list = new StickyList<>(iterable);
免责声明:我是开发者之一。
我只是想指出不会工作的一个看似明显的解决方案:
List list = Stream.generate(iterator::next) .collect(Collectors.toList());
这是因为Stream#generate(Supplier<T>)只能创建无限流,它并不期望其参数抛出NoSuchElementException(这是Iterator#next()最终会做的事情)。
Stream#generate(Supplier<T>)
NoSuchElementException
Iterator#next()
如果你选择迭代器→流→列表的方式,则应该使用xehpuk的答案。
没有外部依赖,这是一个使用Streams和java 16 toList()的一行程序。
给定Iterator<?> iterator:
Iterator<?> iterator
List<?> list = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false).toList();