【问题标题】: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&lt;String&gt; 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[]

标签: java


【解决方案1】:

ArrayList 实现了Iterable,这使得它提供了一个Iterator 对象,然后由 for 循环用户使用。

任何实现 Iterable 的类都可以在 for 循环中使用,就像数组一样。

简化的 for 循环对于数组和集合看起来是一样的,但在底层,它使用数组的索引和集合的迭代器。

【讨论】:

    【解决方案2】:

    这些称为 for-each 循环,可以应用于数组和集合。格式:

    for ([type] [var-name] : [array or iterable value]) {
        ...
    }
    

    要使用 for-each 循环,您只需要满足以下两个条件之一:

    1. 迭代值是一个数组,或者
    2. 迭代值为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()),这允许快速失败的迭代。这会导致像ConcurrentModificationExceptions 这样的东西告诉我们在我们迭代它时集合被修改了。例如,这总是会抛出一个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不是迭代器变量的名字。顺便说一句,“它”是指“代码”而不是“答案”。另外,如果我无法找到对您个人最有用的正确解释方式,我深表歉意。
        猜你喜欢
        • 2020-12-24
        • 2020-06-15
        • 1970-01-01
        • 2016-09-07
        • 2016-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多