【问题标题】:Safely traversing a raw Iterator in Java?在 Java 中安全地遍历原始迭代器?
【发布时间】:2010-09-14 20:30:08
【问题描述】:

我正在使用返回原始迭代器的第三方库,例如

Iterator<?> children = element.getChildElements();

我知道实际的类型,但我不一定相信第三方库将来会坚持使用它。有两种(我能想到的)有点冒险的方法来遍历它:

@SuppressWarnings("unchecked")
Iterator<ActualObject> currentChildren = (Iterator<ActualObject>)currentElement.getChildElements();

Iterator<?> children = element.getChildElements();
while (null != children && children.hasNext()) {
  ActualObject child = (ActualObject)children.next(); //Possible ClassCastException @ runtime
  ...
}

我能想到的唯一“安全”的遍历这种迭代器的方法如下:

Iterator<?> children = element.getChildElements();
while (null != children && children.hasNext()) {
  Object obj = children.next();
  ActualObject child = null;
    if (obj instanceof ActualObject)
      child = (ActualObject)obj;
    ...
}

这似乎过于冗长。是否有更好但同样“安全”的方式来遍历原始迭代器?

编辑:我意识到我可以在 else 块中捕获/记录异常,我正在寻找(希望)与下面提到的 ColinD 等效的 Java 语言。

【问题讨论】:

  • 如果迭代器返回的对象不是 ActualObject的实例,你想发生什么?
  • child的类型不是ActualObject怎么办?如果您不需要继续,我认为捕获 ClassCastException 可能是最干净的方法。您可以记录类型不匹配并继续。
  • @pkaeding & @Gangadhar - 我会抛出异常。
  • Guava 方法(就像 Guava 中的许多东西一样)的存在是为了让在核心 Java 中做一些相当冗长的事情变得更容易和更简洁,所以我不希望在 JDK 中找到任何等效的东西.

标签: java generics iterator types


【解决方案1】:

Guava 使用其Iterators.filter(Iterator<?>, Class<T>) 方法使这变得简单。它返回一个不可修改的Iterator&lt;T&gt;,它基本上只是跳过给定迭代器中不是T类型实例的每个元素:

Iterator<ActualObject> children = Iterators.filter(element.getChildElements(),
    ActualObject.class);

您显然可以遍历生成的迭代器,而无需将每个元素强制转换为 ActualObject AND 而不必担心 ClassCastException

【讨论】:

  • 谢谢,这很有趣,但不幸的是,我不适合使用 Guava。
  • @Segphault:然后阅读源代码并检查他们是如何做到的。
  • 我怀疑他们做了和你上一个例子一样的事情,但只是将它提取到一个包装器对象中。
  • 是的,它确实与第二个示例有效地做同样的事情,尽管它建立在它们的谓词/过滤代码的其余部分之上。
【解决方案2】:

处理它的简单方法是强制转换它并确保如果类型在未来发生变化,则会引发异常并通知您。您将需要检查您记录异常的方式是否有效,并且异常会找到日志文件的方式。存在例外是为了告诉您某些事情不是您所期望的,让他们完成他们的工作。

如果您默默地跳过不是预期类型的​​元素,那么您可能会丢失所需的数据,这对我来说不是一个好的解决方案。

【讨论】:

    【解决方案3】:

    您的上一个版本似乎是可行的方法,但我想我们可以改进一下:

    Iterator<?> children = element.getChildElements();
    // no null check needed. If an api that supposedly
    // returns an iterator actually returns null, it's a bad
    // API, don't use it
    while (children.hasNext()) {
        Object obj = children.next();
        if (obj instanceof ActualObject)
            doStuffWith((ActualObject)obj);
        // we know it's of the right type so we might
        // as well put the cast in the method call.
    }
    

    所以归结为:

    Iterator<?> children = element.getChildElements();
    while (children.hasNext()) {
        Object obj = children.next();
        if (obj instanceof ActualObject)
            doStuffWith((ActualObject)obj);
    }
    

    我会说这还不错。

    编辑:

    if 块下面也应该有一个 else 块。 大致如下:

    else{
        log.warn("Expected type: " + ActualObject.class + ", but got " + obj);
    }
    

    【讨论】:

    • 您对空检查是正确的,我将删除它。这是一个糟糕的 API,其方式比问题所证明的要多。我迫不及待地不想再使用它了。
    【解决方案4】:

    如果遇到不是ActualObject 实例的迭代器返回的对象,听起来您想停止执行并抛出异常,那么我将对其进行强制转换,并有一个catch 块来处理可能的ClassCastException

    【讨论】:

      猜你喜欢
      • 2012-10-22
      • 1970-01-01
      • 2016-09-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多