# functional-programming-in-java-bookshelf
# Error Handling
Either Monad
public sealed interface Try<T> permits Failure, Success {
T getResult();
Throwable getError();
static <T> Try<T> of(Callable<T> code){
try{
return new Success<>(code.call());
} catch (Throwable throwable) {
return new Failure<>(throwable);
}
}
default <R> Try<R> map(Function<T,R> mapper){
if(this instanceof Success<T>){
return of(()->mapper.apply(getResult()) );
}else{
return new Failure<>(getError());
}
}
}
public record Success<T>(T result) implements Try<T> {
@Override
public T getResult() {
return result;
}
@Override
public Throwable getError() {
throw new RuntimeException("Invalid invocation");
}
}
public record Failure<T>(Throwable throwable) implements Try<T> {
@Override
public T getResult() {
throw new RuntimeException("Invalid invocation");
}
@Override
public Throwable getError() {
return throwable;
}
}
# Functional Programming Idioms
- Don't write dense lambda expressions (avoid multiline lambda expressions)
- Prefer method references
- Keep separate conditions in separate filters
- Use Type Inference for Parameters
- Avoid side effects in functional pipelines