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 * http://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 *
44 * @param <E> the type of elements in this bag
45 * @since 2.0
46 */
47 public interface Bag<E> extends Collection<E> {
48
49 /**
50 * <em>(Violation)</em>
51 * Adds one copy of the specified object to the Bag.
52 * <p>
53 * If the object is already in the {@link #uniqueSet()} then increment its
54 * count as reported by {@link #getCount(Object)}. Otherwise add it to the
55 * {@link #uniqueSet()} and report its count as 1.
56 * </p>
57 * <p>
58 * Since this method always increases the size of the bag,
59 * according to the {@link Collection#add(Object)} contract, it
60 * should always return {@code true}. Since it sometimes returns
61 * {@code false}, this method violates the contract.
62 * </p>
63 *
64 * @param object the object to add
65 * @return {@code true} if the object was not already in the {@code uniqueSet}
66 */
67 @Override
68 boolean add(E object);
69
70 /**
71 * Adds {@code nCopies} copies of the specified object to the Bag.
72 * <p>
73 * If the object is already in the {@link #uniqueSet()} then increment its
74 * count as reported by {@link #getCount(Object)}. Otherwise add it to the
75 * {@link #uniqueSet()} and report its count as {@code nCopies}.
76 * </p>
77 *
78 * @param object the object to add
79 * @param nCopies the number of copies to add
80 * @return {@code true} if the object was not already in the {@code uniqueSet}
81 * @throws ClassCastException if the class of the specified element prevents it from being added to this collection
82 */
83 boolean add(E object, int nCopies);
84
85 /**
86 * <em>(Violation)</em>
87 * Returns {@code true} if the bag contains all elements in
88 * the given collection, respecting cardinality. That is, if the
89 * given collection {@code coll} contains {@code n} copies
90 * of a given object, calling {@link #getCount(Object)} on that object must
91 * be {@code >= n} for all {@code n} in {@code coll}.
92 *
93 * <p>
94 * The {@link Collection#containsAll(Collection)} method specifies
95 * that cardinality should <em>not</em> be respected; this method should
96 * return true if the bag contains at least one of every object contained
97 * in the given collection.
98 * </p>
99 *
100 * @param coll the collection to check against
101 * @return {@code true} if the Bag contains all the collection
102 */
103 @Override
104 boolean containsAll(Collection<?> coll);
105
106 /**
107 * Gets the number of occurrences (cardinality) of the given
108 * object currently in the bag. If the object does not exist in the
109 * bag, return 0.
110 *
111 * @param object the object to search for
112 * @return the number of occurrences of the object, zero if not found
113 */
114 int getCount(Object object);
115
116 /**
117 * Returns an {@link Iterator} over the entire set of members,
118 * including copies due to cardinality. This iterator is fail-fast
119 * and will not tolerate concurrent modifications.
120 *
121 * @return iterator over all elements in the Bag
122 */
123 @Override
124 Iterator<E> iterator();
125
126 /**
127 * <em>(Violation)</em>
128 * Removes all occurrences of the given object from the bag.
129 * <p>
130 * This will also remove the object from the {@link #uniqueSet()}.
131 * </p>
132 * <p>
133 * According to the {@link Collection#remove(Object)} method,
134 * this method should only remove the <em>first</em> occurrence of the
135 * given object, not <em>all</em> occurrences.
136 * </p>
137 *
138 * @param object the object to remove
139 * @return {@code true} if this call changed the collection
140 */
141 @Override
142 boolean remove(Object object);
143
144 /**
145 * Removes {@code nCopies} copies of the specified object from the Bag.
146 * <p>
147 * If the number of copies to remove is greater than the actual number of
148 * copies in the Bag, no error is thrown.
149 * </p>
150 *
151 * @param object the object to remove
152 * @param nCopies the number of copies to remove
153 * @return {@code true} if this call changed the collection
154 */
155 boolean remove(Object object, int nCopies);
156
157 /**
158 * <em>(Violation)</em>
159 * Remove all elements represented in the given collection,
160 * respecting cardinality. That is, if the given collection
161 * {@code coll} contains {@code n} copies of a given object,
162 * the bag will have {@code n} fewer copies, assuming the bag
163 * had at least {@code n} copies to begin with.
164 *
165 * <p>
166 * The {@link Collection#removeAll(Collection)} method specifies
167 * that cardinality should <em>not</em> be respected; this method should
168 * remove <em>all</em> occurrences of every object contained in the
169 * given collection.
170 * </p>
171 *
172 * @param coll the collection to remove
173 * @return {@code true} if this call changed the collection
174 */
175 @Override
176 boolean removeAll(Collection<?> coll);
177
178 /**
179 * <em>(Violation)</em>
180 * Remove any members of the bag that are not in the given
181 * collection, respecting cardinality. That is, if the given
182 * collection {@code coll} contains {@code n} copies of a
183 * given object and the bag has {@code m > n} copies, then
184 * delete {@code m - n} copies from the bag. In addition, if
185 * {@code e} is an object in the bag but
186 * {@code !coll.contains(e)}, then remove {@code e} and any
187 * of its copies.
188 *
189 * <p>
190 * The {@link Collection#retainAll(Collection)} method specifies
191 * that cardinality should <em>not</em> be respected; this method should
192 * keep <em>all</em> occurrences of every object contained in the
193 * given collection.
194 * </p>
195 *
196 * @param coll the collection to retain
197 * @return {@code true} if this call changed the collection
198 */
199 @Override
200 boolean retainAll(Collection<?> coll);
201
202 /**
203 * Returns the total number of items in the bag across all types.
204 *
205 * @return the total size of the Bag
206 */
207 @Override
208 int size();
209
210 /**
211 * Returns a {@link Set} of unique elements in the Bag.
212 * <p>
213 * Uniqueness constraints are the same as those in {@link java.util.Set}.
214 * </p>
215 *
216 * @return the Set of unique Bag elements
217 */
218 Set<E> uniqueSet();
219
220 // The following is not part of the formal Bag interface, however where possible
221 // Bag implementations should follow these comments.
222 // /**
223 // * Compares this Bag to another.
224 // * This Bag equals another Bag if it contains the same number of occurrences of
225 // * the same elements.
226 // * This equals definition is compatible with the Set interface.
227 // *
228 // * @param obj the Bag to compare to
229 // * @return true if equal
230 // */
231 // boolean equals(Object obj);
232 //
233 // /**
234 // * Gets a hash code for the Bag compatible with the definition of equals.
235 // * The hash code is defined as the sum total of a hash code for each element.
236 // * The per element hash code is defined as
237 // * {@code (e==null ? 0 : e.hashCode()) ^ noOccurrences)}.
238 // * This hash code definition is compatible with the Set interface.
239 // *
240 // * @return the hash code of the Bag
241 // */
242 // int hashCode();
243
244 }