为啥循环遍历 ArrayList<String> 与常规数组相同? [复制]
Posted
技术标签:
【中文标题】为啥循环遍历 ArrayList<String> 与常规数组相同? [复制]【英文标题】:Why Looping through ArrayList<String> is same as a regular array? [duplicate]为什么循环遍历 ArrayList<String> 与常规数组相同? [复制] 【发布时间】:2013-07-20 02:40:27 【问题描述】:方法一
ArrayList<String> list = new ArrayList<String>();
for (String s : list)
write.append(s);
write.append('\n');
如何以这种方式循环遍历ArrayList
?这种方法是不是只适用于静态常用数组,例如:String[] list2 = new String[]"1","2","3","4";
?
如果我想遍历 ArrayList<String> list
,为什么不这样做:方法 2
for (int i = 0; i < list.size(); i++)
write.append(list.get(i));
write.append("\n");
我只是不明白如何使用 方法 1。欢迎任何解释。
【问题讨论】:
搜索“enhanced for loop”和“iterables”并阅读它们! 不,这不是重复。我想知道原因,没有解释为什么以及如何可能。 我意识到 - 这里是a better resource。 @WilliamFox 我没有投票赞成关闭,只是输入了我的建议。 same.. 没有解释如何使用带有ArrayList
的方法 1 而不是Array
来进行迭代。当我说数组时,我的意思是String[] bla = new String[]
【参考方案1】:
ArrayList
实现了Iterable
,这使得它提供了一个Iterator
对象,然后由 for 循环用户使用。
任何实现 Iterable
的类都可以在 for 循环中使用,就像数组一样。
简化的 for 循环对于数组和集合看起来是一样的,但在底层,它使用数组的索引和集合的迭代器。
【讨论】:
【参考方案2】:这些称为 for-each 循环,可以应用于数组和集合。格式:
for ([type] [var-name] : [array or iterable value])
...
要使用 for-each 循环,您只需要满足以下两个条件之一:
-
迭代值是一个数组,或者
迭代值为
Iterable
。
我们这样做的最大原因是因为List
不是我们可以在循环中使用的唯一Iterable
,但它是唯一可以索引的。这使您可以进行通用迭代,而不是将自己锁定在固定的索引列表格式中。
例如,HashSet
没有排序,但我仍然可以在 for-each 循环中对其进行迭代:
HashSet<String> strs = new HashSet<String>();
for (String str : strs) ...
我还可以有一个方法采用Iterable
而不是List
:
public static void printStrings(Iterable<String> strs)
for (String str : strs)
System.out.println(str);
如果不先将其复制到其他东西(例如数组或List
)中,我无法使用索引对其进行迭代。
使用 for-each 循环的另一个重要原因是它编译为使用列表外的Iterator
(通过Iterable.iterator()
),这允许快速失败的迭代。这会导致像ConcurrentModificationException
s 这样的东西告诉我们在我们迭代它时集合被修改了。例如,这总是会抛出一个ConcurrentModificationException
:
List<String> strs = ... ;
for (String str : strs)
strs.remove(str);
但这不会:
List<String> strs = ... ;
for (int i = 0; i < strs.length(); i++)
strs.remove(str);
这对于多线程应用程序很有用,因为您应该在访问列表之前锁定列表,因为大多数 List
实现不是为线程安全而设计的,并且迭代是从不没有外部同步的线程安全,同时使用索引和 Iterator
。如果一个线程对其进行迭代,而另一个线程对其进行了更改,则可以(不能保证,但可以)抛出ConcurrentModificationException
,它告诉您列表未正确锁定。被索引的永远不会给你这种信息。相反,它只会表现出奇怪的行为,比如跳过元素。
【讨论】:
【参考方案3】:有一个名为Iterable
的接口允许快速迭代。如果某些东西实现了Iterable
,则允许快速迭代。 Iterable
接口有一个方法,它返回一个Iterator
,可用于迭代元素。
【讨论】:
“快速”迭代是什么意思?Itereable
是一个单一方法接口,仅此而已。
“快速”迭代并不是很快。这只是一个打字快捷方式。【参考方案4】:
第一个称为enhanced-for,或“for each”。它被认为是 for
语句的传统模型的语法糖 - 允许您迭代集合中的 每个 元素 - 无论是数组还是 Java 集合框架中的任何内容。
这些类型的循环有两个明显的区别:
增强的 for 语句为您索引值,并将其作为声明的一部分存储在临时变量中。因此,您不必执行val[i]
或 value.get(i)
之类的操作 - 这会自动为您完成。
您无法在增强的 for 语句中指定增量;您可以遍历集合中的所有元素,或者通过 break
语句提前终止。
在 JLS 中定义了可以使用标准数组进行迭代的原因,特别是 §14.14.2 - 因为数组没有实现 Iterable
,它会将其转换为标准行为的 for
语句。
...否则,表达式必须具有数组类型,T[]。
让
L1 ... Lm
是紧接在增强的 for 语句之前的标签序列(可能为空)。增强的 for 语句相当于基本的 for 语句,形式如下:
T[] #a = Expression; L1: L2: ... Lm: for (int #i = 0; #i < #a.length; #i++) VariableModifiers(opt) TargetType Identifier = #a[#i]; Statement
#a 和 #i 是自动生成的标识符,与增强 for 语句发生时范围内的任何其他标识符(自动生成或其他方式)不同。
【讨论】:
【参考方案5】:这是 for-each 语法:http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html
编译器会将您在方法 1 中的代码转换为类似:
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); )
String s = iterator.next();
write.append(s);
write.append('\n');
【讨论】:
这仅适用于实现Iterable
的集合。数组没有实现Iterable
,所以这不适用。
而且是错误的,因为没有getIterator
方法。
@Makoto,问题是“我只是不明白如何使用*方法 1。”。这是我的回答。
@MarkoTopolnik,如果你说getIterator
应该是iterator
,那将是一个更有用的评论。我不认为拼写错误会导致答案错误。
还是错了,因为list
不是迭代器变量的名字。顺便说一句,“它”是指“代码”而不是“答案”。另外,如果我无法找到对您个人最有用的正确解释方式,我深表歉意。以上是关于为啥循环遍历 ArrayList<String> 与常规数组相同? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何从 HashMap 中提取 ArrayList 并在 Java 中循环遍历它?
求教arraylist里面放map,怎么循环遍历得到map里面的数据,如:List<Map<String, String>> list = new Ar