StreamAPIも大好きですよ。
前回はラムダもなるべく推さないように書いていたつもりですがさすがに今回は使います。
#Optional#map
Optionalは、nullかもしれない返り値を示すやつですが、
返り値以外で使っても便利だと思うのです。
##数珠つなぎなnullチェック
public static class Struct1 {
private final Struct2 value;
public Struct1(Struct2 value) {
this.value = value;
}
public Struct2 getValue() {
return this.value;
}
}
public static class Struct2 {
private final Struct3 value;
public Struct2(Struct3 value) {
this.value = value;
}
public Struct3 getValue() {
return this.value;
}
}
public static class Struct3 {
private final String value;
public Struct3(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
}
private static Struct1 data1 = new Struct1(new Struct2(new Struct3("DATA")));
private static Struct1 data2 = new Struct1(new Struct2(null));
private static Struct1 data3 = null;
public static void main(String[] args) {
System.out.println(getStruct3Value(data1));//DATA
System.out.println(getStruct3Value(data2));//null
System.out.println(getStruct3Value(data3));//null
}
/**
* Struct3のvalueを取得。途中nullだったらnullを返す。
*/
public static String getStruct3Value(Struct1 struct1) {
if (struct1 == null) {
return null;
}
Struct2 struct2 = struct1.getValue();
if (struct2 == null) {
return null;
}
Struct3 struct3 = struct2.getValue();
if (struct3 == null) {
return null;
}
return struct3.getValue();
}
みたいなnullチェックの嵐を書くような場合、Optional#mapが使えます。
public static String getStruct3Value(Struct1 struct1) {
Optional<Struct1> opt = Optional.ofNullable(struct1);
return opt.map(Struct1::getValue)
.map(Struct2::getValue)
.map(Struct3::getValue)
.orElse(null);
}
と。スッキリしますね。
数珠つなぎなnullチェック嵐じゃなくて、次のようなnullチェック嵐でも使えます。
##複数個所でのnullチェック
public static class Foo {
private final String value1;
private final String value2;
public Foo(String value1, String value2) {
this.value1 = value1;
this.value2 = value2;
}
public String getValue1() {
return this.value1;
}
public String getValue2() {
return this.value2;
}
}
/**
* value1のlenthを取得。fooがnullだったら0をかえす
*/
public static int getValue1Length(Foo foo) {
if (foo != null) {
if (foo.getValue1() != null) {
return foo.getValue1().length();
}
}
return 0;
}
/**
* value2のlenthを取得。fooがnullだったら0をかえす
*/
public static int getValue2Length(Foo foo) {
if (foo != null) {
if (foo.getValue2() != null) {
return foo.getValue2().length();
}
}
return 0;
}
っていうような、数ヶ所のnullチェックの嵐がある場合も、
Optionalを使って、
public static int getValue1Length(Optional<Foo> foo) {
return foo.map(Foo::getValue1)
.map(String::length)
.orElse(0);
}
public static int getValue2Length(Optional<Foo> foo) {
return foo.map(Foo::getValue2)
.map(String::length)
.orElse(0);
}
とやると簡潔になりますしミスが少なくなりそうで便利です。
Optional使いたくなりませんか。
#おまけ
で、本気でOptional使おうと思うと実はなかなか難しかったりすると思います。
Optionalはnullかもしれない値を返すということなので、nullになりえない値はOptionalじゃないってことですよね。
すでにあるプログラムの返り値はOptionalじゃないわけですから、ほうっておいたらどちらなのかわかりませんね。
全部書き換えるのは現実的じゃないですし、そもそもJavaさんのMap#getもOptional返してくれませんし、それに相当するメソッドもありません。
現実的にはたまにOptionalつかって便利にこなす位がちょうどいいんじゃないかなーなんて勝手に思ってます。
その3に続く。
その1:Java8が好きになる話(StreamAPIの話はしない) その1 Map#computeIfAbsentとList#sort