Ответ 1
Вы можете получить пустой список типов Foo через следующий синтаксис:
return Collections.<Foo>emptyList().iterator();
В Java мне нужно вернуть Iterator из моего метода. Мои данные поступают из другого объекта, который обычно может дать мне итератор, поэтому я могу просто вернуть его, но в некоторых случаях базовые данные равны нулю. Для согласованности я хочу вернуть "пустой" итератор в этом случае, чтобы мои вызывающие лица не тестировали значение null.
Я хотел написать что-то вроде:
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-collections. Никакой параметр типа не нужен, в таких случаях, как ваш.
Я предполагаю, что это показывает, что вывод типа 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, лучше не вставлять информацию типа inferable, если она может быть выведена (даже если это делает ваш код длиннее).
Вы почти наверняка будете делать это несколько раз, поэтому вставьте метод 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(){
}
}
}