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 org.apache.commons.collections4.bag.CollectionBag;
20 import org.apache.commons.collections4.bag.HashBag;
21 import org.apache.commons.collections4.bag.PredicatedBag;
22 import org.apache.commons.collections4.bag.PredicatedSortedBag;
23 import org.apache.commons.collections4.bag.SynchronizedBag;
24 import org.apache.commons.collections4.bag.SynchronizedSortedBag;
25 import org.apache.commons.collections4.bag.TransformedBag;
26 import org.apache.commons.collections4.bag.TransformedSortedBag;
27 import org.apache.commons.collections4.bag.TreeBag;
28 import org.apache.commons.collections4.bag.UnmodifiableBag;
29 import org.apache.commons.collections4.bag.UnmodifiableSortedBag;
30
31 /**
32 * Provides utility methods and decorators for {@link Bag} and {@link SortedBag} instances.
33 *
34 * @since 2.1
35 */
36 public class BagUtils {
37
38 /**
39 * An empty unmodifiable bag.
40 */
41 @SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type
42 public static final Bag EMPTY_BAG = UnmodifiableBag.unmodifiableBag(new HashBag<>());
43
44 /**
45 * An empty unmodifiable sorted bag.
46 */
47 @SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type
48 public static final Bag EMPTY_SORTED_BAG =
49 UnmodifiableSortedBag.unmodifiableSortedBag(new TreeBag<>());
50
51 /**
52 * Returns a bag that complies to the Collection contract, backed by the given bag.
53 *
54 * @param <E> the element type
55 * @param bag the bag to decorate, must not be null
56 * @return a Bag that complies to the Collection contract
57 * @throws NullPointerException if bag is null
58 * @since 4.0
59 */
60 public static <E> Bag<E> collectionBag(final Bag<E> bag) {
61 return CollectionBag.collectionBag(bag);
62 }
63
64 /**
65 * Gets an empty {@code Bag}.
66 *
67 * @param <E> the element type
68 * @return an empty Bag
69 */
70 @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
71 public static <E> Bag<E> emptyBag() {
72 return EMPTY_BAG;
73 }
74
75 /**
76 * Gets an empty {@code SortedBag}.
77 *
78 * @param <E> the element type
79 * @return an empty sorted Bag
80 */
81 @SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
82 public static <E> SortedBag<E> emptySortedBag() {
83 return (SortedBag<E>) EMPTY_SORTED_BAG;
84 }
85
86 /**
87 * Returns a predicated (validating) bag backed by the given bag.
88 * <p>
89 * Only objects that pass the test in the given predicate can be added to
90 * the bag. Trying to add an invalid object results in an
91 * IllegalArgumentException. It is important not to use the original bag
92 * after invoking this method, as it is a backdoor for adding invalid
93 * objects.
94 * </p>
95 *
96 * @param <E> the element type
97 * @param bag the bag to predicate, must not be null
98 * @param predicate the predicate for the bag, must not be null
99 * @return a predicated bag backed by the given bag
100 * @throws NullPointerException if the Bag or Predicate is null
101 */
102 public static <E> Bag<E> predicatedBag(final Bag<E> bag, final Predicate<? super E> predicate) {
103 return PredicatedBag.predicatedBag(bag, predicate);
104 }
105
106 /**
107 * Returns a predicated (validating) sorted bag backed by the given sorted
108 * bag.
109 * <p>
110 * Only objects that pass the test in the given predicate can be added to
111 * the bag. Trying to add an invalid object results in an
112 * IllegalArgumentException. It is important not to use the original bag
113 * after invoking this method, as it is a backdoor for adding invalid
114 * objects.
115 * </p>
116 *
117 * @param <E> the element type
118 * @param bag the sorted bag to predicate, must not be null
119 * @param predicate the predicate for the bag, must not be null
120 * @return a predicated bag backed by the given bag
121 * @throws NullPointerException if the SortedBag or Predicate is null
122 */
123 public static <E> SortedBag<E> predicatedSortedBag(final SortedBag<E> bag,
124 final Predicate<? super E> predicate) {
125 return PredicatedSortedBag.predicatedSortedBag(bag, predicate);
126 }
127
128 /**
129 * Returns a synchronized (thread-safe) bag backed by the given bag. In
130 * order to guarantee serial access, it is critical that all access to the
131 * backing bag is accomplished through the returned bag.
132 * <p>
133 * It is imperative that the user manually synchronize on the returned bag
134 * when iterating over it:
135 * </p>
136 *
137 * <pre>
138 * Bag bag = BagUtils.synchronizedBag(new HashBag());
139 * ...
140 * synchronized(bag) {
141 * Iterator i = bag.iterator(); // Must be in synchronized block
142 * while (i.hasNext())
143 * foo(i.next());
144 * }
145 * }
146 * </pre>
147 *
148 * Failure to follow this advice may result in non-deterministic behavior.
149 *
150 * @param <E> the element type
151 * @param bag the bag to synchronize, must not be null
152 * @return a synchronized bag backed by that bag
153 * @throws NullPointerException if the Bag is null
154 */
155 public static <E> Bag<E> synchronizedBag(final Bag<E> bag) {
156 return SynchronizedBag.synchronizedBag(bag);
157 }
158
159 /**
160 * Returns a synchronized (thread-safe) sorted bag backed by the given
161 * sorted bag. In order to guarantee serial access, it is critical that all
162 * access to the backing bag is accomplished through the returned bag.
163 * <p>
164 * It is imperative that the user manually synchronize on the returned bag
165 * when iterating over it:
166 * </p>
167 *
168 * <pre>
169 * SortedBag bag = BagUtils.synchronizedSortedBag(new TreeBag());
170 * ...
171 * synchronized(bag) {
172 * Iterator i = bag.iterator(); // Must be in synchronized block
173 * while (i.hasNext())
174 * foo(i.next());
175 * }
176 * }
177 * </pre>
178 *
179 * Failure to follow this advice may result in non-deterministic behavior.
180 *
181 * @param <E> the element type
182 * @param bag the bag to synchronize, must not be null
183 * @return a synchronized bag backed by that bag
184 * @throws NullPointerException if the SortedBag is null
185 */
186 public static <E> SortedBag<E> synchronizedSortedBag(final SortedBag<E> bag) {
187 return SynchronizedSortedBag.synchronizedSortedBag(bag);
188 }
189
190 /**
191 * Returns a transformed bag backed by the given bag.
192 * <p>
193 * Each object is passed through the transformer as it is added to the Bag.
194 * It is important not to use the original bag after invoking this method,
195 * as it is a backdoor for adding untransformed objects.
196 * </p>
197 * <p>
198 * Existing entries in the specified bag will not be transformed.
199 * If you want that behavior, see {@link TransformedBag#transformedBag(Bag, Transformer)}.
200 * </p>
201 *
202 * @param <E> the element type
203 * @param bag the bag to predicate, must not be null
204 * @param transformer the transformer for the bag, must not be null
205 * @return a transformed bag backed by the given bag
206 * @throws NullPointerException if the Bag or Transformer is null
207 */
208 public static <E> Bag<E> transformingBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) {
209 return TransformedBag.transformingBag(bag, transformer);
210 }
211
212 /**
213 * Returns a transformed sorted bag backed by the given bag.
214 * <p>
215 * Each object is passed through the transformer as it is added to the Bag.
216 * It is important not to use the original bag after invoking this method,
217 * as it is a backdoor for adding untransformed objects.
218 * </p>
219 * <p>
220 * Existing entries in the specified bag will not be transformed.
221 * If you want that behavior, see
222 * {@link TransformedSortedBag#transformedSortedBag(SortedBag, Transformer)}.
223 * </p>
224 *
225 * @param <E> the element type
226 * @param bag the bag to predicate, must not be null
227 * @param transformer the transformer for the bag, must not be null
228 * @return a transformed bag backed by the given bag
229 * @throws NullPointerException if the Bag or Transformer is null
230 */
231 public static <E> SortedBag<E> transformingSortedBag(final SortedBag<E> bag,
232 final Transformer<? super E, ? extends E> transformer) {
233 return TransformedSortedBag.transformingSortedBag(bag, transformer);
234 }
235
236 /**
237 * Returns an unmodifiable view of the given bag. Any modification attempts
238 * to the returned bag will raise an {@link UnsupportedOperationException}.
239 *
240 * @param <E> the element type
241 * @param bag the bag whose unmodifiable view is to be returned, must not be null
242 * @return an unmodifiable view of that bag
243 * @throws NullPointerException if the Bag is null
244 */
245 public static <E> Bag<E> unmodifiableBag(final Bag<? extends E> bag) {
246 return UnmodifiableBag.unmodifiableBag(bag);
247 }
248
249 /**
250 * Returns an unmodifiable view of the given sorted bag. Any modification
251 * attempts to the returned bag will raise an
252 * {@link UnsupportedOperationException}.
253 *
254 * @param <E> the element type
255 * @param bag the bag whose unmodifiable view is to be returned, must not be null
256 * @return an unmodifiable view of that bag
257 * @throws NullPointerException if the SortedBag is null
258 */
259 public static <E> SortedBag<E> unmodifiableSortedBag(final SortedBag<E> bag) {
260 return UnmodifiableSortedBag.unmodifiableSortedBag(bag);
261 }
262
263 /**
264 * Don't allow instances.
265 */
266 private BagUtils() {
267 // empty
268 }
269
270 }