Java8 Optional
を使用して次のコードを置き換えたい:
public Obj getObjectFromDB() {
Obj obj = dao.find();
if (obj != null) {
obj.setAvailable(true);
} else {
logger.fatal("Object not available");
}
return obj;
}
次の擬似コードはorElseRun
メソッドがないため機能しませんが、とにかく私の目的を示しています:
public Optional<Obj> getObjectFromDB() {
Optional<Obj> obj = dao.find();
return obj.ifPresent(obj.setAvailable(true)).orElseRun(logger.fatal("Object not available"));
}
Java 9以上では、 ifPresentOrElse
がおそらく必要なものです。
Optional<> opt = dao.find();
opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));
vavr などを使用してカリー化すると、すっきりしたコードになることもありますが、まだ試していません。
単一のステートメントでそれを行うことができるとは思わない。より良い:
if (!obj.isPresent()) {
logger.fatal(...);
} else {
obj.get().setAvailable(true);
}
return obj;
これを複数のステートメントに分割する必要があります。これを行う1つの方法を次に示します。
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
obj.ifPresent(o -> o.setAvailable(true));
return obj;
別の方法(おそらく過剰設計)は、map
を使用することです。
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> {o.setAvailable(true); return o;});
obj.setAvailable
が便利にobj
を返す場合、2番目の例を単純に使用して次のことができます。
if (!obj.isPresent()) {
logger.fatal("Object not available");
}
return obj.map(o -> o.setAvailable(true));
Java 8の場合、Springは ifPresentOrElse
から「オプションで動作するユーティリティメソッド」を使用して、目的を達成します。例は次のとおりです。
import static org.springframework.data.util.Optionals.ifPresentOrElse;
ifPresentOrElse(dao.find(), obj -> obj.setAvailable(true), () -> logger.fatal("Object not available"));
まず、dao.find()
はOptional<Obj>
を返すか、作成する必要があります。
例えば.
Optional<Obj> = dao.find();
または、次のように自分で行うことができます:
Optional<Obj> = Optional.ofNullable(dao.find());
これは、存在する場合はOptional<Obj>
を、存在しない場合はOptional.empty()
を返します。
それでは、解決策に取り掛かりましょう。
public Obj getObjectFromDB() {
return Optional.ofNullable(dao.find()).flatMap(ob -> {
ob.setAvailable(true);
return Optional.of(ob);
}).orElseGet(() -> {
logger.fatal("Object not available");
return null;
});
}
これはあなたが探している唯一のライナーです:)
is.orElseRun
メソッドですが、.orElseGet
と呼ばれますが、問題は、.map
とは異なり、.isPresent
がOptional<Obj>
を返さないことです。
本当に1つのステートメントでこれを実行したい場合、これは可能です。
public Obj getObjectFromDB() {
return dao.find()
.map( obj -> {
obj.setAvailable(true);
return Optional.of(obj);
})
.orElseGet( () -> {
logger.fatal("Object not available");
return Optional.empty();
});
}
しかし、これは以前よりも不格好です。
たとえば、次の2つの「1行」ソリューションを思いつくことができました。
obj.map(o -> (Runnable) () -> o.setAvailable(true))
.orElse(() -> logger.fatal("Object not available"))
.run();
または
obj.map(o -> (Consumer<Object>) c -> o.setAvailable(true))
.orElse(o -> logger.fatal("Object not available"))
.accept(null);
または
obj.map(o -> (Supplier<Object>) () -> {
o.setAvailable(true);
return null;
}).orElse(() () -> {
logger.fatal("Object not available")
return null;
}).get();
見た目はあまり良くありません。orElseRun
のようなものの方がはるかに優れていますが、1行のソリューションが本当に必要な場合は、Runnableのオプションは受け入れられると思います。
Optional.isPresent() および orElse() が必要です。スニペットは、存在しない場合は何も返さないため機能しません。
Optionalのポイントは、メソッドから返すことです。