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

net.yetamine.lang.functional.Choice Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2016 Yetamine
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.yetamine.lang.functional;

import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

import net.yetamine.lang.exceptions.ThrowingOperation;

/**
 * An alternative to {@link Optional} for the cases when the value may be right
 * or wrong, but the value itself might be used anyway, e.g., for logging. The
 * the value is marked as either right or wrong and this mark is
 * carried with the value, so that the consumer of the value can decide if and
 * how the value could be used.
 *
 * @param 
 *            the type of the contained value
 *
 * @deprecated Planned for removal. Alternative and more powerful options, e.g.,
 *             {@code net.yetamine.sova.Adaptation} are available.
 */
@Deprecated
public final class Choice implements Supplier {

    /** Shared instance for right {@code null}. */
    private static final Choice RIGHT_NULL = new Choice<>(null, true);
    /** Shared instance for wrong {@code null}. */
    private static final Choice WRONG_NULL = new Choice<>(null, false);

    /** Stored value. */
    private final T value;
    /** Flag marking right or wrong. */
    private final boolean right;

    /**
     * Creates a new instance.
     *
     * @param o
     *            the value to store
     * @param t
     *            the flag marking right or wrong
     */
    private Choice(T o, boolean t) {
        value = o;
        right = t;
    }

    /**
     * Narrows a widened type performing a safe type cast (thanks to the safe
     * covariant changes for immutable types).
     *
     * @param 
     *            the type of the represented value
     * @param instance
     *            the instance to narrow
     *
     * @return the narrowed instance
     */
    @SuppressWarnings("unchecked")
    public static  Choice narrow(Choice instance) {
        return (Choice) instance;
    }

    /**
     * Returns a representation of the given value.
     *
     * @param 
     *            the type of the value
     * @param value
     *            the value to store
     * @param right
     *            {@code true} when the value shall be considered right
     *            and {@code false} otherwise
     *
     * @return a representation of the given value
     */
    public static  Choice of(T value, boolean right) {
        return right ? right(value) : wrong(value);
    }

    /**
     * Returns the shared instance representing a {@code null} as right.
     *
     * @param 
     *            the type of the value
     *
     * @return the shared instance representing a {@code null} as right
     */
    @SuppressWarnings("unchecked")
    public static  Choice rightNull() {
        return (Choice) RIGHT_NULL;
    }

    /**
     * Returns the shared instance representing a {@code null} as wrong.
     *
     * @param 
     *            the type of the value
     *
     * @return the shared instance representing a {@code null} as wrong
     */
    @SuppressWarnings("unchecked")
    public static  Choice wrongNull() {
        return (Choice) WRONG_NULL;
    }

    /**
     * Returns an instance representing the value as right.
     *
     * @param 
     *            the type of the value
     * @param o
     *            the value to represent
     *
     * @return an instance representing the value as right
     */
    public static  Choice right(T o) {
        return (o != null) ? new Choice<>(o, true) : rightNull();
    }

    /**
     * Returns an instance representing the value as wrong.
     *
     * @param 
     *            the type of the value
     * @param o
     *            the value to represent
     *
     * @return an instance representing the value as wrong
     */
    public static  Choice wrong(T o) {
        return (o != null) ? new Choice<>(o, false) : wrongNull();
    }

    /**
     * Returns a new instance representing the given value in the way that the
     * {@code null} value is considered wrong, while a non-{@code null}
     * value is considered right.
     *
     * @param 
     *            the type of the value
     * @param o
     *            the value to represent
     *
     * @return the new instance
     */
    public static  Choice nonNull(T o) {
        return (o != null) ? new Choice<>(o, true) : wrongNull();
    }

    /**
     * Returns a new instance using the given {@link Optional} in the way that a
     * present value is considered right, while an absent value maps to
     * wrong {@code null}.
     *
     * @param 
     *            the type of the value
     * @param optional
     *            the container of the value to represent. It must not be
     *            {@code null}.
     *
     * @return the new instance
     */
    public static  Choice from(Optional optional) {
        return Choice.narrow(optional.map(Choice::right).orElseGet(Choice::wrongNull));
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format("%s[%s]", right ? "Choice.right" : "Choice.wrong", value);
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (obj instanceof Choice) {
            final Choice o = (Choice) obj;
            return Objects.equals(value, o.value) && (right == o.right);
        }

        return false;
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        return Objects.hash(value, right);
    }

    /**
     * Returns the value of this choice.
     *
     * @return the value of this choice
     *
     * @see java.util.function.Supplier#get()
     */
    public T get() {
        return value;
    }

    /**
     * Returns the value of this choice if {@link #isRight()}.
     *
     * @return the value of this choice
     *
     * @throws NoSuchElementException
     *             if this choice {@link #isWrong()}
     */
    public T require() {
        if (isRight()) {
            return value;
        }

        throw new NoSuchElementException();
    }

    /**
     * Returns the value of this choice if {@link #isRight()}.
     *
     * @param 
     *            the type of the exception to throw
     * @param e
     *            the supplier of the exception to throw if {@link #isWrong()}.
     *            It must not be {@code null}.
     *
     * @return the value of this choice
     *
     * @throws X
     *             if this choice {@link #isWrong()}
     */
    public  T require(Supplier e) throws X {
        if (isRight()) {
            return value;
        }

        throw e.get();
    }

    /**
     * Creates a stream of this instance as the only element of the stream.
     *
     * @return a stream of this instance
     */
    public Stream> stream() {
        return Stream.of(this);
    }

    /**
     * Returns an {@link Optional} representing a non-{@code null} right
     * value.
     *
     * @return an {@link Optional} with the non-{@code null} right value,
     *         otherwise {@link Optional#empty()}
     */
    public Optional optional() {
        return isRight() ? Optional.ofNullable(value) : Optional.empty();
    }

    /**
     * Returns a right case of the represented value.
     *
     * @return a right case of the represented value
     */
    public Choice right() {
        return isRight() ? this : right(value);
    }

    /**
     * Returns a wrong case of the represented value.
     *
     * @return a wrong case of the represented value
     */
    public Choice wrong() {
        return isWrong() ? this : wrong(value);
    }

    /**
     * Returns an instance representing the same value, but right turned
     * into wrong and vice versa.
     *
     * @return an swapped instance
     */
    public Choice swap() {
        return isRight() ? wrong(value) : right(value);
    }

    /**
     * Tests if the value represented by this choice is considered right.
     *
     * @return {@code true} if the represented value is considered right
     */
    public boolean isRight() {
        return right;
    }

    /**
     * Tests if the value represented by this choice is considered wrong.
     *
     * @return {@code false} if the represented value is considered wrong
     */
    public boolean isWrong() {
        return !isRight();
    }

    /**
     * Passes the represented value to the given consumer if {@link #isRight()}
     * returns {@code true}.
     *
     * @param consumer
     *            the consumer to accept the value. It must not be {@code null}.
     *
     * @return this instance
     */
    public Choice ifRight(Consumer consumer) {
        if (isRight()) {
            consumer.accept(value);
        }

        return this;
    }

    /**
     * Runs the given action if {@link #isRight()} returns {@code false}.
     *
     * @param consumer
     *            the consumer to accept the value. It must not be {@code null}.
     *
     * @return this instance
     */
    public Choice ifWrong(Consumer consumer) {
        if (isWrong()) {
            consumer.accept(value);
        }

        return this;
    }

    /**
     * Maps the represented value if right, keeping the wrong value untouched.
     *
     * @param mapping
     *            the function to map the represented value when
     *            {@link #isRight()}. It must not be {@code null}.
     *
     * @return a new instance representing the mapped value
     */
    public Choice mapRight(Function mapping) {
        return isRight() ? right(mapping.apply(value)) : this;
    }

    /**
     * Maps the represented value if wrong, keeping the right value untouched.
     *
     * @param mapping
     *            the function to map the represented value when
     *            {@link #isWrong()}. It must not be {@code null}.
     *
     * @return a new instance representing the mapped value
     */
    public Choice mapWrong(Function mapping) {
        return isRight() ? this : wrong(mapping.apply(value));
    }

    /**
     * Maps the represented value.
     *
     * @param 
     *            the type of the new value
     * @param whenRight
     *            the function to map the represented value when
     *            {@link #isRight()}. It must not be {@code null}.
     * @param whenWrong
     *            the function to map the represented value when
     *            {@link #isWrong()}. It must not be {@code null}.
     *
     * @return a new instance representing the mapped value
     */
    public  Choice map(Function whenRight, Function whenWrong) {
        return isRight() ? right(whenRight.apply(value)) : wrong(whenWrong.apply(value));
    }

    /**
     * Maps this instance.
     *
     * @param 
     *            the type of the new represented value
     * @param mapping
     *            the mapping function. It must not be {@code null} and it
     *            should not return {@code null}.
     *
     * @return the result of the mapping function
     */
    public  Choice map(Function, Choice> mapping) {
        return mapping.apply(this);
    }

    /**
     * Applies either action depending on {@link #isRight()} result.
     *
     * @param whenRight
     *            the consumer to accept the represented value if
     *            {@link #isRight()}. It must not be {@code null}.
     * @param whenWrong
     *            the consumer to accept the represented value if
     *            {@link #isWrong()}. It must not be {@code null}.
     *
     * @return this instance
     */
    public Choice use(Consumer whenRight, Consumer whenWrong) {
        if (isRight()) {
            whenRight.accept(value);
        } else {
            whenWrong.accept(value);
        }

        return this;
    }

    /**
     * Applies the given action regardless of the actual right or
     * wrong case.
     *
     * @param consumer
     *            the consumer to accept the represented value. It must not be
     *            {@code null}.
     *
     * @return this instance
     */
    public Choice use(Consumer consumer) {
        consumer.accept(value);
        return this;
    }

    /**
     * Maps the represented value and returns it using the appropriate mapping
     * function for the actual right or wrong case.
     *
     * @param 
     *            the type of the new value
     * @param whenRight
     *            the function to map the represented value when
     *            {@link #isRight()}. It must not be {@code null}.
     * @param whenWrong
     *            the function to map the represented value when
     *            {@link #isWrong()}. It must not be {@code null}.
     *
     * @return the mapped value
     */
    public  V reconcile(Function whenRight, Function whenWrong) {
        return isRight() ? whenRight.apply(value) : whenWrong.apply(value);
    }

    /**
     * Maps the represented value and returns it using the given function
     * regardless of the actual right or wrong case.
     *
     * @param 
     *            the type of the new value
     * @param function
     *            the function to map the represented value. It must not be
     *            {@code null}.
     *
     * @return the mapped value
     */
    public  V reconcile(Function function) {
        return function.apply(value);
    }

    /**
     * Maps the represented value and returns it using the appropriate mapping
     * function for the actual right or wrong case.
     *
     * @param 
     *            the type of the new value
     * @param 
     *            the type of the exception that might be thrown
     * @param whenRight
     *            the function to map the represented value when
     *            {@link #isRight()}. It must not be {@code null}.
     * @param whenWrong
     *            the function to map the represented value when
     *            {@link #isWrong()}. It must not be {@code null}.
     *
     * @return the mapped value
     *
     * @throws X
     *             if an operation fails
     */
    public  V resolve(ThrowingOperation whenRight, ThrowingOperation whenWrong) throws X {
        return isRight() ? whenRight.execute(value) : whenWrong.execute(value);
    }

    /**
     * Maps the represented value and returns it using the given function
     * regardless of the actual right or wrong case.
     *
     * @param 
     *            the type of the new value
     * @param 
     *            the type of the exception that might be thrown
     * @param function
     *            the function to map the represented value. It must not be
     *            {@code null}.
     *
     * @return the mapped value
     *
     * @throws X
     *             if an operation fails
     */
    public  V resolve(ThrowingOperation function) throws X {
        return function.execute(value);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy