/* __ __ __ __ __ ___ * \ \ / / \ \ / / __/ * \ \/ / /\ \ \/ / / * \____/__/ \__\____/__/.ɪᴏ * ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ */ package io.vavr; /*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*\ G E N E R A T O R C R A F T E D \*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/ import static io.vavr.CheckedFunction3Module.sneakyThrow; import io.vavr.control.Option; import io.vavr.control.Try; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.function.Function; /** * Represents a function with three arguments. * * @param <T1> argument 1 of the function * @param <T2> argument 2 of the function * @param <T3> argument 3 of the function * @param <R> return type of the function * @author Daniel Dietrich */ @FunctionalInterface public interface CheckedFunction3<T1, T2, T3, R> extends Lambda<R> { /** * The <a href="https://docs.oracle.com/javase/8/docs/api/index.html">serial version uid</a>. */ long serialVersionUID = 1L; /** * Creates a {@code CheckedFunction3} based on * <ul> * <li><a href="https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html">method reference</a></li> * <li><a href="https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#syntax">lambda expression</a></li> * </ul> * * Examples (w.l.o.g. referring to Function1): * <pre><code>// using a lambda expression * Function1<Integer, Integer> add1 = Function1.of(i -> i + 1); * * // using a method reference (, e.g. Integer method(Integer i) { return i + 1; }) * Function1<Integer, Integer> add2 = Function1.of(this::method); * * // using a lambda reference * Function1<Integer, Integer> add3 = Function1.of(add1::apply); * </code></pre> * <p> * <strong>Caution:</strong> Reflection loses type information of lambda references. * <pre><code>// type of a lambda expression * Type<?, ?> type1 = add1.getType(); // (Integer) -> Integer * * // type of a method reference * Type<?, ?> type2 = add2.getType(); // (Integer) -> Integer * * // type of a lambda reference * Type<?, ?> type3 = add3.getType(); // (Object) -> Object * </code></pre> * * @param methodReference (typically) a method reference, e.g. {@code Type::method} * @param <R> return type * @param <T1> 1st argument * @param <T2> 2nd argument * @param <T3> 3rd argument * @return a {@code CheckedFunction3} */ static <T1, T2, T3, R> CheckedFunction3<T1, T2, T3, R> of(CheckedFunction3<T1, T2, T3, R> methodReference) { return methodReference; } /** * Lifts the given {@code partialFunction} into a total function that returns an {@code Option} result. * * @param partialFunction a function that is not defined for all values of the domain (e.g. by throwing) * @param <R> return type * @param <T1> 1st argument * @param <T2> 2nd argument * @param <T3> 3rd argument * @return a function that applies arguments to the given {@code partialFunction} and returns {@code Some(result)} * if the function is defined for the given arguments, and {@code None} otherwise. */ @SuppressWarnings("RedundantTypeArguments") static <T1, T2, T3, R> Function3<T1, T2, T3, Option<R>> lift(CheckedFunction3<? super T1, ? super T2, ? super T3, ? extends R> partialFunction) { return (t1, t2, t3) -> Try.<R>of(() -> partialFunction.apply(t1, t2, t3)).toOption(); } /** * Lifts the given {@code partialFunction} into a total function that returns an {@code Try} result. * * @param partialFunction a function that is not defined for all values of the domain (e.g. by throwing) * @param <R> return type * @param <T1> 1st argument * @param <T2> 2nd argument * @param <T3> 3rd argument * @return a function that applies arguments to the given {@code partialFunction} and returns {@code Success(result)} * if the function is defined for the given arguments, and {@code Failure(throwable)} otherwise. */ static <T1, T2, T3, R> Function3<T1, T2, T3, Try<R>> liftTry(CheckedFunction3<? super T1, ? super T2, ? super T3, ? extends R> partialFunction) { return (t1, t2, t3) -> Try.of(() -> partialFunction.apply(t1, t2, t3)); } /** * Narrows the given {@code CheckedFunction3<? super T1, ? super T2, ? super T3, ? extends R>} to {@code CheckedFunction3<T1, T2, T3, R>} * * @param f A {@code CheckedFunction3} * @param <R> return type * @param <T1> 1st argument * @param <T2> 2nd argument * @param <T3> 3rd argument * @return the given {@code f} instance as narrowed type {@code CheckedFunction3<T1, T2, T3, R>} */ @SuppressWarnings("unchecked") static <T1, T2, T3, R> CheckedFunction3<T1, T2, T3, R> narrow(CheckedFunction3<? super T1, ? super T2, ? super T3, ? extends R> f) { return (CheckedFunction3<T1, T2, T3, R>) f; } /** * Applies this function to three arguments and returns the result. * * @param t1 argument 1 * @param t2 argument 2 * @param t3 argument 3 * @return the result of function application * @throws Throwable if something goes wrong applying this function to the given arguments */ R apply(T1 t1, T2 t2, T3 t3) throws Throwable; /** * Applies this function partially to one argument. * * @param t1 argument 1 * @return a partial application of this function */ default CheckedFunction2<T2, T3, R> apply(T1 t1) { return (T2 t2, T3 t3) -> apply(t1, t2, t3); } /** * Applies this function partially to two arguments. * * @param t1 argument 1 * @param t2 argument 2 * @return a partial application of this function */ default CheckedFunction1<T3, R> apply(T1 t1, T2 t2) { return (T3 t3) -> apply(t1, t2, t3); } @Override default int arity() { return 3; } /** * Returns a function that always returns the constant * value that you give in parameter. * * @param <T1> generic parameter type 1 of the resulting function * @param <T2> generic parameter type 2 of the resulting function * @param <T3> generic parameter type 3 of the resulting function * @param <R> the result type * @param value the value to be returned * @return a function always returning the given value */ static <T1, T2, T3, R> CheckedFunction3<T1, T2, T3, R> constant(R value) { return (t1, t2, t3) -> value; } @Override default Function1<T1, Function1<T2, CheckedFunction1<T3, R>>> curried() { return t1 -> t2 -> t3 -> apply(t1, t2, t3); } @Override default CheckedFunction1<Tuple3<T1, T2, T3>, R> tupled() { return t -> apply(t._1, t._2, t._3); } @Override default CheckedFunction3<T3, T2, T1, R> reversed() { return (t3, t2, t1) -> apply(t1, t2, t3); } @Override default CheckedFunction3<T1, T2, T3, R> memoized() { if (isMemoized()) { return this; } else { final Map<Tuple3<T1, T2, T3>, R> cache = new HashMap<>(); return (CheckedFunction3<T1, T2, T3, R> & Memoized) (t1, t2, t3) -> Memoized.of(cache, Tuple.of(t1, t2, t3), t -> Try.of(() -> apply(t1, t2, t3)).get()); } } /** * Return a composed function that first applies this CheckedFunction3 to the given arguments and in case of throwable * try to get value from {@code recover} function with same arguments and throwable information. * * @param recover the function applied in case of throwable * @return a function composed of this and recover * @throws NullPointerException if recover is null */ default Function3<T1, T2, T3, R> recover(Function<? super Throwable, ? extends Function3<? super T1, ? super T2, ? super T3, ? extends R>> recover) { Objects.requireNonNull(recover, "recover is null"); return (t1, t2, t3) -> { try { return this.apply(t1, t2, t3); } catch (Throwable throwable) { final Function3<? super T1, ? super T2, ? super T3, ? extends R> func = recover.apply(throwable); Objects.requireNonNull(func, () -> "recover return null for " + throwable.getClass() + ": " + throwable.getMessage()); return func.apply(t1, t2, t3); } }; } /** * Returns an unchecked function that will <em>sneaky throw</em> if an exceptions occurs when applying the function. * * @return a new Function3 that throws a {@code Throwable}. */ default Function3<T1, T2, T3, R> unchecked() { return (t1, t2, t3) -> { try { return apply(t1, t2, t3); } catch(Throwable t) { return sneakyThrow(t); } }; } /** * Returns a composed function that first applies this CheckedFunction3 to the given argument and then applies * {@linkplain CheckedFunction1} {@code after} to the result. * * @param <V> return type of after * @param after the function applied after this * @return a function composed of this and after * @throws NullPointerException if after is null */ default <V> CheckedFunction3<T1, T2, T3, V> andThen(CheckedFunction1<? super R, ? extends V> after) { Objects.requireNonNull(after, "after is null"); return (t1, t2, t3) -> after.apply(apply(t1, t2, t3)); } } interface CheckedFunction3Module { // DEV-NOTE: we do not plan to expose this as public API @SuppressWarnings("unchecked") static <T extends Throwable, R> R sneakyThrow(Throwable t) throws T { throw (T) t; } }