1 /*
   2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @summary This class provide basic support for lambda syntax
  26  * @(#) LambdaUtilities.java
  27  * @author Tristan Yan
  28  */
  29 
  30 import java.lang.reflect.Constructor;
  31 import java.lang.reflect.InvocationTargetException;
  32 import java.math.BigDecimal;
  33 import java.nio.file.Path;
  34 import java.util.*;
  35 import java.util.concurrent.atomic.AtomicInteger;
  36 import java.util.concurrent.atomic.AtomicLong;
  37 import java.util.concurrent.atomic.AtomicReference;
  38 import java.util.function.*;
  39 import java.util.stream.IntStream;
  40 import java.util.stream.Stream;
  41 
  42 public class LambdaUtilities {
  43 
  44     public static enum CharType {
  45         DIGIT, LOWERCASE, UPPERCASE, SPECIAL
  46     }
  47 
  48     public static enum StringPredicateType {
  49         START_WTIH, NOT_START_WITH, MORE_THAN_LEN, LESS_THAN_LEN
  50     }
  51 
  52     public static enum IntOp {
  53         ADD, SUBTRACT, MULTIPLY, DIVIDE, MOD
  54     }
  55 
  56     public static IntPredicate randomIntPredicate(boolean isUP, int limit) {
  57         if (isUP) {
  58             return i -> i >= limit;
  59         } else {
  60             return i -> i < limit;
  61         }
  62     }
  63 
  64     public static Predicate<Integer> randomIntegerPredicate(boolean isUP, int limit) {
  65         if (isUP) {
  66             return i -> i >= limit;
  67         } else {
  68             return i -> i < limit;
  69         }
  70     }
  71 
  72     public static LongPredicate randomLongPredicate(boolean isUP, long limit) {
  73         if (isUP) {
  74             return i -> i >= limit;
  75         } else {
  76             return i -> i < limit;
  77         }
  78     }
  79 
  80     public static Predicate<Path> startPathPredicate(Path start) {
  81         return p -> p.startsWith(start);
  82     }
  83 
  84     public static <T> Predicate<T> randomGenericPredicate(boolean isUp, T value, Comparator<T> c) {
  85         if (isUp) {
  86             return emp -> c.compare(emp, value) >= 0;
  87         }else {
  88             return emp -> c.compare(emp, value) < 0;
  89         }
  90     }
  91 
  92     public static Predicate<StringBuilder> randomSBPredicate(StringPredicateType type, String value) {
  93         switch (type) {
  94             case START_WTIH:
  95                 return sb -> Character.isDigit(sb.charAt(0));
  96             case NOT_START_WITH:
  97                 return sb -> Character.isLowerCase(sb.charAt(0));
  98             case MORE_THAN_LEN:
  99                 return sb -> Character.isUpperCase(sb.charAt(0));
 100             default:
 101                 return sb -> !Character.isLetterOrDigit(sb.charAt(0));
 102         }
 103     }
 104 
 105     public static Predicate<? extends CharSequence> randomSBPredicate(CharType startType,
 106             boolean first) {
 107         switch (startType) {
 108             case DIGIT:
 109                 return sb -> Character.isDigit(sb.charAt(first ? 0 : sb.toString().length() - 1));
 110             case LOWERCASE:
 111                 return sb -> Character.isLowerCase(sb.charAt(first ? 0 : sb.toString().length() - 1));
 112             case UPPERCASE:
 113                 return sb -> Character.isUpperCase(sb.charAt(first ? 0 : sb.toString().length() - 1));
 114             default:
 115                 return sb -> !Character.isLetterOrDigit(sb.charAt(first ? 0 : sb.toString().length() - 1));
 116         }
 117     }
 118 
 119     public static Predicate<Character> isDigitCharacterPredicate() {
 120         return c -> Character.isDigit(c);
 121     }
 122 
 123     public static Function<Integer, Integer> posIntegerFunction(boolean isHighest) {
 124         if (isHighest) {
 125             return i -> Integer.valueOf(new StringBuilder().append(i < 0 ? -i : i).reverse().toString()) % 10;
 126         } else {
 127             return i -> i % 10 < 0 ? -i % 10 : i % 10;
 128         }
 129     }
 130 
 131     public static Function<StringBuilder, CharType> sbGenericFunction(boolean isFirst) {
 132         if (isFirst)
 133             return i -> Character.isAlphabetic(i.charAt(0)) ? (Character.isUpperCase(i.charAt(0)) ? CharType.UPPERCASE : CharType.LOWERCASE) : (Character.isDigit(i.charAt(0)) ? CharType.DIGIT : CharType.SPECIAL);
 134             else
 135             return i -> Character.isAlphabetic(i.charAt(i.length() - 1)) ? (Character.isUpperCase(i.charAt(i.length() - 1)) ? CharType.UPPERCASE : CharType.LOWERCASE) : (Character.isDigit(i.charAt(i.length() - 1)) ? CharType.DIGIT : CharType.SPECIAL);
 136     }
 137 
 138     public static Function<String, Integer> mappingFunction(Map<String, Integer> m, IntOp op, int value) {
 139         switch (op) {
 140             case ADD:
 141                 return k -> (value != 0) ? m.get(k) + value : m.get(k);
 142             case SUBTRACT:
 143                 return k -> (value != 0) ? m.get(k) - value : m.get(k);
 144             case MULTIPLY:
 145                 return k -> (value != 0) ? m.get(k) * value : m.get(k);
 146             case DIVIDE:
 147                 return k -> (value != 0) ? m.get(k) / value : m.get(k);
 148             default:
 149                 return k -> (value != 0) ? m.get(k) % value : m.get(k);
 150         }
 151     }
 152 
 153     public static IntFunction<Integer> posIntFunction(boolean isHighest) {
 154         if (isHighest) {
 155             return i -> Integer.valueOf(new StringBuilder().append(i < 0 ? -i : i).reverse().toString()) % 10;
 156         } else {
 157             return i -> i % 10 < 0 ? -i % 10 : i % 10;
 158         }
 159     }
 160 
 161     public static BiFunction<Integer, Integer, Integer> randBetweenIntegerFunction() {
 162         return (t1, t2) -> randBetween(t1, t2);
 163     }
 164 
 165     public static int randBetween(int low, int up) {
 166         assert (low < up && low >= 0);
 167         Random rand = new Random();
 168         int i = rand.nextInt(up);
 169         while (i < low) {
 170             i = rand.nextInt();
 171         }
 172         return i;
 173     }
 174 
 175     public static ToIntFunction<Integer> highestPosValueIntFunction() {
 176         return i -> Integer.valueOf(new StringBuilder().append(i < 0 ? -i : i).reverse().toString()) % 10;
 177     }
 178 
 179     public static ToIntFunction<Integer> lowestPosValueIntFunction() {
 180         return i -> i % 10 < 0 ? -i % 10 : i % 10;
 181     }
 182 
 183     public static <T> Consumer<T> reverseConsumer(Set<T> set) {
 184         return t -> {
 185             set.add(t);
 186         };
 187     }
 188 
 189     public static Consumer<Integer> addIntegerConsumer(AtomicInteger ai) {
 190         return t -> {
 191             ai.updateAndGet(t1 -> t1 + t);
 192         };
 193     }
 194 
 195     public static Consumer<StringBuilder> appendSBConsumer(StringBuilder sb) {
 196         return t -> {
 197             sb.append(t);
 198         };
 199     }
 200 
 201     public static IntConsumer addIntConsumer(AtomicInteger ai) {
 202         return t -> {
 203             ai.updateAndGet(t1 -> t1 + t);
 204         };
 205     }
 206 
 207     public static IntConsumer addLongConsumer(AtomicLong ai) {
 208         return t -> {
 209             ai.updateAndGet(t1 -> t1 + t);
 210         };
 211     }
 212 
 213     public static <T> Consumer<T> copyConsumer(List<T> list) {
 214         return t -> {
 215             list.add(t);
 216         };
 217     }
 218 
 219     public static <T> Consumer<T> existsConsumer(Collection<T> in, Collection<T> out) {
 220         return t -> {
 221             if (in.contains(t)) {
 222                 out.add(t);
 223             }
 224         };
 225     }
 226 
 227     public static Supplier<StringBuilder> sbSupplier(StringBuilder value) {
 228         return () -> value;
 229     }
 230 
 231     public static Supplier<Integer> integerSupplier(int value) {
 232         return () -> value;
 233     }
 234 
 235     public static <T> Supplier<T> genericSuppiler(T value) {
 236         return () -> value;
 237     }
 238 
 239     public static IntSupplier intSupplier(int value) {
 240         return () -> value;
 241     }
 242 
 243     public static Supplier<Long> longSupplier(long value) {
 244         return () -> value;
 245     }
 246 
 247     public static Supplier<AtomicInteger> atomicIntegerSupplier(int value) {
 248         return () -> new AtomicInteger(value);
 249     }
 250 
 251     public static <T> Supplier<AtomicReference<T>> atomicGenericSupplier(T value) {
 252         return () -> new AtomicReference<>(value);
 253     }
 254 
 255     public static Supplier<AtomicReference<StringBuilder>> atomicSBSupplier(StringBuilder value) {
 256         return () -> new AtomicReference<>(value);
 257     }
 258 
 259     public static UnaryOperator<Integer> opIntegerUnaryOperator(IntOp op, int value) {
 260         switch (op) {
 261             case ADD:
 262                 return t -> t + value;
 263             case SUBTRACT:
 264                 return t -> t - value;
 265             case MULTIPLY:
 266                 return t -> t * value;
 267             case DIVIDE:
 268                 return t -> t / value;
 269             default:
 270                 return t -> t % value;
 271         }
 272     }
 273 
 274     public static IntUnaryOperator opIntUnaryOperator(IntOp op, int value) {
 275         if(value == 0)
 276             return t -> t;
 277         switch (op) {
 278             case ADD:
 279                 return t -> t + value;
 280             case SUBTRACT:
 281                 return t -> t - value;
 282             case MULTIPLY:
 283                 return t -> t * value;
 284             case DIVIDE:
 285                 return t -> t / value;
 286             default:
 287                 return t -> t % value;
 288         }
 289     }
 290 
 291     public static Function<Integer, Integer> opIntegerFunction(IntOp op, int value) {
 292         if(value == 0)
 293             return t -> t;
 294         switch (op) {
 295             case ADD:
 296                 return t -> Integer.valueOf(t + value);
 297             case SUBTRACT:
 298                 return t -> Integer.valueOf(t - value);
 299             case MULTIPLY:
 300                 return t -> Integer.valueOf(t * value);
 301             case DIVIDE:
 302                 return t -> Integer.valueOf(t / value);
 303             default:
 304                 return t -> Integer.valueOf(t % value);
 305         }
 306     }
 307 
 308     public static ToIntFunction<Integer> opToIntFunction(IntOp op, int value) {
 309         if(value == 0)
 310             return t -> t.intValue();
 311         switch (op) {
 312             case ADD:
 313                 return t -> t.intValue() + value;
 314             case SUBTRACT:
 315                 return t -> t.intValue() - value;
 316             case MULTIPLY:
 317                 return t -> t.intValue() * value;
 318             case DIVIDE:
 319                 return t -> t.intValue() / value;
 320             default:
 321                 return t -> t.intValue() % value;
 322         }
 323     }
 324 
 325     public static IntFunction<Integer> opIntFunction(IntOp op, int value) {
 326         if(value == 0)
 327             return t -> t;
 328         switch (op) {
 329             case ADD:
 330                 return t -> t + value;
 331             case SUBTRACT:
 332                 return t -> t - value;
 333             case MULTIPLY:
 334                 return t -> t * value;
 335             case DIVIDE:
 336                 return t -> t / value;
 337             default:
 338                 return t -> t % value;
 339         }
 340     }
 341 
 342     public static IntUnaryOperator addIntUnaryOperator(int value) {
 343         return t -> t + value;
 344     }
 345 
 346     public static IntUnaryOperator subIntUnaryOperator(int value) {
 347         return t -> t - value;
 348     }
 349 
 350     public static IntUnaryOperator mulIntUnaryOperator(int value) {
 351         return t -> t * value;
 352     }
 353 
 354     public static IntUnaryOperator divIntUnaryOperator(int value) {
 355         return t -> t / value;
 356     }
 357 
 358     public static IntBinaryOperator minIntBinaryOperator() {
 359         return (t1, t2) -> t1< t2 ? t1 : t2;
 360     }
 361 
 362     public static BinaryOperator<Integer> minIntegerBinaryOperator(Comparator<Integer> c) {
 363         return (t1, t2) -> c.compare(t1, t2) < 0 ? t1 : t2;
 364     }
 365 
 366     public static <T>BinaryOperator<T> minGenericBinaryOperator(Comparator<T> c) {
 367         return (t1, t2) -> c.compare(t1, t2) < 0 ? t1 : t2;
 368     }
 369 
 370     public static BinaryOperator<StringBuilder> minSBBinaryOperator(Comparator<StringBuilder>  c) {
 371         return ( t1, t2 ) -> c.compare(t1, t2) < 0 ? t1 : t2;
 372     }
 373 
 374     public static IntBinaryOperator maxIntBinaryOperator() {
 375         return ( t1, t2 ) -> (t1< t2) ? t2: t1;
 376     }
 377 
 378     public static BinaryOperator<Integer> maxIntegerBinaryOperator(Comparator<Integer>  c) {
 379         return (t1, t2) -> c.compare(t1, t2) < 0 ? t2 : t1;
 380     }
 381 
 382     public static <T> BinaryOperator<T> maxGenericBinaryOperator(Comparator<T>  c) {
 383         return (t1, t2) -> c.compare(t1, t2) < 0 ? t2 : t1;
 384     }
 385 
 386     public static IntBinaryOperator maxIntBinaryOperator(Comparator<Integer>  c) {
 387         return ( t1, t2 ) -> c.compare(t1, t2) < 0 ? t2 : t1;
 388     }
 389 
 390     public static BinaryOperator<StringBuilder> maxSBBinaryOperator(Comparator<StringBuilder>  c) {
 391         return ( t1, t2 ) -> c.compare(t1, t2) < 0 ? t2 : t1;
 392     }
 393 
 394     public static BinaryOperator<Integer> addIntegerBinaryOperator() {
 395         return ( t1 , t2 ) -> t1 + t2;
 396     }
 397 
 398     public static IntBinaryOperator addIntBinaryOperator() {
 399         return ( t1 , t2 ) -> t1 + t2;
 400     }
 401 
 402     public static BinaryOperator<BigDecimal> addBigDecimalBinaryOperator() {
 403         return ( t1 , t2 ) -> t1.add(t2);
 404     }
 405 
 406     public static DoubleBinaryOperator addDoubleBinaryOperator() {
 407         return ( t1 , t2 ) -> t1 + t2;
 408     }
 409 
 410     public static BinaryOperator<StringBuilder> appendSBBinaryOperator() {
 411         return (t1 , t2) -> new StringBuilder().append(t1).append(t2);
 412     }
 413 
 414     public static BinaryOperator<Integer> subIntegerBinaryOperator() {
 415         return (t1, t2) -> t1 - t2;
 416     }
 417 
 418     public static IntBinaryOperator subIntBinaryOperator() {
 419         return (t1, t2) -> t1 - t2;
 420     }
 421 
 422     public static BinaryOperator<StringBuilder> deleteSBBinaryOperator() {
 423         return (t1, t2) -> {if (t1.length() >= t2.length()) {
 424                                 int i1 = t1.indexOf(t2.toString());
 425                                 int i2 = i1 + t2.length();
 426                                 return new StringBuilder(t1).delete(i1, i2);
 427                             }else {
 428                                 int i1 = t2.indexOf(t1.toString());
 429                                 int i2 = i1 + t1.length();
 430                                 return new StringBuilder(t2).delete(i1, i2);
 431                             }
 432         };
 433 
 434     }
 435 
 436     public static IntBinaryOperator mulIntBinaryOperator() {
 437         return (t1, t2) -> t1 * t2;
 438     }
 439 
 440     public static IntBinaryOperator divIntBinaryOperator() {
 441         return (t1, t2) -> t1 / t2;
 442     }
 443 
 444     public static LongUnaryOperator addLongUnaryOperator(long value) {
 445         return t -> t + value;
 446     }
 447 
 448     public static UnaryOperator<StringBuilder> appendSBUnaryOperator(StringBuilder value) {
 449         return t -> t.append(value);
 450     }
 451 
 452     public static LongUnaryOperator subLongUnaryOperator(long value) {
 453         return t -> t - value;
 454     }
 455 
 456     public static LongUnaryOperator mulLongUnaryOperator(long value) {
 457         return t -> t * value;
 458     }
 459 
 460     public static LongUnaryOperator divLongUnaryOperator(long value) {
 461         return t -> t / value;
 462     }
 463 
 464     public static LongBinaryOperator addLongBinaryOperator() {
 465         return (t1, t2) -> t1 + t2;
 466     }
 467 
 468     public static LongBinaryOperator subLongBinaryOperator() {
 469         return (t1, t2) -> t1 - t2;
 470     }
 471 
 472     public static LongBinaryOperator mulLongBinaryOperator() {
 473         return (t1, t2) -> t1 * t2;
 474     }
 475 
 476     public static LongBinaryOperator divLongBinaryOperator() {
 477         return (t1, t2) -> t1 / t2;
 478     }
 479 
 480     public static BiConsumer<AtomicInteger, Integer> addIntegerBiConsumer() {
 481         return (t1 , t2 ) -> {  t1.addAndGet(t2); };
 482     }
 483 
 484     public static BiConsumer<AtomicInteger, AtomicInteger> addAtomicIntegerBiConsumer() {
 485         return (t1 , t2) -> {  t1.addAndGet(t2.get()); };
 486     }
 487 
 488     public static BiConsumer<AtomicReference<StringBuilder>, StringBuilder> appendSBBiConsumer() {
 489         return (t1, t2) -> {t1.updateAndGet(appendSBUnaryOperator(t2));};
 490     }
 491 
 492     public static BiConsumer<AtomicReference<StringBuilder>, AtomicReference<StringBuilder>> appendAtomicSBBiConsumer() {
 493         return (t1, t2) -> {t1.updateAndGet(appendSBUnaryOperator(t2.get()));};
 494     }
 495 
 496     public static BiConsumer<AtomicInteger, Integer> maxIntegerBiConsumer(Comparator<Integer> c) {
 497         return (t1 , t2 ) -> {  t1.getAndUpdate(t -> max(t, t2, c)); };
 498     }
 499 
 500     public static <T> BiConsumer<AtomicReference<T>, T> maxGenericBiConsumer(Comparator<T> c) {
 501         return (t1 , t2 ) -> {  t1.getAndUpdate(t -> max(t, t2, c)); };
 502     }
 503 
 504     public static BiConsumer<AtomicInteger, AtomicInteger> maxAtomicIntegerBiConsumer(Comparator<Integer> c) {
 505         return (t1 , t2) -> {  t1.getAndUpdate(t -> max(t, t2.get(), c)); };
 506     }
 507 
 508     public static <T> BiConsumer<AtomicReference<T>, AtomicReference<T>> maxAtomicGenericBiConsumer(Comparator<T> c) {
 509         return (t1 , t2) -> {  t1.getAndUpdate(t -> max(t, t2.get(), c)); };
 510     }
 511 
 512     public static BiConsumer<AtomicInteger, Integer> minIntegerBiConsumer(Comparator<Integer> c) {
 513         return (t1 , t2) -> {  t1.getAndUpdate(t -> min(t, t2, c)); };
 514     }
 515 
 516     public static <T> BiConsumer<AtomicReference<T>, T> minGenericBiConsumer(Comparator<T> c) {
 517         return (t1 , t2) -> {  t1.getAndUpdate(t -> min(t, t2, c)); };
 518     }
 519 
 520     public static BiConsumer<AtomicInteger, AtomicInteger> minAtomicIntegerBiConsumer(Comparator<Integer> c) {
 521         return (t1, t2) -> {  t1.getAndUpdate(t -> min(t, t2.get(), c)); };
 522     }
 523 
 524     public static <T> BiConsumer<AtomicReference<T>, AtomicReference<T>> minAtomicGenericBiConsumer(Comparator<T> c) {
 525         return (t1, t2) -> {  t1.getAndUpdate(t -> min(t, t2.get(), c)); };
 526     }
 527 
 528     public static BiFunction<Integer, Integer, Integer> maxIntegerFunction(Comparator<Integer> c) {
 529         return (t1, t2) -> max(t1, t2, c);
 530     }
 531 
 532     public static BiFunction<BigDecimal, Integer, BigDecimal> deviationSequareFunction(double avg) {
 533         return (bd, t) -> bd.add(new BigDecimal(avg - t).pow(2));
 534     }
 535 
 536     public static <T> BiFunction<T, T, T> maxGenericFunction(Comparator<T> c) {
 537         return (t1, t2) -> max(t1, t2, c);
 538     }
 539 
 540     public static BiFunction<StringBuilder, StringBuilder, StringBuilder> maxStringBuilderFunction(Comparator<StringBuilder> c) {
 541         return (t1, t2) -> max(t1, t2, c);
 542     }
 543 
 544     public static BiFunction<Integer, Integer, Integer> minIntegerFunction(Comparator<Integer> c) {
 545         return (t1, t2) -> min(t1, t2, c);
 546     }
 547 
 548     public static <T> BiFunction<T, T, T> minGenericFunction(Comparator<T> c) {
 549         return (t1, t2) -> min(t1, t2, c);
 550     }
 551 
 552     public static BiFunction<StringBuilder, StringBuilder, StringBuilder> minStringBuilderFunction(Comparator<StringBuilder> c) {
 553         return (t1, t2) -> min(t1, t2, c);
 554     }
 555 
 556     public static BiFunction<String, Integer, Integer> opBiFunction(IntOp op, int value) {
 557         switch (op) {
 558             case ADD:
 559                 return (k, v) -> (value != 0) ? v + value : v;
 560             case SUBTRACT:
 561                 return (k, v) -> (value != 0) ? v - value : v;
 562             case MULTIPLY:
 563                 return (k, v) -> (value != 0) ? v * value : v;
 564             case DIVIDE:
 565                 return (k, v) -> (value != 0) ? v / value : v;
 566             default:
 567                 return (k, v) -> (value != 0) ? v % value : v;
 568         }
 569     }
 570 
 571 
 572     public static BiFunction<Integer, Integer, Integer> opBiFunction(IntOp op) {
 573         switch (op) {
 574             case ADD:
 575                 return (oldv, v) -> (v != 0) ? oldv + v : oldv;
 576             case SUBTRACT:
 577                 return (oldv, v) -> (v != 0) ? oldv - v : oldv;
 578             case MULTIPLY:
 579                 return (oldv, v) -> (v != 0) ? oldv * v : oldv;
 580             case DIVIDE:
 581                 return (oldv, v) -> (v != 0) ? oldv / v : oldv;
 582             default:
 583                 return (oldv, v) -> (v != 0) ? oldv % v : oldv;
 584         }
 585     }
 586 
 587     private static Integer min(Integer i1, Integer i2, Comparator<Integer> c) {
 588         return c.compare(i1, i2) < 0 ? i1 : i2;
 589     }
 590 
 591     private static <T> T min(T i1, T i2, Comparator<T> c) {
 592         return c.compare(i1, i2) < 0 ? i1 : i2;
 593     }
 594 
 595     private static StringBuilder min(StringBuilder sb1, StringBuilder sb2, Comparator<StringBuilder> c) {
 596         return c.compare(sb1, sb2) < 0 ? sb1 : sb2;
 597     }
 598 
 599     private static Integer max(Integer i1, Integer i2, Comparator<Integer> c) {
 600         return c.compare(i1, i2) < 0 ? i2 : i1;
 601     }
 602 
 603     private static <T> T max(T i1, T i2, Comparator<T> c) {
 604         return c.compare(i1, i2) < 0 ? i2 : i1;
 605     }
 606 
 607     private static StringBuilder max(StringBuilder sb1, StringBuilder sb2, Comparator<StringBuilder> c) {
 608         return c.compare(sb1, sb2) < 0 ? sb2 : sb1;
 609     }
 610     /*
 611      * Construct a Collection C object based on a C object, using generic type
 612      * instead of Class type can help preventing type error in compilation
 613      */
 614     @SuppressWarnings({"rawtypes", "unchecked"})
 615     public static <E, C extends Collection<E>>  C create(C c, int... initSize)
 616             throws InstantiationException, IllegalAccessException,
 617             NoSuchMethodException, IllegalArgumentException,
 618             InvocationTargetException {
 619         return create((Class<C>) c.getClass(), initSize);
 620     }
 621 
 622     /*
 623      * Construct a Collection C object based on a C's type, using generic type
 624      * instead of Class type can help preventing type error in compilation
 625      */
 626     @SuppressWarnings({"rawtypes", "unchecked"})
 627     public static <E, T extends Collection<E>>  T create(
 628             Class<? extends Collection<E>> cls, int... initSize)
 629             throws InstantiationException, IllegalAccessException,
 630             NoSuchMethodException, IllegalArgumentException,
 631             InvocationTargetException {
 632         assert (initSize.length <= 1);
 633         Collection<E> c;
 634         if (initSize.length == 0) {
 635             c = cls.newInstance();
 636         } else {
 637             Constructor con = cls.getConstructor(int.class);
 638             c = (Collection<E>) con.newInstance(initSize[0]);
 639         }
 640         return (T) c;
 641     }
 642 
 643     /*
 644      * Construct a T object based on T's type, using generic type instead of
 645      * Class type can help preventing type error in compilation
 646      */
 647     @SuppressWarnings({"rawtypes", "unchecked"})
 648     public static <K, V, M extends Map<K, V>>  M createMap(M m, int... initSize)
 649             throws InstantiationException, IllegalAccessException,
 650             NoSuchMethodException, IllegalArgumentException,
 651             InvocationTargetException {
 652         return createMap((Class<M>) m.getClass(), initSize);
 653     }
 654 
 655     /*
 656      * Construct a Map M object based on M's type, using generic type instead of
 657      * Class type can help preventing type error in compilation
 658      */
 659     @SuppressWarnings({"rawtypes", "unchecked"})
 660     public static <K, V, M extends Map<K, V>>  M createMap(Class<? extends Map<K, V>> cls,
 661             int... initSize) throws InstantiationException,
 662             IllegalAccessException, NoSuchMethodException,
 663             IllegalArgumentException, InvocationTargetException {
 664         assert (initSize.length <= 1);
 665         Map<K, V> map;
 666         if (initSize.length == 0) {
 667             map = cls.newInstance();
 668         } else {
 669             Constructor con = cls.getConstructor(int.class);
 670             map = (Map<K, V>) con.newInstance(initSize[0]);
 671         }
 672         return (M) map;
 673     }
 674 }