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 }