独自のOptionalを定義する
Optionalへの不満
最近とみにOptionalの便利さを実感してきているのだが、しかし不満がある。
Serializableではない
不要な人には不要だろうが、必要な者には必要なのである。これだけはどうにもならず、シリアライゼーションするにはOptionalをわざわざ、orElse(null)としなければならないわけだ。
逆にシリアライゼーション復帰の際は、Optional.ofNullable(value)としなければならない。とても面倒だ。
Java9, Java10で機能追加されている
ターゲットはJava8なのだが、特にJava9で追加されたifPresentOrElseは欲しいところ。しかし使えない。その他にも様々なメソッドが追加されている。この位はなから用意できなかったのだろうか?あまりにも想像力がなさすぎると思う。
独自のOptional
そこで独自のOptionalを作ってしまう。とはいっても単にJava10のOptionalのまるコピーだ。
package somePackage;
import java.io.*;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
public final class Opt<T> implements Serializable {
private static final long serialVersionUID = 1L;
private static final Opt<?> EMPTY = new Opt<>();
private final T value;
private Opt() {
this.value = null;
}
public static <T> Opt<T>fromOptional(Optional<T>opt) {
return Opt.ofNullable(opt.orElse(null));
}
public Optional<T>toOptional() {
return Optional.ofNullable(value);
}
public static <T> Opt<T> empty() {
@SuppressWarnings("unchecked")
Opt<T> t = (Opt<T>) EMPTY;
return t;
}
private Opt(T value) {
this.value = Objects.requireNonNull(value);
}
public static <T> Opt<T> of(T value) {
return new Opt<>(value);
}
public static <T> Opt<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> action) {
if (value != null) {
action.accept(value);
}
}
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
public Opt<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
public <U> Opt<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()) {
return empty();
} else {
return Opt.ofNullable(mapper.apply(value));
}
}
public <U> Opt<U> flatMap(Function<? super T, ? extends Opt<? extends U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()) {
return empty();
} else {
@SuppressWarnings("unchecked")
Opt<U> r = (Opt<U>) mapper.apply(value);
return Objects.requireNonNull(r);
}
}
public Opt<T> or(Supplier<? extends Opt<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if (isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Opt<T> r = (Opt<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
public Stream<T> stream() {
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> supplier) {
return value != null ? value : supplier.get();
}
public T orElseThrow() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Opt)) {
return false;
}
Opt<?> other = (Opt<?>) obj;
return Objects.equals(value, other.value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public String toString() {
return value != null ? String.format("Opt[%s]", value) : "Opt.empty";
}
}
ただし、メソッドを追加してることに注意。Optionalからの変換と逆変換だ。単純に以下のようなものである。
public static <T> Opt<T>fromOptional(Optional<T>opt) {
return Opt.ofNullable(opt.orElse(null));
}
public Optional<T>toOptional() {
return Optional.ofNullable(value);
}