在Java中安全地遍历原始迭代器?

时间:2010-09-14 20:30:08

标签: java generics iterator types

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

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

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

@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块中捕获/记录异常,我正在寻找(希望)Java语言等同于ColinD在下面提到的内容。

4 个答案:

答案 0 :(得分:7)

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

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

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

答案 1 :(得分:2)

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

如果您静静地跳过不是预期类型的​​元素,那么您可能会错过所需的数据,这对我来说听起来不是一个好方法。

答案 2 :(得分:2)

您的上一个版本似乎是要走的路,但我想我们可以改进一下:

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);
}

答案 3 :(得分:1)

因为听起来你想要停止执行并且如果遇到迭代器返回的对象(不是ActualObject的实例)就抛出异常,那么我只是强制转换它,并且有一个catch块来处理可能的ClassCastException