【问题标题】:Java iterator over an empty collection of a parameterized type参数化类型的空集合上的 Java 迭代器
【发布时间】:2010-10-23 17:17:21
【问题描述】:

在 Java 中,我需要从我的方法中返回一个迭代器。我的数据来自另一个对象,它通常可以给我一个迭代器,所以我可以返回它,但在某些情况下,基础数据为空。为了保持一致性,我想在这种情况下返回一个“空”迭代器,这样我的调用者就不必测试 null。

我想写这样的东西:

public Iterator<Foo> iterator() {
   if (underlyingData != null) {
      return underlyingData.iterator();  // works
   } else {
      return Collections.emptyList().iterator();  // compiler error
   }
}

但是 Java 编译器抱怨返回 Iterator&lt;Object&gt; 而不是 Iterator&lt;Foo&gt;。投射到 (Iterator&lt;Foo&gt;) 也不起作用。

【问题讨论】:

    标签: java collections iterator


    【解决方案1】:

    你可以通过下面的语法得到一个Foo类型的空列表:

    return Collections.<Foo>emptyList().iterator();
    

    【讨论】:

    • 我刚刚发现,有时试图快点会让你慢下来。我写了一个空的 Iterator 实现,然后回到这里发现我已经走上了一条小路。 +1
    • 在 Java 1.7 Collections API 中扩展了 Collections.emptyIterator()
    【解决方案2】:

    对不起,我想通了。您需要使用赋值,以便编译器可以确定参数化类型。

    public Iterator<Foo> iterator() {
       if (underlyingData != null) {
          return underlyingData.iterator();
       } else {
          List<Foo> empty = Collections.emptyList();  // param type inference
          return empty.iterator();
       }
    }
    

    【讨论】:

    • 哇,亚历克斯 B 甚至在我输入我的解决方案之前就回答了。我缺少由 emptyList() 返回的参数化类型的语法。任务有效,但一个班轮更好。
    【解决方案3】:

    我会更倾向于

    public Iterator<Foo> iterator() {
        if (underlyingData == null)
            return Collections.<Foo> emptyList().iterator();
        return underlyingData.iterator();
    }
    

    只是,处理特殊情况并返回,然后处理正常情况。但我的主要观点是,你可以避免分配与

    Collections.<Foo> emptyList().iterator();
    

    【讨论】:

    • IMO,null 和 non-null 在这种情况下同样特殊。 else 在这里更清楚。
    • 当然,您有权使用 YO,但在我看来,这个类似乎正在处理所有列表,包括空列表,就好像(这个类)是列表 - 这是正常的流,对我来说——但它特别对待 null——就好像它是空列表一样,但事实并非如此。它正常地委托给底层数据,并在不能时制造一些特殊的东西。
    • @DJClayworth,您也有权使用 YO。我认为不必要的大括号是代码垃圾。 slideshare.net/carlmanaster/codejunk-ignitesd
    【解决方案4】:

    我想这表明 Java 类型推断并非在所有情况下都有效,并且三元运算符并不总是等价于表面上等价的 if-else 构造。

    我还想声明避免使用null。还要避免传递Iterators about,因为它们有奇怪的状态行为(更喜欢Iterable)。然而,假设你有一个合法的、非过早的理由这样做,我首选的写作方式是

    public Iterator<Foo> iterator() {
        return getUnderlyingData().iterator();
    }
    private List<Foo> getUnderlyingData() {
        if (underlyingData == null) {
            return Collections.emptyList();
        } else {
            return underlyingData;
        }
    }
    

    IMO,如果可以推断,最好不要插入可推断类型信息(即使它使您的代码更长)。

    您几乎肯定会不止一次这样做,因此插入一个getUnderlyingData 方法而不是仅仅声明一个局部变量。

    你在两个结果上都调用iterator,所以不要重复你自己。

    【讨论】:

    • +1 因为只从一个地方调用 iterator() 而获得 DRY 胜利。我想知道这种解决方案是否可以移动到修改基础数据的地方 - 我认为这将是最干燥的。
    【解决方案5】:

    Collections.&lt;Foo&gt;emptyList().iterator() 的烦恼是我们在google-collections 中提供Iterators.emptyIterator() 的主要原因。在像您这样的情况下,不需要类型参数。

    【讨论】:

      【解决方案6】:
      public  final class EmptyIterator{
      
          public static Iterator iterator(){
              return new Empty();
          }
      
          private static class Empty implements Iterator {
              public boolean hasNext(){
                  return false;
              }
              public Object next(){
                  throw new NoSuchElementException();
              }
              public void remove(){
              }
          }
      }
      

      【讨论】:

      • 有一个内置的迭代器可以做同样的事情:Collections.emptyIterator();.
      【解决方案7】:

      Java 7 已经推出很长时间了。除非您正在为以前的 Java 版本进行开发,否则您将返回一个空迭代器,如下所示:

      return Collections.emptyIterator();
      

      【讨论】:

      • 你也可以参数化你的空迭代器:Collections.&lt;Integer&gt; emptyIterator()
      猜你喜欢
      • 2017-04-11
      • 2012-07-07
      • 2016-02-27
      • 1970-01-01
      • 2017-12-08
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      • 1970-01-01
      相关资源
      最近更新 更多