Java-итератор над пустой коллекцией параметризованного типа

StackOverflow https://stackoverflow.com/questions/821536

  •  03-07-2019
  •  | 
  •  

Вопрос

В Java мне нужно вернуть Iterator из моего метода. Мои данные поступают из другого объекта, который обычно может дать мне итератор, поэтому я могу просто вернуть его, но в некоторых случаях базовые данные равны нулю. Для согласованности я хочу вернуть & Quot; empty & Quot; итератор в этом случае, так что мои абоненты не должны проверять на ноль.

Я хотел написать что-то вроде:

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

Но компилятор Java жалуется на возвращение Iterator<Object> вместо Iterator<Foo>. Приведение к (Iterator<Foo>) тоже не работает.

Это было полезно?

Решение

Вы можете получить пустой список типа Foo с помощью следующего синтаксиса:

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

Другие советы

Java 7 уже давно отсутствует. Если вы не разрабатываете для предыдущей версии Java, вы бы вернули пустой итератор, например так:

return Collections.emptyIterator();

Я бы пошел по пути

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

Просто обработайте специальный случай и вернитесь, затем обработайте обычный случай. Но главное, что вы можете избежать назначения с помощью

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

Раздражение Collections.<Foo>emptyList().iterator() - это основная причина, по которой мы предоставляем Iterators.emptyIterator() в google-collection . , В таких случаях, как ваш, параметр типа не требуется.

Я предполагаю, что это показывает, что вывод типа Java не работает в каждом случае и что троичный оператор не всегда эквивалентен явно эквивалентной конструкции if-else.

Я также хочу указать избегать null . Также избегайте прохождения Iterator, потому что у них странное поведение с состоянием (предпочитайте Iterable). Однако, если у вас есть законные, преждевременные причины для этого, мой предпочтительный способ написать это будет

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

IMO, лучше не вставлять информацию о заменимом типе, если она может быть выведена (даже если это делает ваш код длиннее).

Вы почти наверняка сделаете это несколько раз, поэтому вставьте метод getUnderlyingData вместо простого объявления локальной переменной.

Вы звоните iterator по обоим результатам, поэтому не повторяйте себя.

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

public Iterator<Foo> iterator() {
   if (underlyingData != null) {
      return underlyingData.iterator();
   } else {
      List<Foo> empty = Collections.emptyList();  // param type inference
      return empty.iterator();
   }
}
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(){
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top