Содержат ли containsAll() и retainAll () в интерфейсе коллекции адресную мощность?
В Java containsAll и retainAll в классе AbstractCollection явно указывают, что кардинальность не соблюдается, поэтому, другими словами, не имеет значения, сколько экземпляров значения находятся на каждой стороне. Поскольку все коллекции Java в стандартной библиотеке расширяют AbstractCollection, предполагается, что все они работают одинаково.
Однако документация этих методов в интерфейсе коллекции ничего не говорит. Предполагается ли выводить из абстрактного сбора, или это было оставлено неопределенным специально, чтобы можно было определить коллекции, которые работают по-разному?
Например, Bag в apache-collections явно заявляет, что он уважает кардинальность, и утверждает, что он нарушает контракт версии из коллекции (хотя на самом деле это не так).
Итак, какова семантика этих операций в коллекции, а не в абстрактном сборе?
Edit: те, кто интересуется, почему меня это волнует, это потому, что как часть моей докторской работы я продемонстрировал, что разработчики не ожидают нарушения соответствия в Apache, но я пытаюсь понять, почему интерфейс коллекции был оставлен таким неоднозначным.
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 из каждого элемента, который имеет по крайней мере одну копию как в a, так и в
- результат содержит каждый элемент (включая дубликаты), который был в a, за исключением тех, которые не находятся в b
- или даже, результат содержит где-то между 1 и количеством копий, найденных в a каждого элемента в a, за исключением тех, которые не находятся в b. Я ожидал бы либо № 1, либо № 2, но предположил бы, что любой из этих трех будет законным на основании контракта.
Javadocs для AbstractCollection подтверждают, что он использует #2:
Эта реализация повторяет это сбор, проверка каждого элемента возвращается итератором в свою очередь к смотрите, содержится ли он в указанном коллекция. Если это не так сдержанно, он удален из этой коллекции с помощью метод удаления итератора
Хотя, поскольку это не входит в мое чтение контракта исходного интерфейса коллекции, я не обязательно предполагаю, что поведение коллекции в целом будет таким.
Возможно, вам следует рассмотреть возможность отправки предложенных обновлений в JavaDoc, как только вы закончите.
Что касается "почему интерфейс коллекции был оставлен таким неоднозначным" - я серьезно сомневаюсь, что это было сделано намеренно - вероятно, просто что-то, чему не был дан должный приоритет, когда эта часть API была написана.
Я не думаю, что Collection определяет его так или иначе, но это просто стало своего рода соглашением, чтобы следовать поведению AbstractCollection, например google-collections do: see their Multiset documentation (Multiset-это то, что они называют сумкой)