Когда я должен принимать параметр Iterable <T> vs. Collection <T> в Java?
Каковы соображения использования Iterable<T>
vs. Collection<T>
в Java?
Например, рассмотрим реализацию типа, который в первую очередь связан с содержимым набора Foo
s и некоторых связанных метаданных. Конструктор этого типа допускает однократную инициализацию списка объектов. (Метаданные могут быть установлены позже.) Какой тип должен принять этот конструктор? Iterable<Foo>
или Collection<Foo>
?
Каковы соображения для этого решения?
Следуя шаблону, заданному типами библиотек, такими как ArrayList
(который может быть инициализирован из любого Collection
, но не Iterable
), я мог бы использовать Collection<Foo>
.
Но почему бы не принять Iterable<Foo>
, учитывая, что этого достаточно для нужд инициализации? Зачем требовать от потребителя более высокий уровень функциональности (Collection
), чем это необходимо (Iterable
)?
Ответы
Ответ 1
Многие типы коллекций существовали до Iterable<T>
(который был введен только в 1.5) - было мало оснований добавлять конструктор для принятия Iterable<T>
, а также Collection<T>
, но изменение существующего конструктора было бы нарушение изменения.
Лично я бы использовал Iterable<T>
, если это позволяет вам делать все, что вы хотите. Он более гибкий для абонентов и, в частности, позволяет вам относительно легко фильтровать/проектировать/и т.д., Используя коллекцию Google Java (и, без сомнения, подобные библиотеки).
Ответ 2
An Iterable
создает объекты Iterator
. Объект Iterator
, по определению, выполняет итерацию. Обратите внимание, что интерфейс Iterator
не дает никаких обещаний относительно того, сколько раз next()
можно вызвать до hasNext()
возвращает false
. Iterator
мог бы перебирать значения Integer.MAX_VALUE + 1
до того, как метод hasNext()
возвращает false
.
Однако a Collection
является специальной формой Iterable
. Поскольку Collection
не может иметь больше, чем Integer.MAX_VALUE
элементов (в силу метода size()
), естественно предположить, что его объекты Iterator
не будут перебирать эти много элементов.
Поэтому, приняв Collection
, а не Iterable
, ваш класс может получить некоторую гарантию того, сколько элементов передано. Это особенно желательно, если ваш класс сам является Collection
.
Только мои два цента...
Ответ 3
Используйте наиболее общий интерфейс, который вы можете использовать. Поскольку все, что вы собираетесь делать, это итерация, тогда я бы сказал, что Iterable
- это путь (поскольку он позволяет ленивые итераторы и т.д.). Вам все равно, откуда итератор, поэтому не ограничивайте его больше, чем вам нужно.
Ответ 4
Пользователи Spring Data JPA
найдут, что возвратные коллекции Repositories
типа Iterable<T>.
В проектах, над которыми я работал в прошлом, которые используют Spring
, я обнаружил, что необходимость работы с коллекцией после извлечения часто диктует, что используется в бизнес-слое, а не Collection<T>
, чтобы выбрать объект T
из коллекции.
Все коллекции Iterable
(это интерфейсы, расширяющие интерфейс Collection
, поэтому не Map
!), поэтому использование Iterable
в бизнес-уровне - это просто случай обращения к коллекции по ее супер-тип и по-прежнему позволяет использовать for-each
для итерации.
Если вам нужно манипулировать содержимым коллекции, метод удобства позволит вам заполнить новый Collection
, чтобы вы могли использовать contains()
, remove()
и т.д. с исходными данными коллекции.
В качестве альтернативы, для этой цели предусмотрены удобные методы использования популярных сторонних API, таких как Google Guava и Apache Commons.
Ответ 5
Некоторые конструкторы, например. ArrayList (Collection c), используйте метод toArray() Collection для эффективности.
Ответ 6
См. "Почему так много внимания на Итераторах и Итераторах?" на Часто задаваемые вопросы по Google Collection
для достойного аргумента для предпочтения Итераторов, особенно при работе с большим количеством данных. Одна из аналогий, которая может помочь, - это различие между курсорами только для чтения и прокручиваемыми курсорами.
Ответ 7
Если вы отправитесь в коллекцию, то ваш класс может быть инициализирован только из коллекции, если вы перейдете на Iterable, тогда вы можете инициализировать либо из коллекции, либо из итерации.
Поскольку усилие и производительность для обоих будет одинаковой, то имеет смысл принимать Iterable в конструкторе.
Ответ 8
В соответствии с принципом наименьшего удивления вы должны эмулировать шаблон коллекции Java и принять конструктор конструктора Collection. Это заставит людей, которые приходят после вас чуть менее озадаченно.
Ответ 9
Вы правы, так как считали хорошей практикой просить самую общую форму того, что вам нужно.
Ответ 10
Как насчет синхронизации? Если вы собираетесь перебирать коллекцию, вам нужно получить блокировку, прежде чем получить итератор.
synchronized(myList) {
Iterator iter = myList.iterator();
while (iter.hasNext()) {
iter.next();
...
}
}
Если вы получили Итератор вместо Коллекция, вы не уверены, принадлежит ли ваш поток этому объекту.