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 >= 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 }