Answers:
最好使用像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);
::
?它叫什么名字?似乎是对list.add()的直接引用;并且似乎还有一些java8新事物;谢谢!:)
::
语法是Java 8中的新增功能,它引用的是“方法引用”,它是lambda的简写形式。看到这里的进一步信息:docs.oracle.com/javase/tutorial/java/javaOO/...
iterator
来的?它是一个无法解析的符号
iterator
。
您可以将迭代器复制到新列表,如下所示:
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
,则在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());
Iterable
iterator
。他们是完全不同的。
Iterator
回单用途 Iterable
使用() -> iterator
。在这样的情况下这可能很有用,但让我再次强调一下重要的事情:只有在可以单次使用的 Iterable
情况下,才可以使用此方法。iterable.iterator()
多次调用会产生意外结果。然后,以上答案变为Iterator<Element> iterator = createIterator();
List<Element> array = StreamSupport.stream(((Iterable<Element>) () -> iterable).spliterator(), false).collect(toList());
您还可以IteratorUtils
从Apache commons-collections中使用它,尽管它不支持泛型:
List list = IteratorUtils.toList(iterator);
使用纯Java 8的简洁解决方案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)
);
}
iterator.forEachRemaining( list::add )
,Java 8中的新功能也更加简洁。Collector
在这种情况下,将list变量压入并不会提高可读性,因为必须由a Stream
和a 支持Spliterator
。
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()
最终将执行此操作)。
如果选择Iterator→Stream→List方式,则应使用xehpuk的答案。
使用谷歌番石榴!
Iterable<String> fieldsIterable = ...
List<String> fields = Lists.newArrayList(fieldsIterable);
++
在这种情况下,如果您想要最快的方法,那就for loop
更好了。
样本数量为10,000 runs
take 的迭代器,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));
假设列表包含字符串。
for
循环和访问列表的元素get(i)
比使用迭代器要快...但这不是OP的要求,他特别提到将迭代器作为输入。
get(int)
循环中,您仅查看100万个1m条目。如果您将该循环更改为it.size()
您将看到这两种方法接近相同的速度。通常,这类Java速度测试只能提供有限的实际性能信息,应对此持怀疑态度。