Безопасно обходить необработанный итератор в Java? - PullRequest
7 голосов
/ 15 сентября 2010

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

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 ]

7 голосов
/ 15 сентября 2010

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

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

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

2 голосов
/ 15 сентября 2010

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

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);
}
2 голосов
/ 15 сентября 2010

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

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

1 голос
/ 15 сентября 2010

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

...