本記事ではJava8から入ったOptional
の最も正しくない使い方を解説します。
なお、これが正しいか正しくないかは読者の方の個人的なセンスにお任せします。
正しくない使い方
入力されたBeanの検証をするときに、if(condition1) { return false; } else if (condition2) { return true; } else { return condition3;}
のようなif else
の連鎖を書きたくないために、Optional#filter
を使う。
モティベーション
if 〜 else if 〜 else if 〜
を書くのが面倒い
お題
次のようなインターフェースを持ったBeanの検証を考えます。
@Managed public interface PropertyEntry { String getName(); void setName(String name); Type getType(); void setType(Type type); String getRefType(); void setRefType(); } enum Type { STRING("String", false), INTEGER("Integer", false), SET("Set", true), REF("", true); Type(String typeName, boolean refToAnotherType) {/*constructor 省略*/} // getter 省略 }
さて、このBeanですが、次のようなValidationを行います。
PropertyEntry
オブジェクトがnull
の場合はfalse
name
がnull
または空文字の場合はfalse
name
がLower Camel Caseでない場合はfalse
type
がnull
の場合はfalse
type
のrefToAnother
の値に応じて次の値を返すrefToAnother
がfalse
ならtrue
を返すrefToAnother
がtrue
の場合refType
がnull
ならfalse
を返すrefType
が空文字ならfalse
を返すrefType
がType
のtypeName
のいずれかと一致するならfalse
を返す- それ以外なら
true
を返す
if 〜 else if 〜
を使う
public static boolean wellDefined(PropertyEntry entry) { if (entry == null) { return false; }else if(entry.getName() == null) { return false; } else if (entry.getName().isEmpty() == false) { return false; } else if // ... 面倒になってきた }
もう、なんか、3つ目のelse if
描き始めた時に面倒さが噴出してきました。
Optional
を使う
まず、Predicate<PropertyEntry>
を大量に用意します。
このときに用意するPredicate<PropertyEntry>
はOKにしたいパターンの条件を書いていきます。
// nameがnullでないときはOK private static final Predicate<PropertyEntry> NAME_NOT_NULL = e -> e.getName() != null; // nameが空文字でないときはOK private static final Predicate<PropertyEntry> NAME_NOT_EMPTY = e -> !e.getName().isEmpty(); // 省略 // refToAnotherしてないならOK private static final Predicate<PropertyEntry> TYPE_NOT_REF_TO_ANOTHER = e -> !e.getType().isRefToAnother(); // refTypeがnullでないならOK private static final Predicate<PropertyEntry> REF_NOT_NULL = e -> e.getRefType() != null; // refTypeが空文字列でないならOK private static final Predicate<PropertyEntry> REF_NOT_EMPTY = e -> !e.getRefType().isEmpty(); // refTypeがTypeのtypeName以外の名前ならOK private static final Predicate<PropertyEntry> REF_NOT_PROHIBITED = //省略 // refTypeがちゃんと定義されている private static final Predicate<PropertyEntry> REF_WELL_DEFINED = REF_NOT_NULL .and(REF_NOT_EMPTY) .and(REF_NOT_PROHIBITED);
あとは、Optional
を使ってわかりやすい条件を書いていきます。
public static boolean wellDefined(PropertyEntry entry) { return Optional.ofNullable(entry) .filter(NAME_NOT_NULL) .filter(NAME_NOT_EMPTY) .filter(NAME_MATCHES_RULE) .filter(TYPE_NOT_NULL) .filter(TYPE_NOT_REF_TO_ANOTHER.or(REF_WELL_DEFINED)) .map(e -> true) .orElse(false); }
Predicate
の名前を適切につけてやれば、if 〜 else if 〜
より読みやすい!と思いませんか?
…思わない。はい、すみません(´・ω・`)
結論
もう、すでにやってる?すみません、仕事してないので最新のJava事情詳しくないんです。