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 }