Emi*_*mil 76 java arrays foreach iterator
给出以下代码段:
int[] arr = {1, 2, 3};
for (int i : arr)
System.out.println(i);
Run Code Online (Sandbox Code Playgroud)
我有以下问题:
uck*_*man 55
如果你想要一个Iterator数组,你可以使用其中一个直接实现,而不是将数组包装在一个List.例如:
Apache Commons Collections ArrayIterator
或者,这个,如果你想使用泛型:
com.Ostermiller.util.ArrayIterator
请注意,如果要使用Iterator基本类型,则不能,因为基本类型不能是通用参数.例如,如果你想要一个Iterator<int>,你必须使用一个Iterator<Integer>代替,这将导致大量的自动装箱和-unboxing,如果它的支持int[].
Pét*_*rök 50
不,没有转换.JVM只是在后台使用索引迭代数组.
引自Effective Java 2nd Ed.,第46项:
请注意,即使对于数组,使用for-each循环也不会有性能损失.实际上,在某些情况下,它可能比普通的for循环提供轻微的性能优势,因为它只计算一次数组索引的限制.
所以你不能得到一个Iterator数组(当然除非把它转换成List第一个).
Joc*_*hem 33
Arrays.asList(ARR).iterator();
或编写自己的,实现ListIterator接口..
30t*_*thh 31
Google Guava Librarie的系列提供了这样的功能:
Iterator<String> it = Iterators.forArray(array);
Run Code Online (Sandbox Code Playgroud)
人们应该优先考虑Guava而不是Apache Collection(似乎已经放弃了).
Ash*_*iya 10
public class ArrayIterator<T> implements Iterator<T> {
private T array[];
private int pos = 0;
public ArrayIterator(T anArray[]) {
array = anArray;
}
public boolean hasNext() {
return pos < array.length;
}
public T next() throws NoSuchElementException {
if (hasNext())
return array[pos++];
else
throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Run Code Online (Sandbox Code Playgroud)
严格地说,你不能得到原始数组的迭代器,因为Iterator.next()只能返回一个Object.但是通过自动装箱的魔力,您可以使用Arrays.asList()方法获取迭代器.
Iterator<Integer> it = Arrays.asList(arr).iterator();
Run Code Online (Sandbox Code Playgroud)
上面的答案是错误的,你不能Arrays.asList()在原始数组上使用它会返回一个List<int[]>.利用番石榴的Ints.asList()来代替.
您无法直接获取数组的迭代器.
但是您可以使用由数组支持的List,并在此列表中获取一个ierator.为此,您的数组必须是Integer数组(而不是int数组):
Integer[] arr={1,2,3};
List<Integer> arrAsList = Arrays.asList(arr);
Iterator<Integer> iter = arrAsList.iterator();
Run Code Online (Sandbox Code Playgroud)
注意:这只是理论.你可以得到这样的迭代器,但我不鼓励你这样做.与使用"扩展语法"的阵列上的直接迭代相比,性能不佳.
注意2:使用此方法的列表构造不支持所有方法(因为列表由具有固定大小的数组支持).例如,迭代器的"remove"方法将导致异常.
我有点晚了,但我注意到一些关键点被遗漏了,特别是关于 Java 8 和Arrays.asList.
作为Ciro Santilli \xe5\x85\xad\xe5\x9b\x9b\xe4\xba\x8b\xe4\xbb\xb6 \xe6\xb3\x95\xe8\xbd\xae\xe5\x8a\x9f \xe5\x8c\ x85\xe5\x8d\x93\xe8\xbd\xa9指出,有一个方便的实用程序用于检查 JDK 附带的字节码:javap。使用它,我们可以确定以下两个代码片段在 Java 8u74 中生成相同的字节码:
int[] arr = {1, 2, 3};\nfor (int n : arr) {\n System.out.println(n);\n}\nRun Code Online (Sandbox Code Playgroud)\n\nint[] arr = {1, 2, 3};\n\n{ // These extra braces are to limit scope; they do not affect the bytecode\n int[] iter = arr;\n int length = iter.length;\n for (int i = 0; i < length; i++) {\n int n = iter[i];\n System.out.println(n);\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n虽然这不适用于基元,但应该注意的是,将数组转换为列表Arrays.asList不会对性能产生任何重大影响。对内存和性能的影响几乎是无法估量的。
Arrays.asList不使用可作为类轻松访问的普通 List 实现。它使用java.util.Arrays.ArrayList,这与 不一样java.util.ArrayList。它是一个非常薄的数组包装,无法调整大小。查看源代码java.util.Arrays.ArrayList,我们可以看到它的设计在功能上等同于数组。几乎没有任何开销。请注意,除了最相关的代码之外,我省略了所有代码,并添加了我自己的注释。
public class Arrays {\n public static <T> List<T> asList(T... a) {\n return new ArrayList<>(a);\n }\n\n private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {\n private final E[] a;\n\n ArrayList(E[] array) {\n a = Objects.requireNonNull(array);\n }\n\n @Override\n public int size() {\n return a.length;\n }\n\n @Override\n public E get(int index) {\n return a[index];\n }\n\n @Override\n public E set(int index, E element) {\n E oldValue = a[index];\n a[index] = element;\n return oldValue;\n }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n迭代器位于java.util.AbstractList.Itr. 就迭代器而言,它非常简单;它只是调用get()直到size()到达,就像手动 for 循环一样。这是Iterator数组最简单且通常最有效的实现。
同样,Arrays.asList不创建java.util.ArrayList. 它更加轻量级,适合以可忽略的开销获取迭代器。
正如其他人所指出的,Arrays.asList不能用于原始数组。Java 8 引入了几种处理数据集合的新技术,其中一些可用于从数组中提取简单且相对高效的迭代器。请注意,如果您使用泛型,则总是会遇到装箱-拆箱问题:您需要从 int 转换为 Integer,然后再转换回 int。虽然装箱/拆箱通常可以忽略不计,但在这种情况下,它确实会对 O(1) 性能产生影响,并且可能会导致非常大的阵列或资源非常有限的计算机(即SoC)出现问题。
对于 Java 8 中的任何类型的数组转换/装箱操作,我个人最喜欢的是新的流 API。例如:
\n\nint[] arr = {1, 2, 3};\nIterator<Integer> iterator = Arrays.stream(arr).mapToObj(Integer::valueOf).iterator();\nRun Code Online (Sandbox Code Playgroud)\n\n流 API 还提供了从一开始就避免装箱问题的构造,但这需要放弃迭代器而转而使用流。int、long 和 double 有专用的流类型(分别为 IntStream、LongStream 和 DoubleStream)。
\n\nint[] arr = {1, 2, 3};\nIntStream stream = Arrays.stream(arr);\nstream.forEach(System.out::println);\nRun Code Online (Sandbox Code Playgroud)\n\n有趣的是,Java 8 还添加了java.util.PrimitiveIterator. 这提供了两全其美的优点:与Iterator<T>过孔装箱兼容以及避免装箱的方法。PrimitiveIterator 具有三个对其进行扩展的内置接口:OfInt、OfLong 和 OfDouble。如果被调用,所有这三个都会装箱next(),但也可以通过诸如 之类的方法返回原语nextInt()。为 Java 8 设计的较新代码应避免使用next(),除非装箱是绝对必要的。
int[] arr = {1, 2, 3};\nPrimitiveIterator.OfInt iterator = Arrays.stream(arr);\n\n// You can use it as an Iterator<Integer> without casting:\nIterator<Integer> example = iterator;\n\n// You can obtain primitives while iterating without ever boxing/unboxing:\nwhile (iterator.hasNext()) {\n // Would result in boxing + unboxing:\n //int n = iterator.next();\n\n // No boxing/unboxing:\n int n = iterator.nextInt();\n\n System.out.println(n);\n}\nRun Code Online (Sandbox Code Playgroud)\n\n如果您还没有使用 Java 8,遗憾的是您最简单的选择不太简洁,并且几乎肯定会涉及拳击:
\n\nfinal int[] arr = {1, 2, 3};\nIterator<Integer> iterator = new Iterator<Integer>() {\n int i = 0;\n\n @Override\n public boolean hasNext() {\n return i < arr.length;\n }\n\n @Override\n public Integer next() {\n if (!hasNext()) {\n throw new NoSuchElementException();\n }\n\n return arr[i++];\n }\n};\nRun Code Online (Sandbox Code Playgroud)\n\n或者,如果您想创建更可重用的东西:
\n\npublic final class IntIterator implements Iterator<Integer> {\n private final int[] arr;\n private int i = 0;\n\n public IntIterator(int[] arr) {\n this.arr = arr;\n }\n\n @Override\n public boolean hasNext() {\n return i < arr.length;\n }\n\n @Override\n public Integer next() {\n if (!hasNext()) {\n throw new NoSuchElementException();\n }\n\n return arr[i++];\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n您可以通过添加自己的获取原语的方法来解决装箱问题,但它只能与您自己的内部代码一起使用。
\n\n不它不是。但是,这并不意味着将其包装在列表中会给您带来更差的性能,只要您使用轻量级的东西,例如Arrays.asList.
| 归档时间: |
|
| 查看次数: |
165512 次 |
| 最近记录: |