package com.github.kmkt.util; import java.util.NoSuchElementException; import java.util.Objects; /** * 値が未設定の場合にデフォルト値を返す Optional。 * * デフォルト値が設定された DefaultOptional では、 {@link #get()} で得られる値が * デフォルト値か {@link #set(Object)} された値か {@link #isDefault()} で判断できる */ public class DefaultOptional<T> { private T value = null; private boolean present = false; private boolean def = false; /** * 値が未設定の DefaultOptional インスタンスを返す。 * このメソッドで得られるインスタンスの {@link #isDefault()} は常に true を返し、 * {@link #set(Object)} で値が指定されるまで {@link #isPresent()} は false を返す。 * @return 値が未設定の DefaultOptional */ public static <T> DefaultOptional<T> empty() { return new DefaultOptional<T>(); } /** * 指定された非 null 値を持つ DefaultOptional インスタンスを返す。 * このメソッドで得られるインスタンスの {@link #isPresent()} は常に true を返し、 * {@link #isDefault()} は常に false を返す。 * @param value 設定する値 notnull * @return 指定された非 null 値を持つ DefaultOptional * @throws NullPointerException value == null 時 */ public static <T> DefaultOptional<T> of(T value) { DefaultOptional<T> result = DefaultOptional.empty(); result.set(value); return result; } /** * 指定された非 null のデフォルト値を持つ DefaultOptional インスタンスを返す。 * このメソッドで得られるインスタンスの {@link #isPresent()} は常に true を返し、 * {@link #set(Object)} で値が指定されるまで {@link #isDefault()} は true を返す。 * @param default_value 設定するデフォルト値 notnull * @return 指定された非 null 値を持つ DefaultOptional * @throws NullPointerException default_value == null 時 */ public static <T> DefaultOptional<T> withDefault(T default_value) { return new DefaultOptional<T>(default_value); } /** * 値が未設定の DefaultOptional インスタンスを生成する。 * このコンストラクタで得られるインスタンスの {@link #isDefault()} は常に true を返し、 * {@link #set(Object)} で値が指定されるまで {@link #isPresent()} は false を返す。 */ private DefaultOptional() { present = false; def = true; } /** * 指定された非 null のデフォルト値を持つ DefaultOptional インスタンスを生成する。 * このコンストラクタで得られるインスタンスの {@link #isPresent()} は常に true を返し、 * {@link #set(Object)} で値が指定されるまで {@link #isDefault()} は true を返す。 * @param default_value 設定するデフォルト値 notnull * @throws NullPointerException default_value == null 時 */ private DefaultOptional(T default_value) { Objects.requireNonNull(default_value, "default_value should not be null"); present = true; def = true; value = default_value; } /** * 非 null 値を設定する。 * {@link #isPresent()} は true となり、{@link #isDefault()} は false となる。 * @param value 設定する値 notnull * @throws NullPointerException value == null 時 */ public synchronized void set(T value) { Objects.requireNonNull(value, "value should not be null"); present = true; def = false; this.value = value; } /** * この DefaultOptional に値が設定されている場合はその値を返し、それ以外は NoSuchElementException をスローする。 * @return この DefaultOptional に設定されている非 null 値 * @throws NoSuchElementException */ public synchronized T get() { if (!isPresent()) throw new NoSuchElementException(); return value; } /** * この DefaultOptional に値が設定されている場合は true を返し、それ以外では false を返す。 * @return 値が設定されている場合は true 、それ以外では false */ public synchronized boolean isPresent() { return present; } /** * この DefaultOptional に値がデフォルト値のままの場合は true を返し、それ以外では false を返す。 * @return デフォルト値のままの場合は true 、それ以外では false */ public synchronized boolean isDefault() { return def; } /** * この DefaultOptional に値が設定されている場合はその値を返し、それ以外の場合は other を返す。 * @param other この DefaultOptional に値が設定されていない場合に返す値。 nullable * @return この DefaultOptional に値が設定されている場合はその値、それ以外の場合は other */ public synchronized T orElse(T other) { return (isPresent() ? value : other); } }