001/* 002 * $Id: CollectionHelpers.java,v 1.21 2011/04/06 19:59:45 jbeavers Exp $ 003 * 004 * This file is part of McIDAS-V 005 * 006 * Copyright 2007-2011 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 031package edu.wisc.ssec.mcidasv.util; 032 033import java.lang.reflect.Array; 034import java.util.ArrayList; 035import java.util.Collection; 036import java.util.Collections; 037import java.util.HashMap; 038import java.util.HashSet; 039import java.util.Iterator; 040import java.util.LinkedHashMap; 041import java.util.LinkedHashSet; 042import java.util.List; 043import java.util.Map; 044import java.util.Set; 045import java.util.concurrent.ConcurrentHashMap; 046import java.util.concurrent.CopyOnWriteArrayList; 047import java.util.concurrent.CopyOnWriteArraySet; 048 049import edu.wisc.ssec.mcidasv.util.functional.Function; 050 051/** 052 * A <i>collection</i> (ugh) of static methods that make working with Java's 053 * default collections a bit easier, or at least allows you to elide some of 054 * the redundancy of idiomatic Java. 055 * 056 * <p>Make use of {@literal "static imports"} to omit even more needless code. 057 */ 058@SuppressWarnings({"ClassWithoutLogger", "UnusedDeclaration"}) 059public final class CollectionHelpers { 060 061 /** Never! */ 062 private CollectionHelpers() {} 063 064 /** 065 * {@literal "Converts"} the incoming {@literal "varargs"} into an array. 066 * 067 * <p>Useful for doing things like: 068 * {@code String[] strs = arr("hello", "how", "are", "you?");} 069 * 070 * @param ts Items that will make up the elements of the returned array. 071 * Cannot be {@code null}, and (for now) the items should be of the 072 * <i>same</i> type. 073 * 074 * @return An array populated with each item from {@code ts}. 075 */ 076 public static <T> T[] arr(T... ts) { 077 return ts; 078 } 079 080 /** 081 * Creates a {@link List} from incoming {@literal "varargs"}. Currently 082 * uses {@link ArrayList} as the {@code List} implementation. 083 * 084 * <p>Used like so: 085 * {@code List<String> listy = list("y", "helo", "thar");} 086 * 087 * @param elements Items that will make up the elements of the returned 088 * {@code List}. 089 * 090 * @return A {@code List} whose elements are each item within {@code elements}. 091 */ 092 public static <E> List<E> list(E... elements) { 093 List<E> newList = arrList(elements.length); 094 Collections.addAll(newList, elements); 095 return newList; 096 } 097 098 /** 099 * Creates a {@link Set} from incoming {@literal "varargs"}. Currently uses 100 * {@link LinkedHashSet} as the {@code Set} implementation (to preserve 101 * ordering). 102 * 103 * <p>Used like so: 104 * {@code for (String s : set("beep", "boop", "blorp")) { ... }} 105 * 106 * @param elements Items that will appear within the returned {@code Set}. 107 * Cannot be {@code null}, and (for now) the items should be of the 108 * <i>same</i> type. 109 * 110 * @return A {@code Set} containing the items in {@code elements}. Remember 111 * that {@code Set}s only contain <i>unique</i> elements! 112 */ 113 public static <E> Set<E> set(E... elements) { 114 Set<E> newSet = new LinkedHashSet<E>(elements.length); 115 Collections.addAll(newSet, elements); 116 return newSet; 117 } 118 119 /** 120 * Creates a new {@code cl} instance (limited to things implementing 121 * {@link Collection}) populated with the {@literal "varargs"}. Useful if 122 * you truly despise {@link #arr(Object...)}, {@link #list(Object...)}, 123 * or {@link #set(Object...)}. 124 * 125 * <p>Example: {@code Collection<Integer> ints = collect(PriorityBlockingQueue.class, 1, 2, 3);} 126 * 127 * @param cl A (non-abstract!) class that implements {@code Collection}. Cannot be {@code null}. 128 * @param elements Objects that will be added to the collection. 129 * 130 * @return An instance of {@code cl} containing the given objects. 131 * 132 * @throws RuntimeException 133 * if {@link java.lang.reflect.Constructor#newInstance(Object...) Constructor#newInstance(Object...)} 134 * had problems. 135 * 136 * @see #arr(Object...) 137 * @see #list(Object...) 138 * @see #set(Object...) 139 */ 140 @SuppressWarnings({ "unchecked", "rawtypes" }) // the only things being added to the collection are objects of type "E" 141 public static <E> Collection<E> collect(Class<? extends Collection> cl, E... elements) { 142 try { 143 Collection<E> c = cl.getConstructor().newInstance(); 144 Collections.addAll(c, elements); 145 return c; 146 } catch (Exception e) { 147 throw new RuntimeException("Problem creating a new "+cl, e); 148 } 149 } 150 151 /** 152 * Determines the {@literal "length"} of a given object. This method 153 * currently understands:<ul> 154 * <li>{@link Collection}</li> 155 * <li>{@link Map}</li> 156 * <li>{@link CharSequence}</li> 157 * <li>{@link Array}</li> 158 * <li>{@link Iterable}</li> 159 * <li>{@link Iterator}</li> 160 * </ul> 161 * 162 * <p>More coming! 163 * 164 * @param o {@code Object} whose length we want. Cannot be {@code null}. 165 * 166 * @return {@literal "Length"} of {@code o}. 167 * 168 * @throws NullPointerException if {@code o} is {@code null}. 169 * @throws IllegalArgumentException if the method doesn't know how to test 170 * whatever type of object {@code o} might be. 171 */ 172 @SuppressWarnings({"WeakerAccess"}) 173 public static int len(final Object o) { 174 if (o == null) { 175 throw new NullPointerException("Null arguments do not have a length"); 176 } 177 if (o instanceof Collection<?>) { 178 return ((Collection<?>)o).size(); 179 } 180 else if (o instanceof Map<?, ?>) { 181 return ((Map<?, ?>)o).size(); 182 } 183 else if (o instanceof CharSequence) { 184 return ((CharSequence)o).length(); 185 } 186 else if (o instanceof Iterator<?>) { 187 int count = 0; 188 Iterator<?> it = (Iterator<?>)o; 189 while (it.hasNext()) { 190 it.next(); 191 count++; 192 } 193 return count; 194 } 195 else if (o instanceof Iterable<?>) { 196 return len(((Iterable<?>)o).iterator()); 197 } 198 199 throw new IllegalArgumentException("Don't know how to find the length of a "+o.getClass().getName()); 200 } 201 202 /** 203 * Searches an object to see if it {@literal "contains"} another object. 204 * This method currently knows how to search:<ul> 205 * <li>{@link Collection}</li> 206 * <li>{@link Map}</li> 207 * <li>{@link CharSequence}</li> 208 * <li>{@link Array}</li> 209 * <li>{@link Iterable}</li> 210 * <li>{@link Iterator}</li> 211 * </ul> 212 * 213 * <p>More coming! 214 * 215 * @param collection {@code Object} that will be searched for 216 * {@code item}. Cannot be {@code null}. 217 * @param item {@code Object} to search for within {@code o}. 218 * {@code null} values are allowed. 219 * 220 * @return {@code true} if {@code o} contains {@code item}, {@code false} 221 * otherwise. 222 * 223 * @throws NullPointerException if {@code o} is {@code null}. 224 * @throws IllegalArgumentException if the method doesn't know how to 225 * search whatever type of object {@code o} might be. 226 */ 227 // TODO(jon:89): item should probably become an array/collection too... 228 @SuppressWarnings({"WeakerAccess"}) 229 public static boolean contains(final Object collection, final Object item) { 230 if (collection == null) { 231 throw new NullPointerException("Cannot search a null object"); 232 } 233 if (collection instanceof Collection<?>) { 234 return ((Collection<?>)collection).contains(item); 235 } 236 else if ((collection instanceof String) && (item instanceof CharSequence)) { 237 return ((String)collection).contains((CharSequence) item); 238 } 239 else if (collection instanceof Map<?, ?>) { 240 return ((Map<?, ?>)collection).containsKey(item); 241 } 242 else if (collection instanceof Iterator<?>) { 243 Iterator<?> it = (Iterator<?>)collection; 244 if (item == null) { 245 while (it.hasNext()) { 246 if (it.next() == null) { 247 return true; 248 } 249 } 250 } else { 251 while (it.hasNext()) { 252 if (item.equals(it.next())) { 253 return true; 254 } 255 } 256 } 257 return false; 258 } 259 else if (collection instanceof Iterable<?>) { 260 return contains(((Iterable<?>) collection).iterator(), item); 261 } 262 else if (collection.getClass().isArray()) { 263 for (int i = 0; i < Array.getLength(collection); i++) { 264 Object value = Array.get(collection, i); 265 if (value.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 /** 538 * Creates an empty {@link ArrayList} that uses a little cleverness with 539 * Java's generics. Useful for eliminating redundant type information and 540 * declaring fields as {@code final}. 541 * 542 * <p>Used like so: 543 * {@code List<String> listy = arrList();} 544 * 545 * <p>Please consider using {@link #arrList(int)} or 546 * {@link #arrList(java.util.Collection)} instead of this method. 547 * 548 * @return A new, empty {@code ArrayList}. 549 * 550 * @see #arrList(int) 551 * @see #arrList(java.util.Collection) 552 */ 553 @SuppressWarnings({"CollectionWithoutInitialCapacity"}) 554 public static <E> List<E> arrList() { 555 return new ArrayList<E>(); 556 } 557 558 /** 559 * Creates an empty {@link ArrayList} with a given capacity. 560 * 561 * @param capacity The initial size of the returned {@code ArrayList}. 562 * 563 * @return A new, empty {@code ArrayList} that has an initial capacity of 564 * {@code capacity} elements. 565 * 566 * @see ArrayList#ArrayList(int) 567 */ 568 public static <E> List<E> arrList(final int capacity) { 569 return new ArrayList<E>(capacity); 570 } 571 572 /** 573 * Copies an existing {@link Collection} into a new {@link ArrayList}. 574 * 575 * @param c {@code Collection} whose elements are to be placed into the 576 * returned {@code ArrayList}. 577 * 578 * @return An {@code ArrayList} containing the elements of {@code c}. 579 * 580 * @see ArrayList#ArrayList(Collection) 581 */ 582 public static <E> List<E> arrList(final Collection<? extends E> c) { 583 return new ArrayList<E>(c); 584 } 585 586 /** 587 * Copies an existing {@link Collection} into a new (non-abstract!) 588 * {@code Collection} class. 589 * 590 * @param cl Non-abstract {@code Collection} class. 591 * @param old An existing {@code Collection}. 592 * 593 * @return A new instance of {@code cl} that contains all of the elements 594 * from {@code old}. 595 * 596 * @throws RuntimeException if there was trouble creating a new instance 597 * of {@code cl}. 598 * 599 * @see #collect(Class, Object...) 600 */ 601 // not sure about the utility of this one... 602 @SuppressWarnings({ "unchecked", "rawtypes" }) // again, only adding items of type "E" 603 public static <E> Collection<E> recollect(Class<? extends Collection> cl, Collection<E> old) { 604 try { 605 Collection<E> c = cl.getConstructor().newInstance(); 606 c.addAll(old); 607 return c; 608 } catch (Exception e) { 609 throw new RuntimeException("", e); 610 } 611 } 612 613 /** 614 * Takes arrays of {@code keys} and {@code values} and merges them 615 * together to form a {@link Map}. The returned {@code Map} is a 616 * {@link LinkedHashMap} and is truncated in length to the length of the 617 * shorter parameter. 618 * 619 * <p>This is intended for use as {@literal "varargs"} supplied to 620 * {@link #arr(Object...)}. Rather than doing something ugly like: 621 * <pre> 622 * Map<String, String> mappy = new LinkedHashMap<String, String>(); 623 * mappy.put("key0", "val0"); 624 * mappy.put("key1", "val1"); 625 * ... 626 * mappy.put("keyN", "valN"); 627 * </pre> 628 * 629 * Simply do like so: 630 * <pre> 631 * mappy = zipMap( 632 * arr("key0", "key1", ..., "keyN"), 633 * arr("val0", "val1", ..., "valN")); 634 * </pre> 635 * 636 * <p>The latter approach also allows you to make {@code static final} 637 * {@link Map}s much more easily. 638 * 639 * @param keys Array whose elements will be the keys in a {@code Map}. 640 * @param values Array whose elements will the values in a {@code Map}. 641 * 642 * @return A {@code Map} whose entries are of the form 643 * {@code keys[N], values[N]}. 644 * 645 * @see #arr(Object...) 646 * @see #zipMap(java.util.Collection, java.util.Collection) 647 */ 648 public static <K, V> Map<K, V> zipMap(K[] keys, V[] values) { 649 Map<K, V> zipped = new LinkedHashMap<K, V>(keys.length); 650 for (int i = 0; (i < keys.length && i < values.length); i++) { 651 zipped.put(keys[i], values[i]); 652 } 653 return zipped; 654 } 655 656 /** 657 * A version of {@link #zipMap(Object[], Object[])} that works with 658 * {@link Collection}s. 659 * 660 * @param keys Items that will be the keys in the resulting {@code Map}. 661 * @param values Items that will be the values in the result {@code Map}. 662 * 663 * @return A {@code Map} whose entries are of the form 664 * {@code keys[N], values[N]}. 665 * 666 * @see #zipMap(Object[], Object[]) 667 */ 668 public static <K, V> Map<K, V> zipMap(Collection<? extends K> keys, Collection<? extends V> values) { 669 Map<K, V> zipped = new LinkedHashMap<K, V>(keys.size()); 670 Iterator<? extends K> keyIterator = keys.iterator(); 671 Iterator<? extends V> valueIterator = values.iterator(); 672 while (keyIterator.hasNext() && valueIterator.hasNext()) { 673 zipped.put(keyIterator.next(), valueIterator.next()); 674 } 675 return zipped; 676 } 677 678 /** 679 * Applies a given function to each item in a given list. 680 * 681 * @param f The {@link Function} to apply. 682 * @param as The list whose items are to be fed into {@code f}. 683 * 684 * @return New list containing the results of each element of {@code as} 685 * being passed through {@code f}. 686 */ 687 public static <A, B> List<B> map(final Function<A, B> f, List<A> as) { 688 List<B> bs = arrList(as.size()); 689 for (A a : as) { 690 bs.add(f.apply(a)); 691 } 692 return bs; 693 } 694 695 /** 696 * Applies a given function to each item in a given {@link Set}. 697 * 698 * @param f The {@link Function} to apply to {@code as}. 699 * @param as The {@code Set} whose items are to be fed into {@code f}. 700 * 701 * @return New {@code Set} containing the results of passing each element 702 * in {@code as} through {@code f}. 703 */ 704 public static <A, B> Set<B> map(final Function<A, B> f, Set<A> as) { 705 Set<B> bs = newLinkedHashSet(as.size()); 706 for (A a : as) { 707 bs.add(f.apply(a)); 708 } 709 return bs; 710 } 711 712 /** 713 * {@literal "Generics-friendly"} way to cast an object of some superclass 714 * ({@code A}) to a subclass or implementation ({@code B}). This method will 715 * fail if you attempt to cast to a type that is not a subclass of type 716 * {@code A}. 717 * 718 * <p>Example/Justification:<br/> 719 * Consider a method like {@link ucar.unidata.xml.XmlUtil#findChildren(org.w3c.dom.Node, String) XmlUtil.findChildren(Node, String)}.<br/> 720 * Despite {@code findChildren} only returning lists containing {@code Node} 721 * objects, Java will generate a warning for the following code: 722 * <pre> 723 * import ucar.unidata.xml.XmlUtil; 724 * .... 725 * List<Node> nodes = XmlUtil.findChildren(panel, "blah"); 726 * </pre> 727 * {@code cast} is a nice and terse way to avoid those warnings. Here's the 728 * previous example (with static imports of {@code cast} and {@code findChildren}): 729 * <pre> 730 * import static ucar.unidata.xml.XmlUtil.findChildren; 731 * import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.cast; 732 * .... 733 * List<Node> nodes = cast(findChildren(panel, "blah")); 734 * </pre> 735 * 736 * @param <A> Superclass of {@code B}. This is what you are 737 * {@literal "casting from"}...likely {@code Object} in most cases 738 * @param <B> Subclass of {@code A}. This is what you are 739 * {@literal "casting to"}. 740 * 741 * @param o The object whose type you are casting. 742 * 743 * @return {@code o}, casted from type {@code A} to {@code B}. Enjoy! 744 */ 745 @SuppressWarnings("unchecked") public static <A, B extends A> B cast(A o) { 746 return (B)o; 747 } 748}