com.aol.cyclops.trycatch.TryT Maven / Gradle / Ivy
package com.aol.cyclops.trycatch;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jooq.lambda.function.Function1;
import com.aol.cyclops.lambda.monads.transformers.OptionalT;
import com.aol.cyclops.monad.AnyM;
/**
* Monad transformer for JDK Try
*
* TryT consists of an AnyM instance that in turns wraps another Monad type that contains an Try
*
* TryT>>>
*
* TryT allows the deeply wrapped Try to be manipulating within it's nested /contained context
*
*
* @author johnmcclean
*
* @param The type contained on the Try within
*/
public class TryT {
private final AnyM> run;
private TryT(final AnyM> run){
this.run = run;
}
/**
* @return The wrapped AnyM
*/
public AnyM> unwrap() {
return run;
}
/**
* Peek at the current value of the Try
*
* {@code
* TryT.of(AnyM.fromStream(Success.of(10))
* .peek(System.out::println);
*
* //prints 10
* }
*
*
* @param peek Consumer to accept current value of Try
* @return TryT with peek call
*/
public TryT peek(Consumer peek) {
return of(run.peek(opt -> opt.map(a -> {
peek.accept(a);
return a;
})));
}
/**
* Filter the wrapped Try
*
* {@code
* TryT.of(AnyM.fromStream(Success.of(10))
* .filter(t->t!=10);
*
* //TryT>>
* }
*
* @param test Predicate to filter the wrapped Try
* @return OptionalT that applies the provided filter
*/
public OptionalT filter(Predicate test) {
return OptionalT.of(run.map(opt -> opt.filter(test)));
}
/**
* Map the wrapped Try
*
*
* {@code
* TryT.of(AnyM.fromStream(Success.of(10))
* .map(t->t=t+1);
*
*
* //TryT>>
* }
*
*
* @param f Mapping function for the wrapped Try
* @return TryT that applies the map function to the wrapped Try
*/
public TryT map(Function f) {
return new TryT(run.map(o -> o.map(f)));
}
/**
* Flat Map the wrapped Try
*
* {@code
* TryT.of(AnyM.fromStream(Success.of(10))
* .flatMap(t->Failure.of(new Exception());
*
*
* //TryT>>
* }
*
* @param f FlatMap function
* @return TryT that applies the flatMap function to the wrapped Try
*/
public TryT flatMap(Function1> f) {
return of(run.flatMap(opt -> {
if (opt.isSuccess())
return f.apply(opt.get()).run;
Try ret = (Try)opt;
return run.unit(ret);
}));
}
/**
* Lift a function into one that accepts and returns an TryT
* This allows multiple monad types to add functionality to existing functions and methods
*
* e.g. to add Exception Handling (via Try) and iteration (via Stream) to an existing function
*
* {@code
* Function add2 = i -> i+2;
Function, TryT> optTAdd2 = TryT.lift(add2);
Stream withNulls = Stream.of(1,2,null);
AnyM stream = AnyM.ofMonad(withNulls);
AnyM> streamOpt = stream.map(this::toTry);
List results = optTAdd2.apply(TryT.of(streamOpt))
.unwrap()
.>>unwrap()
.filter(Try::isSuccess)
.map(Try::get)
.collect(Collectors.toList());
//Arrays.asList(3,4);
*
*
* }
*
*
* @param fn Function to enhance with functionality from Try and another monad type
* @return Function that accepts and returns an TryT
*/
public static Function, TryT> lift(Function fn) {
return optTu -> optTu.map(input -> fn.apply(input));
}
/**
* Lift a BiFunction into one that accepts and returns TryTs
* This allows multiple monad types to add functionality to existing functions and methods
*
* e.g. to add Exception handling (via Try), iteration (via Stream) and asynchronous execution (CompletableFuture)
* to an existing function
*
*
* {@code
BiFunction add = (a,b) -> a+b;
BiFunction,TryT, TryT> optTAdd2 = TryT.lift2(add);
Stream withNulls = Stream.of(1,2,null);
AnyM stream = AnyM.ofMonad(withNulls);
AnyM> streamOpt = stream.map(this::toTry);
CompletableFuture> two = CompletableFuture.completedFuture(Try.of(2));
AnyM> future= AnyM.ofMonad(two);
List results = optTAdd2.apply(TryT.of(streamOpt),TryT.of(future))
.unwrap()
.>>unwrap()
.filter(Try::isSuccess)
.map(Try::get)
.collect(Collectors.toList());
//Arrays.asList(3,4);
}
* @param fn BiFunction to enhance with functionality from Try and another monad type
* @return Function that accepts and returns an TryT
*/
public static BiFunction, TryT, TryT> lift2(BiFunction fn) {
return (optTu1, optTu2) -> optTu1.flatMap(input1 -> optTu2.map(input2 -> fn.apply(input1, input2)));
}
/**
* Construct an TryT from an AnyM that contains a monad type that contains type other than Try
* The values in the underlying monad will be mapped to Try
*
* @param anyM AnyM that doesn't contain a monad wrapping an Try
* @return TryT
*/
@SuppressWarnings("unchecked")
public static TryT fromAnyM(AnyM anyM) {
return (TryT) of(anyM.map(Success::of));
}
/**
* Construct an TryT from an AnyM that wraps a monad containing Trys
*
* @param monads AnyM that contains a monad wrapping an Try
* @return TryT
*/
public static TryT of(AnyM> monads) {
return new TryT<>(monads);
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString() {
return run.toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy