Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.nextbreakpoint.Try Maven / Gradle / Ivy
Go to download
Try implements a functional API for handling checked and unchecked exceptions
/*
* This file is part of Try
*
* Copyright (c) 2016, Andrea Medeghini
* All rights reserved.
*/
package com.nextbreakpoint;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* Try implements a monad for handling checked and unchecked exceptions.
*
* @author Andrea Medeghini
*
* @param the type of returned value
* @param the type of captured exception
*/
public abstract class Try {
/**
* The function to transform an exception into expected exception.
*/
protected final Function mapper;
/**
* The filter to apply when getting or mapping value.
*/
protected final Predicate filter;
/**
* The handler to call when result is success.
*/
protected final Consumer> onSuccess;
/**
* The handler to call when result is failure.
*/
protected final Consumer onFailure;
/**
* Returns true if exception occurred.
* @return true when exception if present
*/
public abstract boolean isFailure();
/**
* Returns true if no exception occurred.
* @return true when exception if not present
*/
public abstract boolean isSuccess();
/**
* Returns true if value is present.
* @return true when value is present
*/
public abstract boolean isPresent();
/**
* Invokes consumer if exception occurred.
* @param consumer the consumer
*/
public abstract void ifFailure(Consumer consumer);
/**
* Invokes consumer if no exception occurred.
* @param consumer the consumer
*/
public abstract void ifSuccess(Consumer> consumer);
/**
* Invokes consumer if value is present.
* @param consumer the consumer
*/
public abstract void ifPresent(Consumer consumer);
/**
* Invokes consumer if value is present or throws exception if failure.
* @param consumer the consumer
* @throws E the exception
*/
public abstract void ifPresentOrThrow(Consumer consumer) throws E;
/**
* Returns the value.
* @return the value
* @throws NoSuchElementException if value not present.
*/
public abstract V get();
/**
* Returns the value if present or returns the default value.
* @param value the default value
* @return the value
*/
public abstract V orElse(V value);
/**
* Returns the value if present or invokes the supplier to get the value.
* @param supplier the supplier
* @return the value
*/
public abstract V orElseGet(Supplier supplier);
/**
* Returns the value if present or throws exception if failure.
* @return the value
* @throws E the exception
* @throws NoSuchElementException if value not present.
*/
public abstract V orThrow() throws E;
/**
* Returns the value if present or throws exception if failure or returns the default value.
* @param value the default value
* @return the value
* @throws E the exception
*/
public abstract V orThrow(V value) throws E;
/**
* Returns optional of value.
* @return new optional
*/
public abstract Optional value();
/**
* Throws exception if failure.
* @throws E the exception
*/
public abstract void throwIfFailure() throws E;
/**
* Creates new instance mapper given mapping function.
* @param func the function
* @param the result's value type
* @return new instance
* @throws NullPointerException if func is null.
*/
public abstract Try map(Function func);
/**
* Creates new instance mapper given mapping function.
* @param func the function
* @param the result's value type
* @return new instance
* @throws NullPointerException if func is null.
*/
public abstract Try flatMap(Function> func);
/**
* Creates new instance which executes alternative callable if failure.
* @param callable the callable
* @return new instance
* @throws NullPointerException if callable is null.
*/
public abstract Try or(Callable callable);
/**
* Creates new instance which executes consecutive callable if success.
* @param callable the callable
* @return new instance
* @throws NullPointerException if callable is null.
*/
public abstract Try and(Callable callable);
/**
* Creates new instance with given consumer of success event.
* @param consumer the consumer
* @return new instance
*/
public abstract Try onSuccess(Consumer> consumer);
/**
* Creates new instance with given consumer of failure event.
* @param consumer the consumer
* @return new instance
*/
public abstract Try onFailure(Consumer consumer);
/**
* Creates new instance with given exception mapper.
* @param mapper the mapper
* @param the exception type
* @return new instance
* @throws NullPointerException if mapper is null.
*/
public abstract Try mapper(Function mapper);
/**
* Creates new instance with given value filter.
* @param filter the filter
* @return new instance
* @throws NullPointerException if filter is null.
*/
public abstract Try filter(Predicate filter);
/**
* Creates not lazy instance. Executes code if needed.
* @return new instance
*/
public abstract Try execute();
/**
* Creates new instance with given callable.
* @param callable the callable
* @param the result's value type
* @return new instance
*/
public static Try of(Callable callable) {
return new TryCallable<>(defaultMapper(), defaultFilter(), callable);
}
/**
* Creates new instance with given exception.
* @param exception the exception
* @param the result's value type
* @return new instance
*/
public static Try failure(Exception exception) {
return new TryFailure<>(defaultMapper(), defaultFilter(), exception);
}
/**
* Creates new instance with given value.
* @param value the value
* @param the result's value type
* @return new instance
*/
public static Try success(R value) {
return new TrySuccess<>(defaultMapper(), defaultFilter(), value);
}
private Try(Function mapper, Predicate filter, Consumer> onSuccess, Consumer onFailure) {
this.mapper = Objects.requireNonNull(mapper);
this.filter = Objects.requireNonNull(filter);
this.onSuccess = onSuccess;
this.onFailure = onFailure;
}
private static Function defaultMapper() {
return x -> x;
}
private static Predicate defaultFilter() {
return v -> v != null;
}
private static class TryFailure extends Try {
private final E exception;
public TryFailure(Function mapper, Predicate filter, Consumer> onSuccess, Consumer onFailure, E exception) {
super(mapper, filter, onSuccess, onFailure);
this.exception = Objects.requireNonNull(exception);
}
public TryFailure(Function mapper, Predicate filter, E exception) {
this(mapper, filter, null, null, exception);
}
public boolean isFailure() {
notifyEvent();
return true;
}
public boolean isSuccess() {
notifyEvent();
return false;
}
public boolean isPresent() {
notifyEvent();
return false;
}
public void ifFailure(Consumer consumer) {
notifyEvent();
consumer.accept(exception);
}
public void ifSuccess(Consumer> consumer) {
notifyEvent();
}
public void ifPresent(Consumer consumer) {
notifyEvent();
}
public void ifPresentOrThrow(Consumer consumer) throws E {
notifyEvent();
throw exception;
}
public V get() {
notifyEvent();
throw new NoSuchElementException("Failure doesn't have any value");
}
public V orElse(V value) {
notifyEvent();
return value;
}
public V orElseGet(Supplier supplier) {
notifyEvent();
return supplier.get();
}
public V orThrow() throws E {
notifyEvent();
throw exception;
}
public V orThrow(V value) throws E {
notifyEvent();
throw exception;
}
public Optional value() {
notifyEvent();
return Optional.empty();
}
public void throwIfFailure() throws E {
notifyEvent();
throw exception;
}
public Try map(Function func) {
Objects.requireNonNull(func);
return new TryFailure<>(mapper, defaultFilter(), onSuccess, onFailure, exception);
}
public Try flatMap(Function> func) {
Objects.requireNonNull(func);
return new TryFailure<>(mapper, defaultFilter(), onSuccess, onFailure, exception);
}
public Try or(Callable callable) {
Objects.requireNonNull(callable);
return create(() -> orTry(onFailure, callable, mapper));
}
public Try and(Callable callable) {
Objects.requireNonNull(callable);
return new TryFailure<>(mapper, defaultFilter(), onSuccess, onFailure, exception);
}
public Try onSuccess(Consumer> consumer) {
return new TryFailure<>(mapper, filter, consumer, onFailure, exception);
}
public Try onFailure(Consumer consumer) {
return new TryFailure<>(mapper, filter, onSuccess, consumer, exception);
}
public Try mapper(Function mapper) {
return new TryFailure<>(mapper, filter, onSuccess, onFailure, mapper.apply(exception));
}
public Try filter(Predicate filter) {
return new TryFailure<>(mapper, filter, onSuccess, onFailure, exception);
}
public Try execute() {
return this;
}
private void notifyEvent() {
Optional.ofNullable(onFailure).ifPresent(consumer -> consumer.accept(exception));
}
private Try create(Callable callable) {
return new TryCallable<>(mapper, defaultFilter(), onSuccess, onFailure, callable);
}
private V call(Callable callable) throws Exception {
return callable.call();
}
private V orTry(Consumer onFailure, Callable callable, Function mapper) throws Exception {
Optional.ofNullable(onFailure).ifPresent(consumer -> consumer.accept(mapper.apply(exception)));
return call(callable);
}
}
private static class TrySuccess extends Try {
private final V value;
public TrySuccess(Function mapper, Predicate filter, Consumer> onSuccess, Consumer onFailure, V value) {
super(mapper, filter, onSuccess, onFailure);
this.value = value;
}
public TrySuccess(Function mapper, Predicate filter, V value) {
this(mapper, filter, null, null, value);
}
public boolean isFailure() {
notifyEvent();
return false;
}
public boolean isSuccess() {
notifyEvent();
return true;
}
public boolean isPresent() {
return value().isPresent();
}
public void ifFailure(Consumer consumer) {
notifyEvent();
}
public void ifSuccess(Consumer> consumer) {
consumer.accept(value());
}
public void ifPresent(Consumer consumer) {
value().ifPresent(consumer);
}
public void ifPresentOrThrow(Consumer consumer) {
value().ifPresent(consumer);
}
public V get() {
return value().get();
}
public V orElse(V value) {
return value().orElse(value);
}
public V orElseGet(Supplier supplier) {
return value().orElseGet(supplier);
}
public V orThrow() throws E {
return value().get();
}
public V orThrow(V value) throws E {
return value().orElse(value);
}
public Optional value() {
notifyEvent();
return evaluate();
}
public void throwIfFailure() throws E {
notifyEvent();
}
public Try map(Function func) {
Objects.requireNonNull(func);
return create(() -> evaluate().map(func).orElse(null));
}
public Try flatMap(Function> func) {
Objects.requireNonNull(func);
return create(() -> evaluate().map(func).orElseGet(() -> empty()).orThrow(null));
}
public Try or(Callable callable) {
Objects.requireNonNull(callable);
return new TrySuccess<>(mapper, defaultFilter(), onSuccess, onFailure, value);
}
public Try and(Callable callable) {
Objects.requireNonNull(callable);
return create(() -> andTry(onSuccess, callable));
}
public Try onSuccess(Consumer> consumer) {
return new TrySuccess<>(mapper, filter, consumer, onFailure, value);
}
public Try onFailure(Consumer consumer) {
return new TrySuccess<>(mapper, filter, onSuccess, consumer, value);
}
public Try mapper(Function mapper) {
return new TrySuccess<>(mapper, filter, onSuccess, onFailure, value);
}
public Try filter(Predicate filter) {
return new TrySuccess<>(mapper, filter, onSuccess, onFailure, value);
}
public Try execute() {
return this;
}
private Optional evaluate() {
return Optional.ofNullable(value).filter(filter);
}
private Try empty() {
return new TrySuccess<>(mapper, defaultFilter(), onSuccess, onFailure, null);
}
private Try create(Callable callable) {
return new TryCallable<>(mapper, defaultFilter(), onSuccess, onFailure, callable);
}
private void notifyEvent() {
Optional.ofNullable(onSuccess).ifPresent(consumer -> consumer.accept(Optional.ofNullable(value)));
}
private V call(Callable callable) throws Exception {
return callable.call();
}
private V andTry(Consumer> onSuccess, Callable callable) throws Exception {
Optional value = evaluate();
Optional.ofNullable(onSuccess).ifPresent(consumer -> consumer.accept(Optional.ofNullable(value.orElse(null))));
return call(callable);
}
}
private static class TryCallable extends Try {
private final Callable callable;
public TryCallable(Function mapper, Predicate filter, Consumer> onSuccess, Consumer onFailure, Callable callable) {
super(mapper, filter, onSuccess, onFailure);
this.callable = Objects.requireNonNull(callable);
}
public TryCallable(Function mapper, Predicate filter, Callable callable) {
this(mapper, filter, null, null, callable);
}
public boolean isFailure() {
return execute().isFailure();
}
public boolean isSuccess() {
return execute().isSuccess();
}
public boolean isPresent() {
return execute().isPresent();
}
public void ifFailure(Consumer consumer) {
execute().ifFailure(consumer);
}
public void ifSuccess(Consumer> consumer) {
execute().ifSuccess(consumer);
}
public void ifPresent(Consumer consumer) {
execute().ifPresent(consumer);
}
public void ifPresentOrThrow(Consumer consumer) throws E {
execute().ifPresentOrThrow(consumer);
}
public V get() {
return execute().get();
}
public V orElse(V value) {
return execute().orElse(value);
}
public V orElseGet(Supplier supplier) {
return execute().orElseGet(supplier);
}
public V orThrow() throws E {
return execute().orThrow();
}
public V orThrow(V value) throws E {
return execute().orThrow(value);
}
public Optional value() {
return execute().value();
}
public void throwIfFailure() throws E {
execute().throwIfFailure();
}
public Try map(Function func) {
Objects.requireNonNull(func);
return create(() -> evaluate().map(func).orElse(null));
}
public Try flatMap(Function> func) {
Objects.requireNonNull(func);
return create(() -> evaluate().map(func).orElseGet(() -> empty()).orThrow(null));
}
public Try or(Callable callable) {
Objects.requireNonNull(callable);
return create(() -> orTry(onFailure, callable, mapper));
}
public Try and(Callable callable) {
Objects.requireNonNull(callable);
return create(() -> andTry(onSuccess, callable));
}
public Try onSuccess(Consumer> consumer) {
return new TryCallable<>(mapper, filter, consumer, onFailure, callable);
}
public Try onFailure(Consumer consumer) {
return new TryCallable<>(mapper, filter, onSuccess, consumer, callable);
}
public Try mapper(Function mapper) {
return new TryCallable<>(mapper, filter, onSuccess, onFailure, callable);
}
public Try filter(Predicate filter) {
return new TryCallable<>(mapper, filter, onSuccess, onFailure, callable);
}
public Try execute() {
try {
V value = evaluate().orElse(null);
Optional.ofNullable(onSuccess).ifPresent(consumer -> consumer.accept(Optional.ofNullable(value)));
return createTerminal(value);
} catch (Exception e) {
E t = mapper.apply(e);
Optional.ofNullable(onFailure).ifPresent(consumer -> consumer.accept(t));
return createTerminal(t);
}
}
private Optional evaluate() throws Exception {
return evaluate(callable);
}
private Optional evaluate(Callable callable) throws Exception {
return Optional.ofNullable(call(callable)).filter(filter);
}
private Try empty() {
return new TrySuccess<>(mapper, defaultFilter(), onSuccess, onFailure, null);
}
private Try create(Callable callable) {
return new TryCallable<>(mapper, defaultFilter(), onSuccess, onFailure, callable);
}
private Try createTerminal(E exception) {
return new TryFailure<>(mapper, defaultFilter(), null, null, exception);
}
private Try createTerminal(R value) {
return new TrySuccess<>(mapper, defaultFilter(), null, null, value);
}
private V call() throws Exception {
return call(callable);
}
private V call(Callable callable) throws Exception {
return callable.call();
}
private V orTry(Consumer onFailure, Callable callable, Function mapper) throws Exception {
try {
return call();
} catch (Exception e) {
Optional.ofNullable(onFailure).ifPresent(consumer -> consumer.accept(mapper.apply(e)));
return call(callable);
}
}
private V andTry(Consumer> onSuccess, Callable callable) throws Exception {
Optional value = evaluate();
Optional.ofNullable(onSuccess).ifPresent(consumer -> consumer.accept(Optional.ofNullable(value.orElse(null))));
return call(callable);
}
}
}