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