Содержат ли containsAll() и retainAll () в интерфейсе коллекции адресную мощность?


В Java containsAll и retainAll в классе AbstractCollection явно указывают, что кардинальность не соблюдается, поэтому, другими словами, не имеет значения, сколько экземпляров значения находятся на каждой стороне. Поскольку все коллекции Java в стандартной библиотеке расширяют AbstractCollection, предполагается, что все они работают одинаково.

Однако документация этих методов в интерфейсе коллекции ничего не говорит. Предполагается ли выводить из абстрактного сбора, или это было оставлено неопределенным специально, чтобы можно было определить коллекции, которые работают по-разному?

Например, Bag в apache-collections явно заявляет, что он уважает кардинальность, и утверждает, что он нарушает контракт версии из коллекции (хотя на самом деле это не так).

Итак, какова семантика этих операций в коллекции, а не в абстрактном сборе?

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

2 2

2 ответа:

Javadocs для containsAll (в коллекции) говорят:

Возвращает: true, если эта коллекция содержит все элементы в указанная коллекция

И для retainAll (в коллекции):

Сохраняет только элементы в этом коллекции, которые содержатся в указанная коллекция (необязательно операция). Другими словами, удаляет из этой коллекции все свои элементы, которые не содержатся в указанный коллекция.

Я прочитал контракт containsAll, означающий, что вызов a. containsAll (b) вернет true, если и только если вызов a.contains(bElem) для каждого элемента bElem в b вернет true. Я также хотел взять его, чтобы подразумевать, что.containsAll(someEmptyCollection) также будет возвращать значение true. По мере того, как вы устанавливаете javadocs для AbstractCollection, более явно укажите это:

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

Я согласен, что контакт для сбора для containsAll должен быть более явным, чтобы избежать любой возможной путаницы. (И что чтение javadocs для AbstractCollection не должно было быть необходимым для подтверждения понимания коллекции)

Я бы не сделал предположения относительно количества дубликатов элементы после вызова retainAll. Указанный контракт в коллекции (по моему прочтению) не подразумевает, каким образом будут обрабатываться дубликаты в любой коллекции. Основываясь на моем прочтении retainAll в сборнике, все возможные результаты a. retainAll (b) являются разумными:

  1. результат содержит 1 из каждого элемента, который имеет по крайней мере одну копию как в a, так и в
  2. результат содержит каждый элемент (включая дубликаты), который был в a, за исключением тех, которые не находятся в b
  3. или даже, результат содержит где-то между 1 и количеством копий, найденных в a каждого элемента в a, за исключением тех, которые не находятся в b. Я ожидал бы либо № 1, либо № 2, но предположил бы, что любой из этих трех будет законным на основании контракта.

Javadocs для AbstractCollection подтверждают, что он использует #2:

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

Хотя, поскольку это не входит в мое чтение контракта исходного интерфейса коллекции, я не обязательно предполагаю, что поведение коллекции в целом будет таким.

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

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

Я не думаю, что Collection определяет его так или иначе, но это просто стало своего рода соглашением, чтобы следовать поведению AbstractCollection, например google-collections do: see their Multiset documentation (Multiset-это то, что они называют сумкой)