All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javaslang.API Maven / Gradle / Ivy

There is a newer version: 0.2.5
Show newest version
/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   JΛVΛSLΛNG
 *  _/  /  /\  \  \/  /  /\  \\__\\  \  //  /\  \ /\\/ \ /__\ \   Copyright 2014-2016 Javaslang, http://javaslang.io
 * /___/\_/  \_/\____/\_/  \_/\__\/__/\__\_/  \_//  \__/\_____/   Licensed under the Apache License, Version 2.0
 */
package javaslang;

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*\
   G E N E R A T O R   C R A F T E D
\*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

import static javaslang.API.Match.*;

import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import javaslang.collection.Iterator;
import javaslang.control.Option;

/**
 * The most basic Javaslang functionality is accessed through this API class.
 *
 * 

 * import static javaslang.API.*;
 * 
* *

For-comprehension

*

* The {@code For}-comprehension is syntactic sugar for nested for-loops. We write * *


 * // lazily evaluated
 * Iterator<R> result = For(iterable1, iterable2, ..., iterableN).yield(f);
 * 
* * or * *

 * Iterator<R> result =
 *     For(iterable1, v1 ->
 *         For(iterable2, v2 ->
 *             ...
 *             For(iterableN).yield(vN -> f.apply(v1, v2, ..., vN))
 *         )
 *     );
 * 
* * instead of * *

 * for(T1 v1 : iterable1) {
 *     for (T2 v2 : iterable2) {
 *         ...
 *         for (TN vN : iterableN) {
 *             R result = f.apply(v1, v2, ..., VN);
 *             //
 *             // We are forced to perform side effects to do s.th. meaningful with the result.
 *             //
 *         }
 *     }
 * }
 * 
* * Please note that values like Option, Try, Future, etc. are also iterable. *

* Given a suitable function * f: {@code (v1, v2, ..., vN) -> ...} and 1 <= N <= 8 iterables, the result is a Stream of the * mapped cross product elements. * *


 * { f(v1, v2, ..., vN) | v1 ∈ iterable1, ... vN ∈ iterableN }
 * 
* * As with all Javaslang Values, the result of a For-comprehension can be converted * to standard Java library and Javaslang types. * @author Daniel Dietrich * @since 2.0.0 */ public final class API { private API() { } // // Java type tweaks // /** * Runs a {@code unit} of work and returns {@code Void}. This is helpful when a return value is expected, * e.g. by {@code Match}: * *
Match(i).of(
     *     Case(is(0), i -> run(() -> System.out.println("zero"))),
     *     Case(is(1), i -> run(() -> System.out.println("one"))),
     *     Case($(), o -> run(() -> System.out.println("many")))
     * )
* * @param unit A block of code to be run. * @return the single instance of {@code Void}, namely {@code null} */ public static Void run(Runnable unit) { unit.run(); return null; } // // For-Comprehension // /** * A shortcut for {@code Iterator.ofAll(ts).flatMap(f)} which allows us to write real for-comprehensions using * {@code For(...).yield(...)}. *

* Example: *


     * For(getPersons(), person ->
     *     For(person.getTweets(), tweet ->
     *         For(tweet.getReplies())
     *             .yield(reply -> person + ", " + tweet + ", " + reply)));
     * 
* * @param ts An iterable * @param f A function {@code T -> Iterable} * @param element type of {@code ts} * @param component type of the resulting {@code Iterator} * @return A new Iterator */ public static Iterator For(Iterable ts, Function> f) { return Iterator.ofAll(ts).flatMap(f); } /** * Creates a {@code For}-comprehension of one Iterable. * * @param ts1 the 1st Iterable * @param component type of the 1st Iterable * @return a new {@code For}-comprehension of arity 1 */ public static For1 For(Iterable ts1) { Objects.requireNonNull(ts1, "ts1 is null"); return new For1<>(ts1); } /** * Creates a {@code For}-comprehension of two Iterables. * * @param ts1 the 1st Iterable * @param ts2 the 2nd Iterable * @param component type of the 1st Iterable * @param component type of the 2nd Iterable * @return a new {@code For}-comprehension of arity 2 */ public static For2 For(Iterable ts1, Iterable ts2) { Objects.requireNonNull(ts1, "ts1 is null"); Objects.requireNonNull(ts2, "ts2 is null"); return new For2<>(ts1, ts2); } /** * Creates a {@code For}-comprehension of three Iterables. * * @param ts1 the 1st Iterable * @param ts2 the 2nd Iterable * @param ts3 the 3rd Iterable * @param component type of the 1st Iterable * @param component type of the 2nd Iterable * @param component type of the 3rd Iterable * @return a new {@code For}-comprehension of arity 3 */ public static For3 For(Iterable ts1, Iterable ts2, Iterable ts3) { Objects.requireNonNull(ts1, "ts1 is null"); Objects.requireNonNull(ts2, "ts2 is null"); Objects.requireNonNull(ts3, "ts3 is null"); return new For3<>(ts1, ts2, ts3); } /** * Creates a {@code For}-comprehension of 4 Iterables. * * @param ts1 the 1st Iterable * @param ts2 the 2nd Iterable * @param ts3 the 3rd Iterable * @param ts4 the 4th Iterable * @param component type of the 1st Iterable * @param component type of the 2nd Iterable * @param component type of the 3rd Iterable * @param component type of the 4th Iterable * @return a new {@code For}-comprehension of arity 4 */ public static For4 For(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4) { Objects.requireNonNull(ts1, "ts1 is null"); Objects.requireNonNull(ts2, "ts2 is null"); Objects.requireNonNull(ts3, "ts3 is null"); Objects.requireNonNull(ts4, "ts4 is null"); return new For4<>(ts1, ts2, ts3, ts4); } /** * Creates a {@code For}-comprehension of 5 Iterables. * * @param ts1 the 1st Iterable * @param ts2 the 2nd Iterable * @param ts3 the 3rd Iterable * @param ts4 the 4th Iterable * @param ts5 the 5th Iterable * @param component type of the 1st Iterable * @param component type of the 2nd Iterable * @param component type of the 3rd Iterable * @param component type of the 4th Iterable * @param component type of the 5th Iterable * @return a new {@code For}-comprehension of arity 5 */ public static For5 For(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5) { Objects.requireNonNull(ts1, "ts1 is null"); Objects.requireNonNull(ts2, "ts2 is null"); Objects.requireNonNull(ts3, "ts3 is null"); Objects.requireNonNull(ts4, "ts4 is null"); Objects.requireNonNull(ts5, "ts5 is null"); return new For5<>(ts1, ts2, ts3, ts4, ts5); } /** * Creates a {@code For}-comprehension of 6 Iterables. * * @param ts1 the 1st Iterable * @param ts2 the 2nd Iterable * @param ts3 the 3rd Iterable * @param ts4 the 4th Iterable * @param ts5 the 5th Iterable * @param ts6 the 6th Iterable * @param component type of the 1st Iterable * @param component type of the 2nd Iterable * @param component type of the 3rd Iterable * @param component type of the 4th Iterable * @param component type of the 5th Iterable * @param component type of the 6th Iterable * @return a new {@code For}-comprehension of arity 6 */ public static For6 For(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5, Iterable ts6) { Objects.requireNonNull(ts1, "ts1 is null"); Objects.requireNonNull(ts2, "ts2 is null"); Objects.requireNonNull(ts3, "ts3 is null"); Objects.requireNonNull(ts4, "ts4 is null"); Objects.requireNonNull(ts5, "ts5 is null"); Objects.requireNonNull(ts6, "ts6 is null"); return new For6<>(ts1, ts2, ts3, ts4, ts5, ts6); } /** * Creates a {@code For}-comprehension of 7 Iterables. * * @param ts1 the 1st Iterable * @param ts2 the 2nd Iterable * @param ts3 the 3rd Iterable * @param ts4 the 4th Iterable * @param ts5 the 5th Iterable * @param ts6 the 6th Iterable * @param ts7 the 7th Iterable * @param component type of the 1st Iterable * @param component type of the 2nd Iterable * @param component type of the 3rd Iterable * @param component type of the 4th Iterable * @param component type of the 5th Iterable * @param component type of the 6th Iterable * @param component type of the 7th Iterable * @return a new {@code For}-comprehension of arity 7 */ public static For7 For(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5, Iterable ts6, Iterable ts7) { Objects.requireNonNull(ts1, "ts1 is null"); Objects.requireNonNull(ts2, "ts2 is null"); Objects.requireNonNull(ts3, "ts3 is null"); Objects.requireNonNull(ts4, "ts4 is null"); Objects.requireNonNull(ts5, "ts5 is null"); Objects.requireNonNull(ts6, "ts6 is null"); Objects.requireNonNull(ts7, "ts7 is null"); return new For7<>(ts1, ts2, ts3, ts4, ts5, ts6, ts7); } /** * Creates a {@code For}-comprehension of 8 Iterables. * * @param ts1 the 1st Iterable * @param ts2 the 2nd Iterable * @param ts3 the 3rd Iterable * @param ts4 the 4th Iterable * @param ts5 the 5th Iterable * @param ts6 the 6th Iterable * @param ts7 the 7th Iterable * @param ts8 the 8th Iterable * @param component type of the 1st Iterable * @param component type of the 2nd Iterable * @param component type of the 3rd Iterable * @param component type of the 4th Iterable * @param component type of the 5th Iterable * @param component type of the 6th Iterable * @param component type of the 7th Iterable * @param component type of the 8th Iterable * @return a new {@code For}-comprehension of arity 8 */ public static For8 For(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5, Iterable ts6, Iterable ts7, Iterable ts8) { Objects.requireNonNull(ts1, "ts1 is null"); Objects.requireNonNull(ts2, "ts2 is null"); Objects.requireNonNull(ts3, "ts3 is null"); Objects.requireNonNull(ts4, "ts4 is null"); Objects.requireNonNull(ts5, "ts5 is null"); Objects.requireNonNull(ts6, "ts6 is null"); Objects.requireNonNull(ts7, "ts7 is null"); Objects.requireNonNull(ts8, "ts8 is null"); return new For8<>(ts1, ts2, ts3, ts4, ts5, ts6, ts7, ts8); } /** * For-comprehension with one Iterable. */ public static class For1 { private final Iterable ts1; private For1(Iterable ts1) { this.ts1 = ts1; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(Function f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).map(f); } } /** * For-comprehension with two Iterables. */ public static class For2 { private final Iterable ts1; private final Iterable ts2; private For2(Iterable ts1, Iterable ts2) { this.ts1 = ts1; this.ts2 = ts2; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(BiFunction f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).flatMap(t1 -> Iterator.ofAll(ts2).map(t2 -> f.apply(t1, t2))); } } /** * For-comprehension with three Iterables. */ public static class For3 { private final Iterable ts1; private final Iterable ts2; private final Iterable ts3; private For3(Iterable ts1, Iterable ts2, Iterable ts3) { this.ts1 = ts1; this.ts2 = ts2; this.ts3 = ts3; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(Function3 f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).flatMap(t1 -> Iterator.ofAll(ts2).flatMap(t2 -> Iterator.ofAll(ts3).map(t3 -> f.apply(t1, t2, t3)))); } } /** * For-comprehension with 4 Iterables. */ public static class For4 { private final Iterable ts1; private final Iterable ts2; private final Iterable ts3; private final Iterable ts4; private For4(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4) { this.ts1 = ts1; this.ts2 = ts2; this.ts3 = ts3; this.ts4 = ts4; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(Function4 f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).flatMap(t1 -> Iterator.ofAll(ts2).flatMap(t2 -> Iterator.ofAll(ts3).flatMap(t3 -> Iterator.ofAll(ts4).map(t4 -> f.apply(t1, t2, t3, t4))))); } } /** * For-comprehension with 5 Iterables. */ public static class For5 { private final Iterable ts1; private final Iterable ts2; private final Iterable ts3; private final Iterable ts4; private final Iterable ts5; private For5(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5) { this.ts1 = ts1; this.ts2 = ts2; this.ts3 = ts3; this.ts4 = ts4; this.ts5 = ts5; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(Function5 f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).flatMap(t1 -> Iterator.ofAll(ts2).flatMap(t2 -> Iterator.ofAll(ts3).flatMap(t3 -> Iterator.ofAll(ts4).flatMap(t4 -> Iterator.ofAll(ts5).map(t5 -> f.apply(t1, t2, t3, t4, t5)))))); } } /** * For-comprehension with 6 Iterables. */ public static class For6 { private final Iterable ts1; private final Iterable ts2; private final Iterable ts3; private final Iterable ts4; private final Iterable ts5; private final Iterable ts6; private For6(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5, Iterable ts6) { this.ts1 = ts1; this.ts2 = ts2; this.ts3 = ts3; this.ts4 = ts4; this.ts5 = ts5; this.ts6 = ts6; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(Function6 f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).flatMap(t1 -> Iterator.ofAll(ts2).flatMap(t2 -> Iterator.ofAll(ts3).flatMap(t3 -> Iterator.ofAll(ts4).flatMap(t4 -> Iterator.ofAll(ts5).flatMap(t5 -> Iterator.ofAll(ts6).map(t6 -> f.apply(t1, t2, t3, t4, t5, t6))))))); } } /** * For-comprehension with 7 Iterables. */ public static class For7 { private final Iterable ts1; private final Iterable ts2; private final Iterable ts3; private final Iterable ts4; private final Iterable ts5; private final Iterable ts6; private final Iterable ts7; private For7(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5, Iterable ts6, Iterable ts7) { this.ts1 = ts1; this.ts2 = ts2; this.ts3 = ts3; this.ts4 = ts4; this.ts5 = ts5; this.ts6 = ts6; this.ts7 = ts7; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(Function7 f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).flatMap(t1 -> Iterator.ofAll(ts2).flatMap(t2 -> Iterator.ofAll(ts3).flatMap(t3 -> Iterator.ofAll(ts4).flatMap(t4 -> Iterator.ofAll(ts5).flatMap(t5 -> Iterator.ofAll(ts6).flatMap(t6 -> Iterator.ofAll(ts7).map(t7 -> f.apply(t1, t2, t3, t4, t5, t6, t7)))))))); } } /** * For-comprehension with 8 Iterables. */ public static class For8 { private final Iterable ts1; private final Iterable ts2; private final Iterable ts3; private final Iterable ts4; private final Iterable ts5; private final Iterable ts6; private final Iterable ts7; private final Iterable ts8; private For8(Iterable ts1, Iterable ts2, Iterable ts3, Iterable ts4, Iterable ts5, Iterable ts6, Iterable ts7, Iterable ts8) { this.ts1 = ts1; this.ts2 = ts2; this.ts3 = ts3; this.ts4 = ts4; this.ts5 = ts5; this.ts6 = ts6; this.ts7 = ts7; this.ts8 = ts8; } /** * Yields a result for elements of the cross product of the underlying Iterables. * * @param f a function that maps an element of the cross product to a result * @param type of the resulting {@code Iterator} elements * @return an {@code Iterator} of mapped results */ public Iterator yield(Function8 f) { Objects.requireNonNull(f, "f is null"); return Iterator.ofAll(ts1).flatMap(t1 -> Iterator.ofAll(ts2).flatMap(t2 -> Iterator.ofAll(ts3).flatMap(t3 -> Iterator.ofAll(ts4).flatMap(t4 -> Iterator.ofAll(ts5).flatMap(t5 -> Iterator.ofAll(ts6).flatMap(t6 -> Iterator.ofAll(ts7).flatMap(t7 -> Iterator.ofAll(ts8).map(t8 -> f.apply(t1, t2, t3, t4, t5, t6, t7, t8))))))))); } } // // Structural Pattern Matching // // -- static Match API /** * Entry point of the match API. * * @param value a value to be matched * @param type of the value * @return a new {@code Match} instance */ public static Match Match(T value) { return new Match<>(value); } // -- static Case API // - Value // Note: The signature ` Case Case(T value, $FunctionType f)` leads to ambiguities! public static Case Case(T value, Supplier supplier) { Objects.requireNonNull(supplier, "supplier is null"); return new Case0<>($(value), ignored -> supplier.get()); } public static Case Case(T value, R retVal) { return new Case0<>($(value), ignored -> retVal); } // - Predicate public static Case Case(Predicate predicate, Function f) { Objects.requireNonNull(predicate, "predicate is null"); Objects.requireNonNull(f, "f is null"); return new Case0<>($(predicate), f); } public static Case Case(Predicate predicate, Supplier supplier) { Objects.requireNonNull(predicate, "predicate is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case0<>($(predicate), ignored -> supplier.get()); } public static Case Case(Predicate predicate, R retVal) { Objects.requireNonNull(predicate, "predicate is null"); return new Case0<>($(predicate), ignored -> retVal); } // - Pattern0 public static Case Case(Pattern0 pattern, Function f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case0<>(pattern, f); } public static Case Case(Pattern0 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case0<>(pattern, ignored -> supplier.get()); } public static Case Case(Pattern0 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case0<>(pattern, ignored -> retVal); } // - Pattern1 public static Case Case(Pattern1 pattern, Function f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case1<>(pattern, f); } public static Case Case(Pattern1 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case1<>(pattern, _1 -> supplier.get()); } public static Case Case(Pattern1 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case1<>(pattern, _1 -> retVal); } // - Pattern2 public static Case Case(Pattern2 pattern, BiFunction f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case2<>(pattern, f); } public static Case Case(Pattern2 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case2<>(pattern, (_1, _2) -> supplier.get()); } public static Case Case(Pattern2 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case2<>(pattern, (_1, _2) -> retVal); } // - Pattern3 public static Case Case(Pattern3 pattern, Function3 f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case3<>(pattern, f); } public static Case Case(Pattern3 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case3<>(pattern, (_1, _2, _3) -> supplier.get()); } public static Case Case(Pattern3 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case3<>(pattern, (_1, _2, _3) -> retVal); } // - Pattern4 public static Case Case(Pattern4 pattern, Function4 f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case4<>(pattern, f); } public static Case Case(Pattern4 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case4<>(pattern, (_1, _2, _3, _4) -> supplier.get()); } public static Case Case(Pattern4 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case4<>(pattern, (_1, _2, _3, _4) -> retVal); } // - Pattern5 public static Case Case(Pattern5 pattern, Function5 f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case5<>(pattern, f); } public static Case Case(Pattern5 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case5<>(pattern, (_1, _2, _3, _4, _5) -> supplier.get()); } public static Case Case(Pattern5 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case5<>(pattern, (_1, _2, _3, _4, _5) -> retVal); } // - Pattern6 public static Case Case(Pattern6 pattern, Function6 f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case6<>(pattern, f); } public static Case Case(Pattern6 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case6<>(pattern, (_1, _2, _3, _4, _5, _6) -> supplier.get()); } public static Case Case(Pattern6 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case6<>(pattern, (_1, _2, _3, _4, _5, _6) -> retVal); } // - Pattern7 public static Case Case(Pattern7 pattern, Function7 f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case7<>(pattern, f); } public static Case Case(Pattern7 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case7<>(pattern, (_1, _2, _3, _4, _5, _6, _7) -> supplier.get()); } public static Case Case(Pattern7 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case7<>(pattern, (_1, _2, _3, _4, _5, _6, _7) -> retVal); } // - Pattern8 public static Case Case(Pattern8 pattern, Function8 f) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(f, "f is null"); return new Case8<>(pattern, f); } public static Case Case(Pattern8 pattern, Supplier supplier) { Objects.requireNonNull(pattern, "pattern is null"); Objects.requireNonNull(supplier, "supplier is null"); return new Case8<>(pattern, (_1, _2, _3, _4, _5, _6, _7, _8) -> supplier.get()); } public static Case Case(Pattern8 pattern, R retVal) { Objects.requireNonNull(pattern, "pattern is null"); return new Case8<>(pattern, (_1, _2, _3, _4, _5, _6, _7, _8) -> retVal); } // PRE-DEFINED PATTERNS // 1) Atomic patterns $(), $(value), $(predicate) /** * Wildcard pattern, matches any value. * * @param injected type of the underlying value * @return a new {@code Pattern0} instance */ public static Pattern0 $() { return Pattern0.any(); } /** * Value pattern, checks for equality. * * @param type of the prototype * @param prototype the value that should be equal to the underlying object * @return a new {@code Pattern0} instance */ public static Pattern0 $(T prototype) { return new Pattern0() { @Override public Option apply(T obj) { return Objects.equals(obj, prototype) ? Option.some(obj) : Option.none(); } }; } /** * Guard pattern, checks if a predicate is satisfied. * * @param type of the prototype * @param predicate the predicate that tests a given value * @return a new {@code Pattern0} instance */ public static Pattern0 $(Predicate predicate) { Objects.requireNonNull(predicate, "predicate is null"); return new Pattern0() { @Override public Option apply(T obj) { return predicate.test(obj) ? Option.some(obj) : Option.none(); } }; } /** * Scala-like structural pattern matching for Java. Instances are obtained via {@link API#Match(Object)}. * @param type of the object that is matched */ public static final class Match { private final T value; private Match(T value) { this.value = value; } // JDK fails here without "unchecked", Eclipse complains that it is unnecessary @SuppressWarnings({ "unchecked", "varargs" }) @SafeVarargs public final R of(Case... cases) { return option(cases).getOrElseThrow(() -> new MatchError(value)); } // JDK fails here without "unchecked", Eclipse complains that it is unnecessary @SuppressWarnings({ "unchecked", "varargs" }) @SafeVarargs public final Option option(Case... cases) { Objects.requireNonNull(cases, "cases is null"); for (Case _case : cases) { final Option result = ((Case) _case).apply(value); if (result.isDefined()) { return result; } } return Option.none(); } // -- CASES // javac needs fqn's here public interface Case extends java.util.function.Function> { } public static final class Case0 implements Case { private final Pattern0 pattern; private final Function f; private Case0(Pattern0 pattern, Function f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T o) { return pattern.apply(o).map(f); } } public static final class Case1 implements Case { private final Pattern1 pattern; private final Function f; private Case1(Pattern1 pattern, Function f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(f); } } public static final class Case2 implements Case { private final Pattern2 pattern; private final BiFunction f; private Case2(Pattern2 pattern, BiFunction f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(t -> f.apply(t._1, t._2)); } } public static final class Case3 implements Case { private final Pattern3 pattern; private final Function3 f; private Case3(Pattern3 pattern, Function3 f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(t -> f.apply(t._1, t._2, t._3)); } } public static final class Case4 implements Case { private final Pattern4 pattern; private final Function4 f; private Case4(Pattern4 pattern, Function4 f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(t -> f.apply(t._1, t._2, t._3, t._4)); } } public static final class Case5 implements Case { private final Pattern5 pattern; private final Function5 f; private Case5(Pattern5 pattern, Function5 f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(t -> f.apply(t._1, t._2, t._3, t._4, t._5)); } } public static final class Case6 implements Case { private final Pattern6 pattern; private final Function6 f; private Case6(Pattern6 pattern, Function6 f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(t -> f.apply(t._1, t._2, t._3, t._4, t._5, t._6)); } } public static final class Case7 implements Case { private final Pattern7 pattern; private final Function7 f; private Case7(Pattern7 pattern, Function7 f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(t -> f.apply(t._1, t._2, t._3, t._4, t._5, t._6, t._7)); } } public static final class Case8 implements Case { private final Pattern8 pattern; private final Function8 f; private Case8(Pattern8 pattern, Function8 f) { this.pattern = pattern; this.f = f; } @Override public Option apply(T obj) { return pattern.apply(obj).map(t -> f.apply(t._1, t._2, t._3, t._4, t._5, t._6, t._7, t._8)); } } // -- PATTERNS /** * A Pattern is a partial {@link Function} in the sense that a function applications returns an * optional result of type {@code Option}. * * @param Class type that is matched by this pattern * @param Type of the single or composite part this pattern decomposes */ // javac needs fqn's here public interface Pattern extends java.util.function.Function> { } // These can't be @FunctionalInterfaces because of ambiguities. // For benchmarks lambda vs. abstract class see http://www.oracle.com/technetwork/java/jvmls2013kuksen-2014088.pdf public static abstract class Pattern0 implements Pattern { private static final Pattern0 ANY = new Pattern0() { @Override public Option apply(Object o) { return Option.some(o); } }; @SuppressWarnings("unchecked") public static Pattern0 any() { return (Pattern0) ANY; } // DEV-NOTE: We need the lower bound `Class` instead of the more appropriate `Class` // because it allows us to create patterns for generic types, which would otherwise not be // possible: `Pattern0> p = Pattern0.of(Some.class);` public static Pattern0 of(Class type) { return new Pattern0() { @Override public Option apply(T obj) { return (obj != null && type.isAssignableFrom(obj.getClass())) ? Option.some(obj) : Option.none(); } }; } private Pattern0() { } } public static abstract class Pattern1 implements Pattern { public static Pattern1 of(Class type, Pattern p1, Function> unapply) { return new Pattern1() { @SuppressWarnings("unchecked") @Override public Option apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { return unapply.apply(obj).transform(u1 -> ((Pattern) p1).apply(u1).map(_1 -> (T1) u1)); } } }; } private Pattern1() { } } public static abstract class Pattern2 implements Pattern> { public static Pattern2 of(Class type, Pattern p1, Pattern p2, Function> unapply) { return new Pattern2() { @SuppressWarnings("unchecked") @Override public Option> apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { final Tuple2 unapplied = unapply.apply(obj); return unapplied.transform((u1, u2) -> ((Pattern) p1).apply(u1).flatMap(_1 -> ((Pattern) p2).apply(u2).map(_2 -> (Tuple2) unapplied) )); } } }; } private Pattern2() { } } public static abstract class Pattern3 implements Pattern> { public static Pattern3 of(Class type, Pattern p1, Pattern p2, Pattern p3, Function> unapply) { return new Pattern3() { @SuppressWarnings("unchecked") @Override public Option> apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { final Tuple3 unapplied = unapply.apply(obj); return unapplied.transform((u1, u2, u3) -> ((Pattern) p1).apply(u1).flatMap(_1 -> ((Pattern) p2).apply(u2).flatMap(_2 -> ((Pattern) p3).apply(u3).map(_3 -> (Tuple3) unapplied) ))); } } }; } private Pattern3() { } } public static abstract class Pattern4 implements Pattern> { public static Pattern4 of(Class type, Pattern p1, Pattern p2, Pattern p3, Pattern p4, Function> unapply) { return new Pattern4() { @SuppressWarnings("unchecked") @Override public Option> apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { final Tuple4 unapplied = unapply.apply(obj); return unapplied.transform((u1, u2, u3, u4) -> ((Pattern) p1).apply(u1).flatMap(_1 -> ((Pattern) p2).apply(u2).flatMap(_2 -> ((Pattern) p3).apply(u3).flatMap(_3 -> ((Pattern) p4).apply(u4).map(_4 -> (Tuple4) unapplied) )))); } } }; } private Pattern4() { } } public static abstract class Pattern5 implements Pattern> { public static Pattern5 of(Class type, Pattern p1, Pattern p2, Pattern p3, Pattern p4, Pattern p5, Function> unapply) { return new Pattern5() { @SuppressWarnings("unchecked") @Override public Option> apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { final Tuple5 unapplied = unapply.apply(obj); return unapplied.transform((u1, u2, u3, u4, u5) -> ((Pattern) p1).apply(u1).flatMap(_1 -> ((Pattern) p2).apply(u2).flatMap(_2 -> ((Pattern) p3).apply(u3).flatMap(_3 -> ((Pattern) p4).apply(u4).flatMap(_4 -> ((Pattern) p5).apply(u5).map(_5 -> (Tuple5) unapplied) ))))); } } }; } private Pattern5() { } } public static abstract class Pattern6 implements Pattern> { public static Pattern6 of(Class type, Pattern p1, Pattern p2, Pattern p3, Pattern p4, Pattern p5, Pattern p6, Function> unapply) { return new Pattern6() { @SuppressWarnings("unchecked") @Override public Option> apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { final Tuple6 unapplied = unapply.apply(obj); return unapplied.transform((u1, u2, u3, u4, u5, u6) -> ((Pattern) p1).apply(u1).flatMap(_1 -> ((Pattern) p2).apply(u2).flatMap(_2 -> ((Pattern) p3).apply(u3).flatMap(_3 -> ((Pattern) p4).apply(u4).flatMap(_4 -> ((Pattern) p5).apply(u5).flatMap(_5 -> ((Pattern) p6).apply(u6).map(_6 -> (Tuple6) unapplied) )))))); } } }; } private Pattern6() { } } public static abstract class Pattern7 implements Pattern> { public static Pattern7 of(Class type, Pattern p1, Pattern p2, Pattern p3, Pattern p4, Pattern p5, Pattern p6, Pattern p7, Function> unapply) { return new Pattern7() { @SuppressWarnings("unchecked") @Override public Option> apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { final Tuple7 unapplied = unapply.apply(obj); return unapplied.transform((u1, u2, u3, u4, u5, u6, u7) -> ((Pattern) p1).apply(u1).flatMap(_1 -> ((Pattern) p2).apply(u2).flatMap(_2 -> ((Pattern) p3).apply(u3).flatMap(_3 -> ((Pattern) p4).apply(u4).flatMap(_4 -> ((Pattern) p5).apply(u5).flatMap(_5 -> ((Pattern) p6).apply(u6).flatMap(_6 -> ((Pattern) p7).apply(u7).map(_7 -> (Tuple7) unapplied) ))))))); } } }; } private Pattern7() { } } public static abstract class Pattern8 implements Pattern> { public static Pattern8 of(Class type, Pattern p1, Pattern p2, Pattern p3, Pattern p4, Pattern p5, Pattern p6, Pattern p7, Pattern p8, Function> unapply) { return new Pattern8() { @SuppressWarnings("unchecked") @Override public Option> apply(T obj) { if (obj == null || !type.isAssignableFrom(obj.getClass())) { return Option.none(); } else { final Tuple8 unapplied = unapply.apply(obj); return unapplied.transform((u1, u2, u3, u4, u5, u6, u7, u8) -> ((Pattern) p1).apply(u1).flatMap(_1 -> ((Pattern) p2).apply(u2).flatMap(_2 -> ((Pattern) p3).apply(u3).flatMap(_3 -> ((Pattern) p4).apply(u4).flatMap(_4 -> ((Pattern) p5).apply(u5).flatMap(_5 -> ((Pattern) p6).apply(u6).flatMap(_6 -> ((Pattern) p7).apply(u7).flatMap(_7 -> ((Pattern) p8).apply(u8).map(_8 -> (Tuple8) unapplied) )))))))); } } }; } private Pattern8() { } } } }