Почему java.util.Set не имеет get (int index)? - PullRequest
227 голосов
/ 20 апреля 2009

Я уверен, что есть веская причина, но кто-то может объяснить, почему в интерфейсе java.util.Set отсутствует get(int Index) или какой-либо подобный метод get()?

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

Если я знаю, что хочу первый элемент, я могу использовать set.iterator().next(), но в противном случае мне кажется, что я должен привести к массиву, чтобы получить элемент по определенному индексу?

Каковы подходящие способы извлечения данных из набора? (кроме использования итератора)

Я уверен, что тот факт, что он исключен из API, означает, что есть веская причина не делать этого - может кто-нибудь, пожалуйста, просветите меня?

EDIT: Некоторые очень хорошие ответы здесь, а некоторые говорят «больше контекста». Конкретным сценарием был тест dbUnit, в котором я мог разумно утверждать, что возвращенный набор из запроса имел только 1 элемент, и я пытался получить доступ к этому элементу.

Однако вопрос более актуален без сценария, поскольку он остается более сфокусированным:

В чем разница между множеством и списком .

Спасибо всем за фантастические ответы ниже.

Ответы [ 18 ]

171 голосов
/ 20 апреля 2009

Потому что у наборов нет порядка. Некоторые реализации делают это (особенно те, которые реализуют интерфейс java.util.SortedSet), но это не является общим свойством множеств.

Если вы пытаетесь использовать наборы таким образом, вам следует рассмотреть возможность использования списка.

73 голосов
/ 30 мая 2010

На самом деле это повторяющийся вопрос при написании приложений JavaEE, которые используют объектно-реляционное сопоставление (например, с Hibernate); и из всех людей, которые ответили здесь, Андреас Петерссон - единственный, кто понял реальную проблему и предложил правильный ответ на нее: Java пропускает UniqueList! (или вы также можете назвать его OrderedSet или IndexedSet).

Максвинг упомянул этот вариант использования (в котором вам нужны упорядоченные И уникальные данные) и предложил SortedSet, но это не то, что Марти Питт действительно нуждался.

Этот "IndexedSet" НЕ совпадает с SortedSet - в SortedSet элементы сортируются с использованием Comparator (или с использованием их "естественного" порядка).

Но вместо этого он ближе к LinkedHashSet (который также предлагали другие) или даже к (также несуществующему) "ArrayListSet", поскольку он гарантирует, что элементы возвращаются в том же порядке, в котором они были вставлены. 1007 *

Но LinkedHashSet - это реализация, а не интерфейс! Необходим интерфейс IndexedSet (или ListSet, или OrderedSet, или UniqueList)! Это позволит программисту указать, что ему нужна коллекция элементов с определенным порядком и без дубликатов, а затем создать его экземпляр для любой реализации (например, реализации, предоставляемой Hibernate).

Поскольку JDK с открытым исходным кодом, возможно, этот интерфейс будет окончательно включен в Java 7 ...

28 голосов
/ 20 апреля 2009

Просто добавив одну точку, которая не была упомянута в ответе mmyers .

Если я знаю, что хочу первый предмет, я могу используйте set.iterator (). next (), но в противном случае кажется, что я должен бросить массив для извлечения элемента в удельный индекс?

Каковы подходящие способы извлекать данные из набора? (Другой чем с помощью итератора)

Вам также следует ознакомиться с интерфейсом SortedSet (наиболее распространенной реализацией которого является TreeSet).

SortedSet - это Набор (то есть элементы уникальны), который упорядочен с помощью естественного порядка элементов или с использованием некоторого Comparator. Вы можете легко получить доступ к первым и последним элементам, используя методы first() и last(). SortedSet пригодится время от времени, когда вам нужно хранить свою коллекцию без дубликатов и заказывать определенным образом.

Редактировать : Если вам нужен набор, элементы которого хранятся в порядке вставки (очень похоже на список), посмотрите на LinkedHashSet.

24 голосов
/ 21 апреля 2009

Этот тип приводит к вопросу, когда вы должны использовать набор и когда вы должны использовать список. Обычно совет идет:

  1. Если вам нужны заказанные данные, используйте Список
  2. Если вам нужны уникальные данные, используйте набор
  3. Если вам нужны оба варианта, используйте: SortedSet (для данных, упорядоченных компаратором) или OrderedSet / UniqueList (для данных, упорядоченных путем вставки). К сожалению, Java API еще не имеет OrderedSet / UniqueList.

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

17 голосов
/ 21 апреля 2009

Я не уверен, что кто-то написал это именно так, но вам нужно понять следующее:

В наборе нет "первого" элемента.

Потому что, как говорили другие, декорации не имеют порядка. Набор - это математическая концепция, которая конкретно не включает упорядочение.

Конечно, ваш компьютер не может хранить список вещей, которые не упорядочены в памяти. Это должно иметь некоторый порядок. Внутренне это массив или связанный список или что-то. Но вы на самом деле не знаете, что это такое, и у него нет первого элемента; элемент, который выходит «первым», появляется таким образом случайно и может быть не первым в следующий раз. Даже если вы предприняли шаги, чтобы «гарантировать» конкретный первый элемент, он все-таки вышел случайно, потому что вы просто получили его правильно для одной конкретной реализации набора; другая реализация может не работать таким образом с тем, что вы сделали. И, на самом деле, вы можете не знать, какую реализацию вы используете, так, как вы думаете.

Люди сталкиваются с этим ВСЕМ. . ВРЕМЯ. с системами RDBMS и не понимаю. Запрос RDBMS возвращает набор записей. Это тот же тип набора из математики: неупорядоченный набор элементов, только в этом случае элементы являются записями. Результат запроса СУБД вообще не имеет гарантированного порядка, если только вы не используете предложение ORDER BY, но все время люди предполагают, что он это делает, а затем когда-нибудь теряют самообладание, когда форма их данных или кода слегка меняется и запускает работу оптимизатора запросов другой путь, и внезапно результаты оказываются не в том порядке, в котором они ожидают. Как правило, это люди, которые не обращали внимания в классе базы данных (или при чтении документации или учебных пособий), когда им заранее объясняли, что результаты запроса не имеют гарантированного порядка.

10 голосов
/ 28 апреля 2009

некоторые структуры данных отсутствуют в стандартных коллекциях Java.

Сумка (как набор, но может содержать элементы несколько раз)

UniqueList (упорядоченный список, может содержать каждый элемент только один раз)

кажется, что в этом случае вам нужен уникальный список

если вам нужны гибкие структуры данных, вас могут заинтересовать Google Collections

7 голосов
/ 07 января 2011

Если вы собираетесь делать множество случайных обращений по индексу в наборе, вы можете получить представление массива его элементов:

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]

Есть два основных недостатка:

  1. Это не эффективно для памяти, так как необходимо создать массив для всего набора.
  2. Если набор изменен, вид становится устаревшим.
7 голосов
/ 19 января 2010

Это правда, элементы в наборе не упорядочены по определению коллекции множеств. Таким образом, они не могут быть доступны по индексу.

Но почему у нас нет метода get (object), не предоставляя индекс в качестве параметра, а объект, который равен искомому? Таким образом, мы можем получить доступ к данным элемента внутри набора, просто зная его атрибуты, используемые равным методом.

5 голосов
/ 20 апреля 2009

Это потому, что Set гарантирует только уникальность, но ничего не говорит об оптимальных моделях доступа или использования. То есть набор может быть списком или картой, каждая из которых имеет очень разные характеристики поиска.

5 голосов
/ 21 апреля 2009

Единственная причина, по которой я могу использовать числовой индекс в наборе, - это итерация. Для этого используйте

for(A a : set) { 
   visit(a); 
}
...