Java8の機能を実務でどこまで使うかを比較的まじめに考えてみようと思う。
地味だけどまずはOptionalから。
SI業務においては新機能を何でも取り入れるというのは現実的ではないと思うので、使いどころとか、それはアプリケーション担当が意識するか?という観点も入れていきたい。
先にまとめるとOptionalはアプリケーション担当も意識しておいた方が良い知識だと思う。
個人的感想としてOptionalには二つの意義があって、一つは、型がOptionalであることにより、nullが含まれる可能性を明瞭に示せること。もう一つは、nullの場合の操作を提供してくれること。
実益はnullガード戦法の抜けによるNPE発生トラブル抑止になることが期待されていると思うのだが、そもそもnullがありうると気づいていればnullガード戦法でも何とかなるので、その気づきを増やすことが大事なのではないかと思った次第。
あまり細かく説明しませんが、勉強用に書いたコードを晒しておきます。
package java8_study.optional;
import java.util.Optional;
/**
* APIがレガシーな例。
* @author akiraabe
*/
public class Sample1 {
public static void main(String[] args) {
// ---(1) 直接toUpperCaseを呼び出す。
String str1 = "abe";
System.out.println(str1.toUpperCase());
// 値がnullだった場合・・・
String nullStr = null;
//下記文は当然ながらNPEになる。
//System.out.println(nullStr.toUpperCase());
//したがってnullガード戦法を取る
if (nullStr != null) {
System.out.println(nullStr.toUpperCase());
}
// ---(2) toUpperCaseをラップしたnullセーフなメソッドを使う
String str3 = "akira";
System.out.println(myUpper(str3));
// 値がnullだった場合でもラッパーを呼びだせばとりあえずOK
System.out.println(myUpper(nullStr));
// とはいえ、myUpperメソッドからもnullが返ってくることには変わらない。
// --(3) レガシーAPIを前提にOptionalで包み込む
// 参考:http://www.slideshare.net/kawasima
String upperdString = Optional
.ofNullable(myUpper(nullStr))
.orElse("<NULL>");
System.out.println(upperdString);
}
/**
* 引数を受けてUpperに変換するnullセーフなメソッド。<br>
* Optionalは使っていないレガシーなAPI.
*
* @param str 文字列
* @return 大文字変換された文字列(引数がnullならnullを返却)
*/
private static String myUpper(String str) {
if (str == null) {
return null;
} else {
return str.toUpperCase();
}
}
}
続いて2作目!
package java8_study.optional;
import java.util.Optional;
/**
* API(ここではprivateメソッドのこと)自体がOptionalに対応。
*
* @author akiraabe
*/
public class Sample2 {
public static void main(String[] args) {
// ---(1) toUpperCaseをラップしOptionalが返ってくるメソッドを使う
String str1 = "akira";
System.out.println(myUpper(str1));
String ret1 = myUpper(str1).orElse("<NULL>");
System.out.println(ret1);
// 値がnullだった場合でもラッパーを呼びだせばとりあえずOK
System.out.println(myUpper(null));
String ret2 = myUpper(null).orElse("<NULL>");
System.out.println(ret2);
// しかし、これだとアプリのプログラマがOptionalの使い方を習得する必要がある
//(習得しろよ!という説はあるが)
// というのと、結局nullの場合の動作が所与のものとして決められるならば、
// それをAPI側の責務にしてもよいと思う。
// --(2) なのでもう少しAPIに責務を寄せてみる
String ret3 = mySmartUpper(str1);
System.out.println(ret3);
String ret4 = mySmartUpper(null);
System.out.println(ret4);
String ret5 = mySmartUpper(null, "**");
System.out.println(ret5);
}
/**
* 引数を受けてUpperに変換するnullセーフなメソッド。<br>
* Optionalとして返却するAPI.
*
* @param str 文字列
* @return 大文字変換された文字列(引数がnullならnullを返却)
*/
private static Optional<String> myUpper(String str) {
if (str == null) {
return Optional.ofNullable(str); // emptyを返した方が親切?
} else {
return Optional.of(str.toUpperCase());
}
}
/**
* 引数を受けてUpperに変換するnullセーフなメソッド。<br>
* 一部の処理をmyUpperに委譲し、Stringを返す。
*
* @param str 文字列
* @param initVal nullの場合の初期値指定
* @return 大文字変換された文字列(引数がnullなら指定の初期値を返却を返却)
*/
private static String mySmartUpper(String str, String initVal) {
if (str == null && initVal != null) {
return initVal;
}
return myUpper(str).orElse("<NULL>");
}
/**
* 上に委譲する。
*/
private static String mySmartUpper(String str) {
return mySmartUpper(str, null);
}
}
第一次の落としどころは、Sample2の(1)のレベルかと思う。
ラップは部品側でしてあげて、アプリケーション担当はOptionalから取り出す操作を実装する。
その操作があまりにも定型であれば、定型部分をprivateメソッドやHelperに括りだし、Sample2(2)のような形にする。ただしこれはアプリケーション担当の仕事と捉えた方が良いと思う。(ケースバイケースかもしれないが、これが定型になるのかどうかは仕様に依存するから)
Sample1(3)は、ラップしつつ受け取るというのをアプリケーション担当が実装するのだとすると、ちょっと敷居が高い気がするが、これはチームの技術力とか要件によってはありかと。
最後になりますが、この辺りの記事を参考にしました。ありがとうございます。
http://qiita.com/oohira/items/9c13f92815266cc5112c
http://www.slideshare.net/kawasima/java-62447735