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