All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.suppierk.java.util.Try Maven / Gradle / Ivy

Go to download

Java 11 compatible extensions allowing to use checked exceptions in functional programming APIs + Try interface

There is a newer version: 2.0.0
Show newest version
/*
 * MIT License
 *
 * Copyright (c) 2020 Roman Khlebnov
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package io.github.suppierk.java.util;

import io.github.suppierk.java.util.function.ThrowableConsumer;
import io.github.suppierk.java.util.function.ThrowableFunction;
import io.github.suppierk.java.util.function.ThrowablePredicate;
import io.github.suppierk.java.util.function.ThrowableSupplier;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;

/**
 * A container object which contain either a value or exception.
 *
 * 

If a value is present, {@link #isSuccess()} will return {@code true} and {@link #get()} will * return the value. If exception occurred, {@link #isFailure()} will return {@code true} and {@link * #get()} will return first occurred exception. * *

Additional methods that depend on the presence or absence of a contained value are provided, * such as {@link #orElse(java.lang.Object) orElse()} (return a default value if value not present) * and {@link #ifSuccess(ThrowableConsumer)} (execute a block of code if the value is present) or * {@link #ifFailure(ThrowableConsumer)} (execute a block of code if the exception is present). * *

This is a value-based class; use of * identity-sensitive operations (including reference equality ({@code ==}), identity hash code, or * synchronization) on instances of {@code Try} may have unpredictable results and should be * avoided. * * @param the class of the value */ @SuppressWarnings("squid:S1181") public interface Try { /** * Returns a {@link Try} by invoking specified supplier. * * @param the class of the value * @param supplier the supplier to retrieve the value * @return a {@link Try.Success} with the value retrieved successfully or {@link Try.Failure} */ static Try of(ThrowableSupplier supplier) { try { return success(Objects.requireNonNull(supplier).get()); } catch (Throwable t) { return failure(t); } } /** * Returns a {@link Try} created from specified {@link Optional}. * * @param the class of the value * @param optional the {@link Optional} to be present * @return a {@link Try.Success} with the value if it was present otherwise a {@link Try.Failure} * with {@link NoSuchElementException} * @throws NullPointerException if optional is null */ static Try fromOptional(Optional optional) { try { if (Objects.requireNonNull(optional).isPresent()) { return success(optional.get()); } else { return failure(new NoSuchElementException()); } } catch (Throwable t) { return failure(t); } } /** * Returns a {@link Try} with the specified value. * * @param the class of the value * @param value the value to be present * @return a {@link Try.Success} with the value * @throws NullPointerException if value is null */ static Try success(T value) { return new Success<>(value); } /** * Returns a {@link Try} with the specified exception. * * @param the class of the value * @param throwable the value to be present, which must be non-null * @return a {@link Try.Failure} with the exception * @throws NullPointerException if throwable is null */ static Try failure(Throwable throwable) { return new Failure<>(throwable); } /** * If this is {@link Try.Success}, returns the value, if this is {@link Try.Failure}, throws the * exception stored as unchecked. * * @return the value held by this {@link Try.Success} * @see Try#isSuccess() * @see Try#isFailure() */ T get(); /** * @return {@code true} if there is a value present, otherwise {@code false} */ boolean isSuccess(); /** * @return {@code true} if there is an exception present, otherwise {@code false} */ boolean isFailure(); /** * If a value is present, invoke the specified consumer with the value, otherwise do nothing. * * @param consumer block to be executed if a value is present */ void ifSuccess(ThrowableConsumer consumer); /** * If an exception is present, invoke the specified consumer with the value, otherwise do nothing. * * @param consumer block to be executed if an exception is present */ void ifFailure(ThrowableConsumer consumer); /** * If a value is present, and the value matches the given predicate, return a {@link Try} * describing the value, otherwise return a failed {@link Try}. * * @param predicate a predicate to apply to the value, if present * @return a {@link Try.Success} describing the value of this {@link Try} if a value is present * and the value matches the given predicate, otherwise a {@link Try.Failure} */ Try filter(ThrowablePredicate predicate); /** * If a value is present, apply the provided mapping function to it, and if the result is * non-null, return a {@link Try} describing the result. Otherwise return a failed {@link Try}. * * @param The type of the result of the mapping function * @param mapper a mapping function to apply to the value, if present * @return a {@link Try.Success} describing the result of applying a mapping function to the value * of this {@link Try}, if a value is present, otherwise a {@link Try.Failure} */ Try map(ThrowableFunction mapper); /** * If a value is present, apply the provided {@link Try}-bearing mapping function to it, return * that result, otherwise return a failed {@link Try}. This method is similar to {@link * #map(ThrowableFunction)}, but the provided mapper is one whose result is already a {@link Try}, * and if invoked, {@code flatMap} does not wrap it with an additional {@link Try}. * * @param The type parameter to the {@link Try} returned by * @param mapper a mapping function to apply to the value, if present the mapping function * @return the result of applying a {@link Try}-bearing mapping function to the value of this * {@link Try}, if a value is present, otherwise a {@link Try.Failure} */ Try flatMap(ThrowableFunction> mapper); /** * Convert this {@link Try} to {@link Optional} without preserving exception information. * * @return new {@link Optional} containing value or {@link Optional#empty()} if there was an * exception */ Optional toOptional(); /** * Continue {@link Try} composition by providing alternative ways to compute desired value * * @param supplier to invoke in case of failure. * @return new {@link Try} instance */ Try orElseTry(ThrowableSupplier supplier); /** * Return the value if present, otherwise return {@code other}. * * @param other the value to be returned if there is a failure, may be null * @return the value, if present, otherwise {@code other} */ default T orElse(T other) { try { return get(); } catch (Throwable t) { return other; } } /** * Return the value if present, otherwise invoke {@code other} and return the result of that * invocation. * * @param other a {@link Supplier} whose result is returned if no value is present * @return the value if present otherwise the result of {@code other.get()} * @throws NullPointerException if value is not present and {@code other} is null */ default T orElse(Supplier other) { try { return get(); } catch (Throwable t) { return Objects.requireNonNull(other, "Try.orElseGet(Supplier) argument must not be null") .get(); } } /** * A container object which contains value. * * @param the class of the value */ class Success implements Try { /** Non-null value. */ private final T value; /** * Constructs an instance with the value present. * * @param value the non-null value to be present * @throws NullPointerException if value is null */ protected Success(T value) { this.value = Objects.requireNonNull(value, "Try.success(Object) argument must not be null"); } /** {@inheritDoc} */ @Override public T get() { return value; } /** {@inheritDoc} */ @Override public boolean isSuccess() { return true; } /** {@inheritDoc} */ @Override public boolean isFailure() { return false; } /** {@inheritDoc} */ @Override public void ifSuccess(ThrowableConsumer consumer) { Objects.requireNonNull(consumer).accept(value); } /** {@inheritDoc} */ @Override public void ifFailure(ThrowableConsumer consumer) { // Do nothing } /** {@inheritDoc} */ @Override public Try filter(ThrowablePredicate predicate) { try { if (Objects.requireNonNull(predicate).test(get())) { return this; } else { return failure(new NoSuchElementException()); } } catch (Throwable t) { return failure(t); } } /** {@inheritDoc} */ @Override public Try map(ThrowableFunction mapper) { return Try.of(() -> Objects.requireNonNull(mapper).apply(get())); } /** {@inheritDoc} */ @Override public Try flatMap(ThrowableFunction> mapper) { try { return Objects.requireNonNull(mapper).apply(get()); } catch (Throwable t) { return failure(t); } } /** {@inheritDoc} */ @Override public Optional toOptional() { return Optional.ofNullable(get()); } /** {@inheritDoc} */ @Override public Try orElseTry(ThrowableSupplier supplier) { Objects.requireNonNull(supplier, "Try.orElse argument must not be null"); return this; } } /** * A container object which contains exception. * * @param the class of the value */ class Failure implements Try { /** Non-null exception. */ private final Throwable exception; /** * Constructs an instance with the exception present. * * @param exception the non-null exception to be present * @throws NullPointerException if exception is null */ protected Failure(Throwable exception) { this.exception = Objects.requireNonNull(exception, "Try.failure(Throwable) argument must not be null"); } /** {@inheritDoc} */ @Override public T get() { return ExceptionSuppressor.asUnchecked(exception); } /** {@inheritDoc} */ @Override public boolean isSuccess() { return false; } /** {@inheritDoc} */ @Override public boolean isFailure() { return true; } /** {@inheritDoc} */ @Override public void ifSuccess(ThrowableConsumer consumer) { // Do nothing } /** {@inheritDoc} */ @Override public void ifFailure(ThrowableConsumer consumer) { Objects.requireNonNull(consumer).accept(exception); } /** {@inheritDoc} */ @Override public Try filter(ThrowablePredicate predicate) { return this; } /** {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public Try map(ThrowableFunction mapper) { return (Try) this; } /** {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public Try flatMap(ThrowableFunction> mapper) { return (Try) this; } /** {@inheritDoc} */ @Override public Optional toOptional() { return Optional.empty(); } /** {@inheritDoc} */ @Override public Try orElseTry(ThrowableSupplier supplier) { return Try.of(Objects.requireNonNull(supplier, "Try.orElse argument must not be null")); } } }