【问题标题】:Why are Iterable<E> and Iterator<E> in different packages?为什么 Iterable<E> 和 Iterator<E> 在不同的包中?
【发布时间】:2011-08-02 01:02:44
【问题描述】:

Iterable&lt;E&gt;java.lang 中,而Iterator&lt;E&gt;java.util 中。这样做有充分的理由,还是仅仅是糟糕设计的产物?

这似乎很奇怪,因为Iterable&lt;E&gt; 的唯一好处是提供Iterator&lt;E&gt;

编辑:一个潜在的原因是(当时)新引入的 for-each 循环。我想我的问题是,它们是等价的吗?

for(Object o : collection)
    ...
vs
for( Iterator iter = collection.iterator(); iter.hasNext(); ) {
    o = iter.next();
    ...

如果是,那么这仍然不能解释为什么这两个类位于不同的包中,因为编译器无论如何都必须导入 java.util 才能使用 Iterator 构造。

【问题讨论】:

  • 我认为如果他们可以从头开始做所有事情,Iterator 将与 Iterable 一起在 java.lang 中。但正如 duffymo 所说,它从 1.2 开始就在 util 中,你不能真正兼容地将类/接口移动到另一个位置。
  • @Paulo,如果他们愿意,他们可以拥有: interface java.lang.Iterator2;接口 java.util.Iterator 扩展了 java.lang.Iterator2
  • @Paŭlo,实际上它们不会在 java lang 中,在 java.lang 和 java.util.iterator 中放置另一个具有相同方法(next/hasNext)的接口同样容易扩展它。 Doh,Dilum 的评论也是这样,我没注意到。
  • 编译器必须导入 java.util 才能使用 Iterator 构造。 编译器从不导入任何东西,它是编写代码的那个。 for (E e: iterable) 确实需要额外的导入,这将是您问题的答案。
  • @bestsss:实际上,在 for 循环中不需要 remove 方法是第二个 Iterator 接口的一个很好的论据。

标签: java iterator iterable


【解决方案1】:

其中一部分是历史:IteratorJDK 1.2 以来一直与我们同在,IterableJDK 1.5 一起出现。 Iterable 带有增强的 for 循环。

糟糕的设计?不,进化。没有无所不知的创造者。随着经验的积累,它们被合并到 JDK 中。

【讨论】:

  • 这里的“经验教训”是什么?为什么 java.lang 是 Collections API 中的一个合适的包,其成员基本上都在 java.util 中?我认为这根本不能回答问题。
  • 吸取的教训类似于“哦,废话,伙计们,我们也需要为 Iterable 概念建模”。
  • 难道他们不能将Iterable 放在java.util 中吗?虽然它是作为 Collections API 的一部分发布的,但将这两个类放在单独的包中似乎有点愚蠢。
  • 为什么?我无法回答实现 Java 的人在想什么,或者告诉你理由是什么。但我可以指出,它们不是同时实施的。有人提出了一个足够强大的案例来将 Iterable 放入 java.lang。我们将不得不等待做出决定的人告诉我们;其余的都是猜测。
【解决方案2】:

java.lang 保留给作为语言特性依赖项的类。 Iterable 直接通过 for-each 循环提供语言级别支持,但 Iterator 没有。

【讨论】:

  • 这是事后合理化吗?并没有真正挑战答案,但这没有多大意义:java.util.HashMap 还具有“直接语言级别支持”。我一直认为最初的 JDK 包有很多设计错误,这些错误逐渐得到纠正。因此,OP 的 Q 将由“由于历史遗留原因”来回答。
  • HashMap 有哪些直接语言级别的支持?
  • @alpha:是的,我不太确定你是从哪里来的。有一些语法特别依赖于Iterable。据我所知,没有哪个取决于Map。至少,不是在 Java 7 之前。
  • for-each 循环的“语言级别支持”是否编译为使用迭代器?我一直是这么想的。 (请参阅我的问题的编辑)
  • @tskuzzy:我想是这样,javap 可以帮助仔细检查。其他回答者在历史开始发挥作用时是正确的......它可能Iterator添加到java.lang以及它在java.util之前不存在于for-每个循环的介绍。
【解决方案3】:

大多数集合都实现了Iterable,以便您可以使用方便的 for 循环语法:

Iterable<T> someIterableThing;
for (T x : someIterableThing) { ... }

我想Iterablejava.lang 中,因为它与这种语法密切相关,这是Java 语言的一个特性。

【讨论】:

  • Iterator 没有实现 Iterable(但每个 Iterable 都通过其 iterator() 方法提供了一个 Iterator。
  • 嗯...好的,我会调整答案以删除有问题的文本。
  • 很好的观察!然而,for-each 循环是否等同于使用迭代器? (请参阅我的问题的编辑)
  • @Jeremy,我也怀疑这是他们推理的一部分,但恕我直言,它不成立。毕竟,在迭代 Iterable 的情况下,最终还是需要一个 java.util 迭代器。间接性只是把事情扫到地毯下。
  • 好吧,那部分可能是历史的,因为如果我没记错的话java.util.Iterator 早于java.lang.Iterable 和for-each 循环语法。如果它们是同时创建的,我想 Iterator 最终会出现在 java.lang 包中。
【解决方案4】:

随着时间的推移,Java 的java.* 子包开发了各种循环依赖项。例如,

  1. java.lang.Process -- java.io
  2. java.lang.Readable -- java.io, java.nio
  3. java.lang.String -- java.util
  4. java.lang.System -- java.io、java.nio、java.util

所以我认为最好不要将子包视为一种明确分层依赖关系的机制。相反,子包组相关的特殊行为(除了包罗万象的util)和lang 选择性地引入一些非常有用的结构,例如IteratorLocale

我想人们也可以将其全部归结为熵。

【讨论】:

    【解决方案5】:

    回答附加问题:

    增强的 for 循环有两种变体。其中之一,当collection 参数在

    for(E o : collection) {
        ...
    }
    

    是实现Iterable&lt;E&gt;的东西,完全等价于

    for (Iterator<E> iter = collection.iterator(); iter.hasNext(); ) {
        E o = iter.next();
        ...
    }
    

    (不同的是,迭代器没有您可以在循环的其余部分访问的变量名)。编译器将为每个版本生成非常相似甚至完全相同的代码。

    增强的for 循环还有另一个变体:当collection 是一个数组时,它会被编译成这样的:

    E[] a = collection;
    for(int i = 0; i < a.length; i++) {
        E o = a[i];
        ...
    }
    

    (当然,这里我们也不能直接访问ai。)

    顺便说一句,编译器不会导入 java.util.Iterator - 在编译的字节码中,每种类型都由其全名引用。 (无论如何,局部变量并没有真正键入 - 其他一些 checkcast 断言。)

    【讨论】:

      猜你喜欢
      • 2013-10-13
      • 2022-06-20
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 2011-12-22
      • 1970-01-01
      • 2014-03-24
      相关资源
      最近更新 更多