Когда я должен принимать параметр 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();
          ...
      }
  }

Если вы получили Итератор вместо Коллекция, вы не уверены, принадлежит ли ваш поток этому объекту.