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 }