本記事では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の場合はfalsenameがnullまたは空文字の場合はfalsenameがLower Camel Caseでない場合はfalsetypeがnullの場合はfalsetypeの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事情詳しくないんです。