给定
Iterator<Element>
,我们如何方便地将Iterator
转换为List<Element>
,以便我们可以对其进行List
的操作,如get(index)
、add(element)
等
最好使用像Guava这样的库:
import com.google.common.collect.Lists;
Iterator<Element> myIterator = ... //some iterator
List<Element> myList = Lists.newArrayList(myIterator);
另一个番石榴示例:
ImmutableList.copyOf(myIterator);
import org.apache.commons.collections.IteratorUtils;
Iterator<Element> myIterator = ...//some iterator
List<Element> myList = IteratorUtils.toList(myIterator);
在 Java 8 中,您可以使用已添加到
forEachRemaining
接口的新 Iterator
方法:
List<Element> list = new ArrayList<>();
iterator.forEachRemaining(list::add);
您可以将迭代器复制到新列表,如下所示:
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]
Iterable
和 Iterator
之间存在差异。
如果您有
Iterable
,那么对于 Java 8,您可以使用以下解决方案:
Iterable<Element> iterable = createIterable();
List<Element> array = StreamSupport
.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
据我所知
Collectors.toList()
创建 ArrayList
实例。
其实我觉得,一行字也好看。
例如,如果您需要从某种方法返回
List<Element>
:
return StreamSupport.stream(iter.spliterator(), false).collect(Collectors.toList());
您还可以使用 Apache commons-collections
中的
IteratorUtils
,尽管它不支持泛型:
List list = IteratorUtils.toList(iterator);
java.util.stream
,使用纯 Java 8 实现非常简洁的解决方案:
public static <T> ArrayList<T> toArrayList(final Iterator<T> iterator) {
return StreamSupport
.stream(
Spliterators
.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
.collect(
Collectors.toCollection(ArrayList::new)
);
}
没有外部依赖,这是使用 Streams 和 java 16 toList() 的单行代码。
鉴于
Iterator<?> iterator
:
List<?> list = StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false).toList();
List result = new ArrayList();
while (i.hasNext()){
result.add(i.next());
}
我只是想指出一个看似明显但不会工作的解决方案:
列表列表 = Stream.generate(iterator::next) .collect(Collectors.toList());
Stream#generate(Supplier<T>)
只能创建无限流,它不希望它的参数抛出 NoSuchElementException
(这就是 Iterator#next()
最终会做的事情)。
使用谷歌番石榴!
Iterable<String> fieldsIterable = ...
List<String> fields = Lists.newArrayList(fieldsIterable);
++
我在使用 Spring Boot Repository 时遇到了这个问题,其中
Iterable<Element> allIterables = repository.findAll()
返回一个 Iterable。
我的解决方案是实例化一个新列表
List<Element> allElements = new ArrayList<>()
并使用allIterables.forEach(allElements::add)
将所有元素添加到我的列表中。
在这种情况下,如果您想要尽可能最快的方式,那么
for loop
会更好。
样本大小为
10,000 runs
的迭代器需要 40 ms
,而 for 循环则需要 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));
假设列表包含字符串。