java.util.Optional<T>クラスはオブジェクトをラップしてnullチェックを簡素化するためにJava8から導入された比較的新しいクラスである。オブジェクトを格納するためのvalueというインスタンス変数が宣言されている。またオブジェクトが空であることを表すOptional EMPTY = new Optional<>(null)という定数が定義されている。
コンストラクタはprivateになっており,直接new演算子を使って外部からインスタンスを作成することはできない。staticメソッドのof(T value)メソッド,あるいは,ofNullable(T value)を使ってインスタンスを作成する。このstaticメソッド内でprivateなコンストラクタが呼び出されている。
get()メソッドでは,インスタンス変数valueがnullでなければvalueを返す。valueがnullの場合はNoSuchElementExceptionをスローする。
isPresent()メソッドはvalueがnullか否かをチェックする。value != nullを返すだけの実装である。isEmpty()メソッドはその逆で,実装もvalue == nullを返している。
ifPresent(Consumer<? super T> action)メソッドは,同時に導入された関数型プログラミングに対応したものである。valueがnullでない場合に実行するアクションをConsumer型の引数として受け取り,それを実行する。
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)メソッドはifPresent (Consumer action) メソッドに加えて,valueがnullの場合の動作も定義できる。valueがnullの場合の動作はRunnableインタフェースで渡す仕様である。
filter(Predicate<? super T> predicate)メソッドは与えられた条件式に合致するオブジェクトを返すものである。条件式のtest()メソッドがtrueを返したらvalueを返し,falseを返したらEMPTYを返す。
map(Function<? super T, ? extends U> mapper)メソッドは与えられた関数をオブジェクトに適用するものだ。引数で与えられた関数オブジェクトのapply()メソッドにラップしているオブジェクトvalueを渡して,返された値をstaticメソッドofNullable()に渡して新たなOptionalクラスのインスタンスを作成する。
flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)メソッドはmapメソッドと似ているが,戻り値がOptionalではない。
or(Supplier<? extends Optional<? extends T>> supplier)メソッドは,ラップしているオブジェクトvalueがnullでない場合はそのオブジェクトを返し,nullの場合は引数で与えられたオブジェクトを返す。valueがnullの場合の実装は,引数で与えられたSupplierのget()メソッドで取り出したオブジェクトをOptional<T>にキャストしているだけである。
stream()メソッドはStream API用のstreamを作成するメソッドであり,Streamクラスのstaticメソッドof()に移譲している。
orElse(T other)メソッドはとても単純なメソッドで,ラップしているオブジェクトvalueがnullでなければvalueを,valueがnullならば引数として受け取ったotherを返す。
orElseGet(Supplier<? extends T> supplier)メソッドもorElse()メソッドとほぼ同じ実装だが,引数の型がTではなく,Supplier<? extends T>となっている。
orElseThrow()メソッド, orElseThrow(Supplier<? extends X> exceptionSupplier)メソッドは,valueが非null値の場合はvalueを返し,valueがnullの場合は例外をスローする。違いは,スローされる例外クラスが,前者はNoSuchElementExceptionであるのに対して,後者は引数でクラスを指定できる点で,後者ではexceptionSupplier.get()の戻り値をスローする。
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package 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 Optional<T> {
private static final Optional<?> EMPTY = new Optional<>(null);
private final T value;
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
private Optional(T value) {
this.value = value;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(Objects.requireNonNull(value));
}
@SuppressWarnings("unchecked")
public static <T> Optional<T> ofNullable(T value) {
return value == null ? (Optional<T>) EMPTY
: new Optional<>(value);
}
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
public boolean isPresent() {
return value != null;
}
public boolean isEmpty() {
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 Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()) {
return empty();
} else {
return Optional.ofNullable(mapper.apply(value));
}
}
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()) {
return empty();
} else {
@SuppressWarnings("unchecked")
Optional<U> r = (Optional<U>) mapper.apply(value);
return Objects.requireNonNull(r);
}
}
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if (isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<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 Optional)) {
return false;
}
Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}
@Override
public int hashCode() {
return Objects.hashCode(value);
}
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}