StreamとOptionalに共通して存在するメソッドの第二弾。 第一弾はこちら。
前回の記事では、filter()
について書いた。今回は、of()
とofNullable()
について書……こうと思ったら実はempty()
も共通して存在するメソッドだったことに気づいたので、これも併せて3つのメソッドについて書く。
ファクトリメソッド: of()
とofNullable
とempty()
メソッド | Stream | Optional |
---|---|---|
of() | static |
public static |
ofNullable() | static |
public static |
empty() | static |
public static |
of()
とofNullable()
とempty()
は、StreamとOptionalのいずれにおいてもstaticのファクトリメソッドだ。Streamはクラスではなくインタフェースだが、Java 8からはインタフェースにstaticメソッドが書けるようになっているため*1、ファクトリメソッドを定義することができる。実際には、下記のように定義されている。
public static<T> Stream<T> of(T t) { return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); } public static<T> Stream<T> ofNullable(T t) { return t == null ? Stream.empty() : StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); } public static<T> Stream<T> empty() { return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false); }
対して、Optionalのそれぞれのメソッドの定義は下記の通りだ。
public static <T> Optional<T> of(T value) { return new Optional<>(value); } public static <T> Optional<T> ofNullable(T value) { return value == null ? empty() : of(value); } public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
こうして並べてみると、StreamとOptionalのそれぞれにおいて、of()
とofNullable()
という2つのメソッドの関係が同じであることがよくわかる。of()
が引数で受け取った何らかの値をそのままStreamないしOptionalに包んで「返そうとする」のに対して、ofNullable()
は引数がnullだった場合は空のインスタンス(それぞれのempty()
メソッドで取得する)を返し、nullでない場合はof()
と同じ結果を返すようになっている。空のインスタンスについては、その挙動を含めて次回に回す。
of()にnullを渡した場合の挙動の差異
それでは、of()
の引数にnullを渡した場合の挙動はどうなるのか。これはStreamとOptionalで異なっており、Streamのof()
が、単に(nullが実体を持ったオブジェクトであるかのような表現には語弊があるが)「null 1つ」を要素とするStreamを返すのに対し、Optionalのof()
はNullPointerException
をスローする*2。下記のコードで実際に動作を確認できる。
/* JUnit5を利用 */ @Test void Streamのofはnullを含むStreamを返す() { List<Object> list = Stream.of((Object)null).collect(Collectors.toList()); assertEquals(1, list.size()); // 要素数は1 assertNull(list.get(0)); // その要素はnull } @Test void Optionalのofは例外をスローする() { final String helloWorld = "Hello World"; Optional<Object> opt = Optional.of(helloWorld); Exception exception = null; // スローされたら格納しておく try { opt = Optional.of(null); fail("例外がスローされるので到達したらいけないコード"); } catch (Exception e) { exception = e; assertEquals(NullPointerException.class, e.getClass()); } assertEquals(helloWorld, opt.get()); // 当初の値のままであるはず assertNotNull(exception); // 例外がスローされていることを確認 }
その他の違い
以上のように、of()
にnullを渡した際の挙動はStreamとOptionalとで異なっている。その他に、異なる点としては、
- Optionalの
of()
には(Optionalの性質上)単一の引数のものしか存在しないのに対して、Streamのof()
にはof(T... values)
という可変長引数のものも存在している。 - これら6つのメソッドのうち、Streamの
ofNullable()
だけは導入されたバージョンがJava 9であり、一世代新しい。
という点が挙げられる。
感想と次回予告
じっくりと仕様と実装を見てみると、普段いかに雰囲気で使ってしまっているかに気づくことができた。とはいえ、ファクトリはファクトリでしかないので、それぞれの生成の仕方にどのような意味があるのかは、生成が利用される場面とセットでなければわかりにくい。次の記事では、map()
とflatMap()
を紹介しながら、今回の記事で扱ったファクトリをどのように利用するかにも言及したい。