001 /*
002 * $Id: CollectionHelpers.java,v 1.23 2012/02/19 17:35:52 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 *
012 * All Rights Reserved
013 *
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.
016 *
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 *
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025 * GNU Lesser Public License for more details.
026 *
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program. If not, see http://www.gnu.org/licenses.
029 */
030
031 package edu.wisc.ssec.mcidasv.util;
032
033 import java.lang.reflect.Array;
034 import java.util.ArrayList;
035 import java.util.Collection;
036 import java.util.Collections;
037 import java.util.HashMap;
038 import java.util.HashSet;
039 import java.util.Iterator;
040 import java.util.LinkedHashMap;
041 import java.util.LinkedHashSet;
042 import java.util.LinkedList;
043 import java.util.List;
044 import java.util.Map;
045 import java.util.Set;
046 import java.util.concurrent.ConcurrentHashMap;
047 import java.util.concurrent.CopyOnWriteArrayList;
048 import java.util.concurrent.CopyOnWriteArraySet;
049
050 import edu.wisc.ssec.mcidasv.util.functional.Function;
051
052 /**
053 * A <i>collection</i> (ugh) of static methods that make working with Java's
054 * default collections a bit easier, or at least allows you to elide some of
055 * the redundancy of idiomatic Java.
056 *
057 * <p>Make use of {@literal "static imports"} to omit even more needless code.
058 */
059 @SuppressWarnings({"ClassWithoutLogger", "UnusedDeclaration"})
060 public final class CollectionHelpers {
061
062 /** Never! */
063 private CollectionHelpers() {}
064
065 /**
066 * {@literal "Converts"} the incoming {@literal "varargs"} into an array.
067 *
068 * <p>Useful for doing things like:
069 * {@code String[] strs = arr("hello", "how", "are", "you?");}
070 *
071 * @param ts Items that will make up the elements of the returned array.
072 * Cannot be {@code null}, and (for now) the items should be of the
073 * <i>same</i> type.
074 *
075 * @return An array populated with each item from {@code ts}.
076 */
077 public static <T> T[] arr(T... ts) {
078 return ts;
079 }
080
081 /**
082 * Creates a {@link List} from incoming {@literal "varargs"}. Currently
083 * uses {@link ArrayList} as the {@code List} implementation.
084 *
085 * <p>Used like so:
086 * {@code List<String> listy = list("y", "helo", "thar");}
087 *
088 * @param elements Items that will make up the elements of the returned
089 * {@code List}.
090 *
091 * @return A {@code List} whose elements are each item within {@code elements}.
092 */
093 public static <E> List<E> list(E... elements) {
094 List<E> newList = arrList(elements.length);
095 Collections.addAll(newList, elements);
096 return newList;
097 }
098
099 /**
100 * Creates a {@link Set} from incoming {@literal "varargs"}. Currently uses
101 * {@link LinkedHashSet} as the {@code Set} implementation (to preserve
102 * ordering).
103 *
104 * <p>Used like so:
105 * {@code for (String s : set("beep", "boop", "blorp")) { ... }}
106 *
107 * @param elements Items that will appear within the returned {@code Set}.
108 * Cannot be {@code null}, and (for now) the items should be of the
109 * <i>same</i> type.
110 *
111 * @return A {@code Set} containing the items in {@code elements}. Remember
112 * that {@code Set}s only contain <i>unique</i> elements!
113 */
114 public static <E> Set<E> set(E... elements) {
115 Set<E> newSet = new LinkedHashSet<E>(elements.length);
116 Collections.addAll(newSet, elements);
117 return newSet;
118 }
119
120 /**
121 * Creates a new {@code cl} instance (limited to things implementing
122 * {@link Collection}) populated with the {@literal "varargs"}. Useful if
123 * you truly despise {@link #arr(Object...)}, {@link #list(Object...)},
124 * or {@link #set(Object...)}.
125 *
126 * <p>Example: {@code Collection<Integer> ints = collect(PriorityBlockingQueue.class, 1, 2, 3);}
127 *
128 * @param cl A (non-abstract!) class that implements {@code Collection}. Cannot be {@code null}.
129 * @param elements Objects that will be added to the collection.
130 *
131 * @return An instance of {@code cl} containing the given objects.
132 *
133 * @throws RuntimeException
134 * if {@link java.lang.reflect.Constructor#newInstance(Object...) Constructor#newInstance(Object...)}
135 * had problems.
136 *
137 * @see #arr(Object...)
138 * @see #list(Object...)
139 * @see #set(Object...)
140 */
141 @SuppressWarnings({ "unchecked", "rawtypes" }) // the only things being added to the collection are objects of type "E"
142 public static <E> Collection<E> collect(Class<? extends Collection> cl, E... elements) {
143 try {
144 Collection<E> c = cl.getConstructor().newInstance();
145 Collections.addAll(c, elements);
146 return c;
147 } catch (Exception e) {
148 throw new RuntimeException("Problem creating a new "+cl, e);
149 }
150 }
151
152 /**
153 * Determines the {@literal "length"} of a given object. This method
154 * currently understands:<ul>
155 * <li>{@link Collection}</li>
156 * <li>{@link Map}</li>
157 * <li>{@link CharSequence}</li>
158 * <li>{@link Array}</li>
159 * <li>{@link Iterable}</li>
160 * <li>{@link Iterator}</li>
161 * </ul>
162 *
163 * <p>More coming!
164 *
165 * @param o {@code Object} whose length we want. Cannot be {@code null}.
166 *
167 * @return {@literal "Length"} of {@code o}.
168 *
169 * @throws NullPointerException if {@code o} is {@code null}.
170 * @throws IllegalArgumentException if the method doesn't know how to test
171 * whatever type of object {@code o} might be.
172 */
173 @SuppressWarnings({"WeakerAccess"})
174 public static int len(final Object o) {
175 if (o == null) {
176 throw new NullPointerException("Null arguments do not have a length");
177 }
178 if (o instanceof Collection<?>) {
179 return ((Collection<?>)o).size();
180 }
181 else if (o instanceof Map<?, ?>) {
182 return ((Map<?, ?>)o).size();
183 }
184 else if (o instanceof CharSequence) {
185 return ((CharSequence)o).length();
186 }
187 else if (o instanceof Iterator<?>) {
188 int count = 0;
189 Iterator<?> it = (Iterator<?>)o;
190 while (it.hasNext()) {
191 it.next();
192 count++;
193 }
194 return count;
195 }
196 else if (o instanceof Iterable<?>) {
197 return len(((Iterable<?>)o).iterator());
198 }
199
200 throw new IllegalArgumentException("Don't know how to find the length of a "+o.getClass().getName());
201 }
202
203 /**
204 * Searches an object to see if it {@literal "contains"} another object.
205 * This method currently knows how to search:<ul>
206 * <li>{@link Collection}</li>
207 * <li>{@link Map}</li>
208 * <li>{@link CharSequence}</li>
209 * <li>{@link Array}</li>
210 * <li>{@link Iterable}</li>
211 * <li>{@link Iterator}</li>
212 * </ul>
213 *
214 * <p>More coming!
215 *
216 * @param collection {@code Object} that will be searched for
217 * {@code item}. Cannot be {@code null}.
218 * @param item {@code Object} to search for within {@code o}.
219 * {@code null} values are allowed.
220 *
221 * @return {@code true} if {@code o} contains {@code item}, {@code false}
222 * otherwise.
223 *
224 * @throws NullPointerException if {@code o} is {@code null}.
225 * @throws IllegalArgumentException if the method doesn't know how to
226 * search whatever type of object {@code o} might be.
227 */
228 // TODO(jon:89): item should probably become an array/collection too...
229 @SuppressWarnings({"WeakerAccess"})
230 public static boolean contains(final Object collection, final Object item) {
231 if (collection == null) {
232 throw new NullPointerException("Cannot search a null object");
233 }
234 if (collection instanceof Collection<?>) {
235 return ((Collection<?>)collection).contains(item);
236 }
237 else if ((collection instanceof String) && (item instanceof CharSequence)) {
238 return ((String)collection).contains((CharSequence) item);
239 }
240 else if (collection instanceof Map<?, ?>) {
241 return ((Map<?, ?>)collection).containsKey(item);
242 }
243 else if (collection instanceof Iterator<?>) {
244 Iterator<?> it = (Iterator<?>)collection;
245 if (item == null) {
246 while (it.hasNext()) {
247 if (it.next() == null) {
248 return true;
249 }
250 }
251 } else {
252 while (it.hasNext()) {
253 if (item.equals(it.next())) {
254 return true;
255 }
256 }
257 }
258 return false;
259 }
260 else if (collection instanceof Iterable<?>) {
261 return contains(((Iterable<?>) collection).iterator(), item);
262 }
263 else if (collection.getClass().isArray()) {
264 for (int i = 0; i < Array.getLength(collection); i++) {
265 if (Array.get(collection, i).equals(item)) {
266 return true;
267 }
268 }
269 }
270 throw new IllegalArgumentException("Don't know how to search a "+collection.getClass().getName());
271 }
272
273 /**
274 * Creates an empty {@link HashSet} that uses a little cleverness with
275 * Java's generics. Useful for eliminating redundant type information and
276 * declaring fields as {@code final}.
277 *
278 * <p>Please consider using {@link #newHashSet(int)} or
279 * {@link #newHashSet(java.util.Collection)} instead of this method.
280 *
281 * @return A new, empty {@code HashSet}.
282 *
283 * @see #newHashSet(int)
284 * @see #newHashSet(java.util.Collection)
285 */
286 @SuppressWarnings({"CollectionWithoutInitialCapacity"})
287 public static <E> Set<E> newHashSet() {
288 return new HashSet<E>();
289 }
290
291 /**
292 * Creates an empty {@link HashSet} with a given initial capacity.
293 *
294 * @param initialCapacity Initial capacity of the {@code HashSet}. Cannot
295 * be negative.
296 *
297 * @return A new, empty {@code HashSet} with the given initial capacity.
298 */
299 public static <E> Set<E> newHashSet(int initialCapacity) {
300 return new HashSet<E>(initialCapacity);
301 }
302
303 /**
304 * Copies an existing {@link Collection} into a new {@link HashSet}.
305 *
306 * @param original {@code Collection} to be copied. Cannot be {@code null}.
307 *
308 * @return A new {@code HashSet} whose contents are the same as
309 * {@code original}.
310 */
311 public static <E> Set<E> newHashSet(Collection<E> original) {
312 return new HashSet<E>(original);
313 }
314
315 /**
316 * Creates an empty {@link LinkedHashSet} that uses a little cleverness
317 * with Java's generics. Useful for eliminating redundant type
318 * information and declaring fields as {@code final}.
319 *
320 * <p>Please consider using {@link #newLinkedHashSet(int)} or
321 * {@link #newLinkedHashSet(java.util.Collection)} instead of this method.
322 *
323 * @return A new, empty {@code LinkedHashSet}.
324 *
325 * @see #newLinkedHashSet(int)
326 * @see #newLinkedHashSet(java.util.Collection)
327 */
328 @SuppressWarnings({"CollectionWithoutInitialCapacity"})
329 public static <E> Set<E> newLinkedHashSet() {
330 return new LinkedHashSet<E>();
331 }
332
333 /**
334 * Creates an empty {@link LinkedHashSet} with a given initial capacity.
335 *
336 * @param initialCapacity Initial capacity of the {@code LinkedHashSet}.
337 * Cannot be negative.
338 *
339 * @return A new, empty {@code LinkedHashSet} with the given initial
340 * capacity.
341 */
342 public static <E> Set<E> newLinkedHashSet(int initialCapacity) {
343 return new LinkedHashSet<E>(initialCapacity);
344 }
345
346 /**
347 * Copies a {@link Collection} into a new {@link LinkedHashSet}.
348 *
349 * @param original Collection to be copied. Cannot be {@code null}.
350 *
351 * @return A new {@code LinkedHashSet} whose contents are the same as
352 * {@code original}.
353 */
354 public static <E> Set<E> newLinkedHashSet(Collection<E> original) {
355 return new LinkedHashSet<E>(original);
356 }
357
358 /**
359 * Creates an empty {@link HashSet} that uses a little cleverness with
360 * Java's generics. Useful for eliminating redundant type information and
361 * declaring fields as {@code final}, while also reducing compiler warnings.
362 *
363 * <p>Please consider using {@link #newMap(int)} or
364 * {@link #newMap(java.util.Map)} instead of this method.
365 *
366 * @return A new, empty {@code HashMap}.
367 *
368 * @see #newMap(int)
369 * @see #newMap(java.util.Map)
370 */
371 @SuppressWarnings({"CollectionWithoutInitialCapacity"})
372 public static <K, V> Map<K, V> newMap() {
373 return new HashMap<K, V>();
374 }
375
376 /**
377 * Creates an empty {@link HashSet} with a given initial capacity.
378 *
379 * @param initialCapacity Initial capacity of the {@code HashMap}.
380 * Cannot be negative.
381 *
382 * @return A new, empty {@code HashMap} with the given initial capacity.
383 */
384 public static <K, V> Map<K, V> newMap(int initialCapacity) {
385 return new HashMap<K, V>(initialCapacity);
386 }
387
388 /**
389 * Copies an existing {@link Map} into a new {@link HashMap}.
390 *
391 * @param original Map to be copied. Cannot be {@code null}.
392 *
393 * @return A new {@code HashMap} whose contents are the same as
394 * {@code original}.
395 */
396 public static <K, V> Map<K, V> newMap(Map<K, V> original) {
397 return new HashMap<K, V>(original);
398 }
399
400 /**
401 * Creates an empty {@link LinkedHashMap} that uses a little cleverness with
402 * Java's generics. Useful for eliminating redundant type information and
403 * declaring fields as {@code final}, while also reducing compiler warnings.
404 *
405 * <p>Please consider using {@link #newLinkedHashMap(int)} or
406 * {@link #newLinkedHashSet(java.util.Collection)} instead of this method.
407 *
408 * @return A new, empty {@code LinkedHashMap}.
409 *
410 * @see #newLinkedHashMap(int)
411 * @see #newLinkedHashMap(java.util.Map)
412 */
413 @SuppressWarnings({"CollectionWithoutInitialCapacity"})
414 public static <K, V> Map<K, V> newLinkedHashMap() {
415 return new LinkedHashMap<K, V>();
416 }
417
418 /**
419 * Creates an empty {@link LinkedHashMap} with a given initial capacity.
420 *
421 * @param initialCapacity Initial capacity of the {@code LinkedHashMap}.
422 * Cannot be negative.
423 *
424 * @return A new, empty {@code LinkedHashMap} with the given initial
425 * capacity.
426 */
427 public static <K, V> Map<K, V> newLinkedHashMap(int initialCapacity) {
428 return new LinkedHashMap<K, V>(initialCapacity);
429 }
430
431 /**
432 * Copies an existing {@link Map} into a new {@link LinkedHashMap}.
433 *
434 * @param original Map to be copied. Cannot be {@code null}.
435 *
436 * @return A new {@code LinkedHashMap} whose contents are the same as
437 * {@code original}.
438 */
439 public static <K, V> Map<K, V> newLinkedHashMap(Map<K, V> original) {
440 return new LinkedHashMap<K, V>(original);
441 }
442
443 /**
444 * Abuses Java's sad {@literal "type"} implementation to create a new
445 * {@link ConcurrentHashMap}.
446 *
447 * @return Shiny and new {@code ConcurrentHashMap}
448 */
449 public static <K, V> Map<K, V> concurrentMap() {
450 return new ConcurrentHashMap<K,V>();
451 }
452
453 /**
454 * Creates an empty {@link CopyOnWriteArrayList}. Keep in mind that you
455 * only want to use {@code CopyOnWriteArrayList} for lists that are not
456 * going to be modified very often!
457 *
458 * @return A new, empty {@code CopyOnWriteArrayList}.
459 */
460 public static <E> List<E> concurrentList() {
461 return new CopyOnWriteArrayList<E>();
462 }
463
464 /**
465 * Creates a new {@link CopyOnWriteArrayList} that contains all of the
466 * elements in {@code original}. Keep in mind that you only want to use
467 * {@code CopyOnWriteArrayList} for lists that are not going to be
468 * modified very often!
469 *
470 * @param original Collection to be copied into the new list.
471 *
472 * @return A new {@code CopyOnWriteArrayList} whose contents are the same
473 * as {@code original}.
474 */
475 public static <E> List<E> concurrentList(Collection<E> original) {
476 return new CopyOnWriteArrayList<E>(original);
477 }
478
479 /**
480 * Creates a new {@link CopyOnWriteArrayList} from the incoming
481 * {@literal "varargs"}. Keep in mind that you only want to use
482 * {@code CopyOnWriteArrayList} for lists that are not going to be modified
483 * very often!
484 *
485 * @param elems Elements that will be contained in the resulting list.
486 *
487 * @return A new {@code CopyOnWriteArrayList} that contains the incoming
488 * objects.
489 */
490 public static <E> List<E> concurrentList(E... elems) {
491 return new CopyOnWriteArrayList<E>(elems);
492 }
493
494 /**
495 * Creates a new {@link CopyOnWriteArraySet}. Keep in mind that you only
496 * want to use a {@code CopyOnWriteArraySet} for sets that are not going to
497 * be modified very often!
498 *
499 * @return A new, empty {@code CopyOnWriteArraySet}.
500 */
501 public static <E> Set<E> concurrentSet() {
502 return new CopyOnWriteArraySet<E>();
503 }
504
505 /**
506 * Creates a new {@link CopyOnWriteArraySet} that contains all of the
507 * elements in {@code original}. Keep in mind that you only want to use a
508 * {@code CopyOnWriteArraySet} for sets that are not going to be modified
509 * very often!
510 *
511 * @param original Collection to be copied into the new set.
512 *
513 * @return A new {@code CopyOnWriteArraySet} whose contents are the same as
514 * {@code original}.
515 */
516 public static <E> Set<E> concurrentSet(Collection<E> original) {
517 return new CopyOnWriteArraySet<E>(original);
518 }
519
520 /**
521 * Creates a new {@link CopyOnWriteArraySet} from the incoming
522 * {@literal "varargs"}. Keep in mind that you only want to use a
523 * {@code CopyOnWriteArraySet} for sets that are not going to be modified
524 * very often!
525 *
526 * @param elems Elements that will be contained in the resulting set.
527 *
528 * @return A new {@code CopyOnWriteArraySet} that contains the incoming
529 * objects.
530 */
531 public static <E> Set<E> concurrentSet(E... elems) {
532 Set<E> set = new CopyOnWriteArraySet<E>();
533 Collections.addAll(set, elems);
534 return set;
535 }
536
537 public static <E> List<E> linkedList() {
538 return new LinkedList<E>();
539 }
540
541 public static <E> List<E> linkedList(final Collection<? extends E> c) {
542 return new LinkedList<E>(c);
543 }
544
545 /**
546 * Creates an empty {@link ArrayList} that uses a little cleverness with
547 * Java's generics. Useful for eliminating redundant type information and
548 * declaring fields as {@code final}.
549 *
550 * <p>Used like so:
551 * {@code List<String> listy = arrList();}
552 *
553 * <p>Please consider using {@link #arrList(int)} or
554 * {@link #arrList(java.util.Collection)} instead of this method.
555 *
556 * @return A new, empty {@code ArrayList}.
557 *
558 * @see #arrList(int)
559 * @see #arrList(java.util.Collection)
560 */
561 @SuppressWarnings({"CollectionWithoutInitialCapacity"})
562 public static <E> List<E> arrList() {
563 return new ArrayList<E>();
564 }
565
566 /**
567 * Creates an empty {@link ArrayList} with a given capacity.
568 *
569 * @param capacity The initial size of the returned {@code ArrayList}.
570 *
571 * @return A new, empty {@code ArrayList} that has an initial capacity of
572 * {@code capacity} elements.
573 *
574 * @see ArrayList#ArrayList(int)
575 */
576 public static <E> List<E> arrList(final int capacity) {
577 return new ArrayList<E>(capacity);
578 }
579
580 /**
581 * Copies an existing {@link Collection} into a new {@link ArrayList}.
582 *
583 * @param c {@code Collection} whose elements are to be placed into the
584 * returned {@code ArrayList}.
585 *
586 * @return An {@code ArrayList} containing the elements of {@code c}.
587 *
588 * @see ArrayList#ArrayList(Collection)
589 */
590 public static <E> List<E> arrList(final Collection<? extends E> c) {
591 return new ArrayList<E>(c);
592 }
593
594 /**
595 * Copies an existing {@link Collection} into a new (non-abstract!)
596 * {@code Collection} class.
597 *
598 * @param cl Non-abstract {@code Collection} class.
599 * @param old An existing {@code Collection}.
600 *
601 * @return A new instance of {@code cl} that contains all of the elements
602 * from {@code old}.
603 *
604 * @throws RuntimeException if there was trouble creating a new instance
605 * of {@code cl}.
606 *
607 * @see #collect(Class, Object...)
608 */
609 // not sure about the utility of this one...
610 @SuppressWarnings({ "unchecked", "rawtypes" }) // again, only adding items of type "E"
611 public static <E> Collection<E> recollect(Class<? extends Collection> cl, Collection<E> old) {
612 try {
613 Collection<E> c = cl.getConstructor().newInstance();
614 c.addAll(old);
615 return c;
616 } catch (Exception e) {
617 throw new RuntimeException("", e);
618 }
619 }
620
621 /**
622 * Takes arrays of {@code keys} and {@code values} and merges them
623 * together to form a {@link Map}. The returned {@code Map} is a
624 * {@link LinkedHashMap} and is truncated in length to the length of the
625 * shorter parameter.
626 *
627 * <p>This is intended for use as {@literal "varargs"} supplied to
628 * {@link #arr(Object...)}. Rather than doing something ugly like:
629 * <pre>
630 * Map<String, String> mappy = new LinkedHashMap<String, String>();
631 * mappy.put("key0", "val0");
632 * mappy.put("key1", "val1");
633 * ...
634 * mappy.put("keyN", "valN");
635 * </pre>
636 *
637 * Simply do like so:
638 * <pre>
639 * mappy = zipMap(
640 * arr("key0", "key1", ..., "keyN"),
641 * arr("val0", "val1", ..., "valN"));
642 * </pre>
643 *
644 * <p>The latter approach also allows you to make {@code static final}
645 * {@link Map}s much more easily.
646 *
647 * @param keys Array whose elements will be the keys in a {@code Map}.
648 * @param values Array whose elements will the values in a {@code Map}.
649 *
650 * @return A {@code Map} whose entries are of the form
651 * {@code keys[N], values[N]}.
652 *
653 * @see #arr(Object...)
654 * @see #zipMap(java.util.Collection, java.util.Collection)
655 */
656 public static <K, V> Map<K, V> zipMap(K[] keys, V[] values) {
657 Map<K, V> zipped = new LinkedHashMap<K, V>(keys.length);
658 for (int i = 0; (i < keys.length && i < values.length); i++) {
659 zipped.put(keys[i], values[i]);
660 }
661 return zipped;
662 }
663
664 /**
665 * A version of {@link #zipMap(Object[], Object[])} that works with
666 * {@link Collection}s.
667 *
668 * @param keys Items that will be the keys in the resulting {@code Map}.
669 * @param values Items that will be the values in the result {@code Map}.
670 *
671 * @return A {@code Map} whose entries are of the form
672 * {@code keys[N], values[N]}.
673 *
674 * @see #zipMap(Object[], Object[])
675 */
676 public static <K, V> Map<K, V> zipMap(Collection<? extends K> keys, Collection<? extends V> values) {
677 Map<K, V> zipped = new LinkedHashMap<K, V>(keys.size());
678 Iterator<? extends K> keyIterator = keys.iterator();
679 Iterator<? extends V> valueIterator = values.iterator();
680 while (keyIterator.hasNext() && valueIterator.hasNext()) {
681 zipped.put(keyIterator.next(), valueIterator.next());
682 }
683 return zipped;
684 }
685
686 /**
687 * Applies a given function to each item in a given list.
688 *
689 * @param f The {@link Function} to apply.
690 * @param as The list whose items are to be fed into {@code f}.
691 *
692 * @return New list containing the results of each element of {@code as}
693 * being passed through {@code f}.
694 */
695 public static <A, B> List<B> map(final Function<A, B> f, List<A> as) {
696 List<B> bs = arrList(as.size());
697 for (A a : as) {
698 bs.add(f.apply(a));
699 }
700 return bs;
701 }
702
703 /**
704 * Applies a given function to each item in a given {@link Set}.
705 *
706 * @param f The {@link Function} to apply to {@code as}.
707 * @param as The {@code Set} whose items are to be fed into {@code f}.
708 *
709 * @return New {@code Set} containing the results of passing each element
710 * in {@code as} through {@code f}.
711 */
712 public static <A, B> Set<B> map(final Function<A, B> f, Set<A> as) {
713 Set<B> bs = newLinkedHashSet(as.size());
714 for (A a : as) {
715 bs.add(f.apply(a));
716 }
717 return bs;
718 }
719
720 /**
721 * {@literal "Generics-friendly"} way to cast an object of some superclass
722 * ({@code A}) to a subclass or implementation ({@code B}). This method will
723 * fail if you attempt to cast to a type that is not a subclass of type
724 * {@code A}.
725 *
726 * <p>Example/Justification:<br/>
727 * Consider a method like {@link ucar.unidata.xml.XmlUtil#findChildren(org.w3c.dom.Node, String) XmlUtil.findChildren(Node, String)}.<br/>
728 * Despite {@code findChildren} only returning lists containing {@code Node}
729 * objects, Java will generate a warning for the following code:
730 * <pre>
731 * import ucar.unidata.xml.XmlUtil;
732 * ....
733 * List<Node> nodes = XmlUtil.findChildren(panel, "blah");
734 * </pre>
735 * {@code cast} is a nice and terse way to avoid those warnings. Here's the
736 * previous example (with static imports of {@code cast} and {@code findChildren}):
737 * <pre>
738 * import static ucar.unidata.xml.XmlUtil.findChildren;
739 * import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.cast;
740 * ....
741 * List<Node> nodes = cast(findChildren(panel, "blah"));
742 * </pre>
743 *
744 * @param <A> Superclass of {@code B}. This is what you are
745 * {@literal "casting from"}...likely {@code Object} in most cases
746 * @param <B> Subclass of {@code A}. This is what you are
747 * {@literal "casting to"}.
748 *
749 * @param o The object whose type you are casting.
750 *
751 * @return {@code o}, casted from type {@code A} to {@code B}. Enjoy!
752 */
753 @SuppressWarnings("unchecked") public static <A, B extends A> B cast(A o) {
754 return (B)o;
755 }
756 }