View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4;
18  
19  import java.util.Collection;
20  import java.util.Iterator;
21  import java.util.Set;
22  
23  /**
24   * Defines a collection that counts the number of times an object appears in
25   * the collection.
26   * <p>
27   * Suppose you have a Bag that contains {@code {a, a, b, c}}.
28   * Calling {@link #getCount(Object)} on {@code a} would return 2, while
29   * calling {@link #uniqueSet()} would return {@code {a, b, c}}.
30   * </p>
31   * <p>
32   * <em>NOTE: This interface violates the {@link Collection} contract.</em>
33   * The behavior specified in many of these methods is <em>not</em> the same
34   * as the behavior specified by {@code Collection}.
35   * The non-compliant methods are clearly marked with "(Violation)".
36   * Exercise caution when using a bag as a {@code Collection}.
37   * </p>
38   * <p>
39   * This violation resulted from the original specification of this interface.
40   * In an ideal world, the interface would be changed to fix the problems, however
41   * it has been decided to maintain backwards compatibility instead.
42   * </p>
43   * <p>
44   * The {@link MultiSet} interface, added in version 4.1, provides the same
45   * functionality while complying with the {@link Collection} contract, and
46   * should be preferred for new code. Existing code can migrate as follows,
47   * with the cardinality-respecting behavior preserved through explicitly
48   * named methods:
49   * </p>
50   * <ul>
51   *   <li>{@code bag.add(e)} becomes {@code multiSet.add(e)}
52   *       (which always returns {@code true}, per the {@code MultiSet} contract)</li>
53   *   <li>{@code bag.getCount(e)} becomes {@code multiSet.getCount(e)}</li>
54   *   <li>{@code bag.remove(e)}, which removes all copies, becomes
55   *       {@code multiSet.setCount(e, 0)}</li>
56   *   <li>{@code bag.containsAll(coll)} becomes
57   *       {@code MultiSetUtils.containsOccurrences(multiSet, new HashMultiSet<>(coll))}</li>
58   *   <li>{@code bag.removeAll(coll)} becomes
59   *       {@code MultiSetUtils.removeOccurrences(multiSet, new HashMultiSet<>(coll))}</li>
60   *   <li>{@code bag.retainAll(coll)} becomes
61   *       {@code MultiSetUtils.retainOccurrences(multiSet, new HashMultiSet<>(coll))}</li>
62   *   <li>{@link SortedBag} and {@code TreeBag} become {@link SortedMultiSet}
63   *       and {@code TreeMultiSet}</li>
64   *   <li>the {@code CollectionBag} and {@code CollectionSortedBag} wrappers are
65   *       not needed, as a {@code MultiSet} already complies with the
66   *       {@code Collection} contract</li>
67   * </ul>
68   *
69   * @param <E> The type of elements in this bag
70   * @see MultiSet
71   * @since 2.0
72   * @deprecated Since 4.6.0, use {@link MultiSet} instead; see the migration notes above.
73   */
74  @Deprecated
75  public interface Bag<E> extends Collection<E> {
76  
77      /**
78       * <em>(Violation)</em>
79       * Adds one copy of the specified object to the Bag.
80       * <p>
81       * If the object is already in the {@link #uniqueSet()} then increment its
82       * count as reported by {@link #getCount(Object)}. Otherwise add it to the
83       * {@link #uniqueSet()} and report its count as 1.
84       * </p>
85       * <p>
86       * Since this method always increases the size of the bag,
87       * according to the {@link Collection#add(Object)} contract, it
88       * should always return {@code true}. Since it sometimes returns
89       * {@code false}, this method violates the contract.
90       * </p>
91       *
92       * @param object  The object to add.
93       * @return {@code true} if the object was not already in the {@code uniqueSet}.
94       */
95      @Override
96      boolean add(E object);
97  
98      /**
99       * Adds {@code nCopies} copies of the specified object to the Bag.
100      * <p>
101      * If the object is already in the {@link #uniqueSet()} then increment its
102      * count as reported by {@link #getCount(Object)}. Otherwise add it to the
103      * {@link #uniqueSet()} and report its count as {@code nCopies}.
104      * </p>
105      *
106      * @param object  The object to add.
107      * @param nCopies  The number of copies to add.
108      * @return {@code true} if the object was not already in the {@code uniqueSet}.
109      * @throws ClassCastException if the class of the specified element prevents it from being added to this collection.
110      */
111     boolean add(E object, int nCopies);
112 
113     /**
114      * <em>(Violation)</em>
115      * Returns {@code true} if the bag contains all elements in
116      * the given collection, respecting cardinality. That is, if the
117      * given collection {@code coll} contains {@code n} copies
118      * of a given object, calling {@link #getCount(Object)} on that object must
119      * be {@code &gt;= n} for all {@code n} in {@code coll}.
120      *
121      * <p>
122      * The {@link Collection#containsAll(Collection)} method specifies
123      * that cardinality should <em>not</em> be respected; this method should
124      * return true if the bag contains at least one of every object contained
125      * in the given collection.
126      * </p>
127      *
128      * @param coll  The collection to check against.
129      * @return {@code true} if the Bag contains all the collection.
130      */
131     @Override
132     boolean containsAll(Collection<?> coll);
133 
134     /**
135      * Gets the number of occurrences (cardinality) of the given
136      * object currently in the bag. If the object does not exist in the
137      * bag, return 0.
138      *
139      * @param object  The object to search for.
140      * @return The number of occurrences of the object, zero if not found.
141      */
142     int getCount(Object object);
143 
144     /**
145      * Returns an {@link Iterator} over the entire set of members,
146      * including copies due to cardinality. This iterator is fail-fast
147      * and will not tolerate concurrent modifications.
148      *
149      * @return iterator over all elements in the Bag.
150      */
151     @Override
152     Iterator<E> iterator();
153 
154     /**
155      * <em>(Violation)</em>
156      * Removes all occurrences of the given object from the bag.
157      * <p>
158      * This will also remove the object from the {@link #uniqueSet()}.
159      * </p>
160      * <p>
161      * According to the {@link Collection#remove(Object)} method,
162      * this method should only remove the <em>first</em> occurrence of the
163      * given object, not <em>all</em> occurrences.
164      * </p>
165      *
166      * @param object  The object to remove.
167      * @return {@code true} if this call changed the collection.
168      */
169     @Override
170     boolean remove(Object object);
171 
172     /**
173      * Removes {@code nCopies} copies of the specified object from the Bag.
174      * <p>
175      * If the number of copies to remove is greater than the actual number of
176      * copies in the Bag, no error is thrown.
177      * </p>
178      *
179      * @param object  The object to remove.
180      * @param nCopies  The number of copies to remove.
181      * @return {@code true} if this call changed the collection.
182      */
183     boolean remove(Object object, int nCopies);
184 
185     /**
186      * <em>(Violation)</em>
187      * Remove all elements represented in the given collection,
188      * respecting cardinality. That is, if the given collection
189      * {@code coll} contains {@code n} copies of a given object,
190      * the bag will have {@code n} fewer copies, assuming the bag
191      * had at least {@code n} copies to begin with.
192      *
193      * <p>
194      * The {@link Collection#removeAll(Collection)} method specifies
195      * that cardinality should <em>not</em> be respected; this method should
196      * remove <em>all</em> occurrences of every object contained in the
197      * given collection.
198      * </p>
199      *
200      * @param coll  The collection to remove.
201      * @return {@code true} if this call changed the collection.
202      */
203     @Override
204     boolean removeAll(Collection<?> coll);
205 
206     /**
207      * <em>(Violation)</em>
208      * Remove any members of the bag that are not in the given
209      * collection, respecting cardinality. That is, if the given
210      * collection {@code coll} contains {@code n} copies of a
211      * given object and the bag has {@code m > n} copies, then
212      * delete {@code m - n} copies from the bag. In addition, if
213      * {@code e} is an object in the bag but
214      * {@code !coll.contains(e)}, then remove {@code e} and any
215      * of its copies.
216      *
217      * <p>
218      * The {@link Collection#retainAll(Collection)} method specifies
219      * that cardinality should <em>not</em> be respected; this method should
220      * keep <em>all</em> occurrences of every object contained in the
221      * given collection.
222      * </p>
223      *
224      * @param coll  The collection to retain.
225      * @return {@code true} if this call changed the collection.
226      */
227     @Override
228     boolean retainAll(Collection<?> coll);
229 
230     /**
231      * Returns the total number of items in the bag across all types.
232      *
233      * @return The total size of the Bag.
234      */
235     @Override
236     int size();
237 
238     /**
239      * Returns a {@link Set} of unique elements in the Bag.
240      * <p>
241      * Uniqueness constraints are the same as those in {@link Set}.
242      * </p>
243      *
244      * @return The Set of unique Bag elements.
245      */
246     Set<E> uniqueSet();
247 
248     // The following is not part of the formal Bag interface, however where possible
249     // Bag implementations should follow these comments.
250 //    /**
251 //     * Compares this Bag to another.
252 //     * This Bag equals another Bag if it contains the same number of occurrences of
253 //     * the same elements.
254 //     * This equals definition is compatible with the Set interface.
255 //     *
256 //     * @param obj  The Bag to compare to
257 //     * @return true if equal
258 //     */
259 //    boolean equals(Object obj);
260 //
261 //    /**
262 //     * Gets a hash code for the Bag compatible with the definition of equals.
263 //     * The hash code is defined as the sum total of a hash code for each element.
264 //     * The per element hash code is defined as
265 //     * {@code (e==null ? 0 : e.hashCode()) ^ noOccurrences)}.
266 //     * This hash code definition is compatible with the Set interface.
267 //     *
268 //     * @return The hash code of the Bag
269 //     */
270 //    int hashCode();
271 
272 }