![JAR search and dependency download from the Maven repository](/logo.png)
no.finn.lambdacompanion.Try Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of lambda-companion Show documentation
Show all versions of lambda-companion Show documentation
Functional structures and utilities for Java 8 and lambdas
package no.finn.lambdacompanion;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* Try is a right-biased datatype for wrapping function calls that might fail with an Exception.
*
* A Try is alwyas Success or Failure. Success holds a value, and Failure holds an Exception.
*
* Being right biased, you can map and flatMap on it successivly, delaying handling of failure to
* the very end of your chain.
*
* the recover-method usually comes at the end of a call-chain and forces the handling of both
* success and failure.
*
* @param t
*/
public abstract class Try {
/**
* Applies a function on a value of type Success. Returns self if Failure.
* @param mapper Function from T to U with an Exception in the signature
* @param Type of the return value of the function
* @return a new Try
*/
public abstract Try map(ThrowingFunction super T, ? extends U, ? extends Exception> mapper);
/**
* Applies a function on two values. Returns Success of the resulting value, or Returns self if Failure.
* Same as map() but needs a function ending in a Try
* @param mapper Function from T to Try<U> with an Exception in the signature
* @param Type of the value to be wrapped in a Try of the function
* @return a new Try
*/
public abstract Try flatMap(ThrowingFunction super T, ? extends Try, ? extends Exception> mapper);
/**
* Applies a filter, where a match returns Success and Failure otherwise.
* @param predicate Predicate function to determine Success or Failure
* @return the same or new try
*/
public abstract Optional> filter(Predicate predicate);
/**
* Accepts a consuming function and applies it to the value if it is a Success. Does nothing if Failure.
* @param consumer Consuming function with an Exception in the signature
*/
public abstract void forEach(ThrowingConsumer super T, ? extends Exception> consumer);
/**
* Same as forEach but returns the Try for further chaining
* @param consumer Consuming function with an Exception in the signature
* @return the same Try
*/
public abstract Try peek(ThrowingConsumer super T, ? extends Exception> consumer);
/**
* Does nothing on Success, but accepts a consumer on Failure
* @param consumer Consuming function with a failure
* @return the same Try
*/
public abstract Try peekFailure(Consumer> consumer);
/**
* Returns the value of the Success, or a default value of the same type if this is a Failure.
* Note that the argument is always evaluated, and this is not lazy (as opposed to orElseGet)
* @param defaultValue default fallback value
* @return value
*/
public abstract T orElse(T defaultValue);
/**
* Returns the value of the Success, or lazily falls back to a supplied value of the same type
* @param defaultValue lazy default supplier of fallback value
* @return value
*/
public abstract T orElseGet(Supplier extends T> defaultValue);
/**
* Accepts two functions, the first applied if Success - returning the value,
* the other executed if Failure, returning a fallback value. Note that
* - the first function cannot have an Exception in its signature.
* - the fallback function must end in a value
* @param successFunc Function handling the Success case
* @param failureFunc Function handling the Failure case
* @param Type of the value
* @return a value of type U
*/
public abstract U recover(Function super T, ? extends U> successFunc,
Function failureFunc);
/**
* Creates an Optional wrapping the value if Success. Creates an empty Optional if Failure.
* @return An Optional
*/
public abstract Optional toOptional();
/**
* Creates an Either where the Left is the Failure and Right is the Success from this Try
* @param Exception
* @return an Either
*/
public abstract Either toEither();
/**
* Escapes the Try and enters a regular try-catch flow
* @param ExceptionMapper Function to transform the Exception if this is a Failure
* @param any Exception
* @param any Exception
* @return Value or a transformed Exception
* @throws Y any Exception
*/
public abstract T orElseThrow(Function ExceptionMapper) throws Y;
/**
* Escapes the Try and enters a regular try-catch flow by rethowing the caught exception when a Failure
* @param any Exception
* @return Value or a transformed Exception
* @throws E any Exception
*/
public abstract T orElseRethrow() throws E;
/**
* Starting point to the Try structure. Create a try from a function that throws an Exception
* and an argument to this function
* @param func Function to be attempted, e.g. URL::new
* @param v Argument for the function
* @param Type of the function return value
* @param Type of the function argument
* @return a Try
*/
public static Try of(ThrowingFunction func, V v) {
try {
return new Success<>(func.apply(v));
} catch (Exception e) {
return new Failure<>(e);
}
}
/**
* Starting point to the Try structure. Create a try from a function that throws an Exception
* and two arguments to this function
* @param func Function to be attempted, e.g. (a,b) -> a / b
* @param v First argument for the function
* @param w Second argument for the function
* @param Type of the function return value
* @param Type of the first function argument
* @param Type of the second function argument
* @return a Try
*/
public static Try of(ThrowingBiFunction func, V v, W w) {
try {
return new Success<>(func.apply(v, w));
} catch (Exception e) {
return new Failure<>(e);
}
}
/**
* Starting point to the Try structure. Create a try from a Supplier that throws an Exception
* @param supplier The supplier function
* @param Type of the supplied object from the supplier function
* @return a Try
*/
public static Try of(ThrowingSupplier supplier) {
try {
return new Success<>(supplier.get());
} catch (Exception e) {
return new Failure<>(e);
}
}
/**
* Starting point to the Try structure. Create a try from a void Supplier that throws an Exception
* @param supplier The supplier function
* @return a Try
*/
public static Try of(ThrowingVoidSupplier extends Exception> supplier) {
try {
supplier.get();
return new Success<>(null);
} catch (Exception e) {
return new Failure<>(e);
}
}
public static Try failure(Exception Exception) {
return new Failure<>(Exception);
}
public static Try success(T value) {
return new Success<>(value);
}
/**
* Creates one Try from a list of tries containing the same type, or the _first_ failure in the given list
* @param tries List of tries
* @param the type
* @return One Try containing a list of Ts
*/
public static Try> sequence(List> tries) {
if (tries.size() == 0) {
return Try.failure(new IllegalArgumentException("Cannot sequence an empty list"));
}
Try> head = Functions.head(tries).map(Collections::singletonList);
if (tries.size() == 1 || !head.toOptional().isPresent()) {
return head;
}
return concat(head, head.flatMap(t -> sequence(Functions.tail(tries))));
}
private static Try> concat(Try> head, Try> tail) {
return head.flatMap(l -> tail.map(k -> concat(l, k)));
}
private static List concat(List l, List k) {
ArrayList retVal = new ArrayList<>(l);
retVal.addAll(k);
return retVal;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy