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