Безопасное прохождение необработанного итератора в Java?

Я использую стороннюю библиотеку, которая возвращает необработанный итератор, например

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

это кажется слишком многословно. Есть ли лучший, но не менее "безопасный" способ прохождения необработанного итератора?

EDIT: я понимаю, что могу поймать/зарегистрировать исключение в блоке else, я искал (надеялся) эквивалент языка Java того, что Колинд упомянул ниже.

4 ответов


гуавы делает это легко с итераторы.фильтр (итератор> , Класс) метод. Возвращает неподдающееся изменению Iterator<T> это в основном просто пропускает каждый элемент данного итератора, который не является экземпляром типа T:

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

вы можете, очевидно, затем пересечь результирующий итератор без необходимости приведения каждого элемента к ActualObject и без необходимости беспокоиться о ClassCastException.


простой способ справиться с этим-просто бросить его и убедиться, что, если тип изменится от того, что вы ожидаете в будущем, будет брошено исключение, и вы будете уведомлены. Вы захотите проверить, что, однако, вы регистрируете исключения, и исключение найдет свой путь к файлу журнала. Исключения существуют для того, чтобы сказать вам, что что-то не то, что вы ожидаете, пусть они делают свою работу.

Если вы молча пропускаете элементы, которые не являются ожидаемым типом, вы можете быть пропущенные данные, которые вам нужны, это не похоже на хорошее решение для меня.


ваша последняя версия кажется, как путь, но я думаю, что мы можем улучшить это немного:

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

что я бы сказал не так уж плохо.

Edit:

вероятно, под блоком if также должен быть блок else. Что-то вроде:

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

поскольку похоже, что вы хотите остановить выполнение и создать исключение, если вы столкнулись с объектом, возвращаемым итератором, который не является экземпляром ActualObject, тогда я бы просто бросил его, и у меня есть блок catch, чтобы иметь дело с возможным ClassCastException.