私は古典的な「エルビス演算子」の場合があり、それぞれがnullを返し、それらを連結するメソッドを呼び出しています:
thing?:nullableMethod1(a)?:nullableMethod2(b)?:nullableMethod3()
Java 8では、私が見つけた最も忠実な実装は次のようなものです。
return Optional.ofNullable(thing)
.flatMap(x -> Optional.ofNullable(x.nullableMethod1(a)))
.flatMap(y -> Optional.ofNullable(y.nullableMethod2(b)))
.flatMap(z -> Optional.ofNullable(z.nullableMethod3()))
JavaのOptional
にelvis演算子に似たものがあればいいのにと思います。
public<U> Optional<U> elvisOperator(Function<? super T, ? extends U> mapper) {
return flatMap(t -> Optional.ofNullable(mapper.apply(t));
}
したがって、各戻り値をラップする必要はありません。
return Optional.ofNullable(thing)
.elvisOperator(x -> x.nullableMethod1(a))
.elvisOperator(y -> y.nullableMethod2(b))
.elvisOperator(Z::nullableMethod3); // also Nice
Java 8でElvis演算子パターンを実装するより効率的で慣用的な方法はありますか?
何かを見落としているかもしれませんが、Optional#map
を使用できない理由はありますか?
次の例では、Optional
が短絡であるため、Optional
内の値が存在しない場合(null
またはOptional
が空の場合)、空として扱われます。
Optional.ofNullable("test")
.map(s -> null)
.ifPresent(System.out::println);
そのため、次のことができると思います。
return Optional.ofNullable(thing)
.map(x -> x.nullableMethod1(a))
.map(y -> y.nullableMethod2(b))
.map(Z::nullableMethod3);
これは、thing
が存在する場合はマップし、存在しない場合は空のOptional
を返します。
Java 8)では、.map(...)
のOptional.ofNullable(...)
呼び出しをチェーンし、.orElse(...)
でキャップすることにより、エルビス演算子をシミュレートできます。
Optional.ofNullable(dataObject)
.map(DataObject::getNestedDataObject)
.map(NestedDataObject::getEvenMoreNestedDataObject)
...
.orElse(null);
完全な例:
import Java.util.Optional;
class Main {
// Data classes:
static class Animal {
Leg leg;
Animal(Leg leg) {
this.leg = leg;
}
Leg getLeg(){return this.leg;}
public String toString(){
String out = "This is an animal";
out += leg != null ? " with a leg" : "";
return out;
}
}
static class Leg {
Toes toes;
Leg(Toes toes) {
this.toes = toes;
}
Toes getToes(){return this.toes;}
public String toString(){
String out = "This is a leg";
out += toes != null ? " with a collection of toes" : "";
return out;
}
}
static class Toes {
Integer numToes;
Toes(Integer numToes) {
this.numToes = numToes;
}
Integer getNumToes(){return this.numToes;}
public String toString(){
String out = "This is a collection of ";
out += numToes != null && numToes > 0 ? numToes : "no";
out += " toes";
return out;
}
}
// A few example Elvis operators:
static Integer getNumToesOrNull(Animal a) {
return Optional.ofNullable(a)
.map(Animal::getLeg)
.map(Leg::getToes)
.map(Toes::getNumToes)
.orElse(null);
}
static Toes getToesOrNull(Animal a) {
return Optional.ofNullable(a)
.map(Animal::getLeg)
.map(Leg::getToes)
.orElse(null);
}
static Leg getLegOrNull(Animal a) {
return Optional.ofNullable(a)
.map(Animal::getLeg)
.orElse(null);
}
// Main function:
public static void main(String[] args) {
// Trying to access 'numToes':
System.out.println(getNumToesOrNull(new Animal(new Leg(new Toes(4))))); // 4
System.out.println(getNumToesOrNull(new Animal(new Leg(new Toes(null))))); // null
System.out.println(getNumToesOrNull(new Animal(new Leg(null)))); // null
System.out.println(getNumToesOrNull(new Animal(null))); // null
System.out.println(getNumToesOrNull(null)); // null
// Trying to access 'toes':
System.out.println(getToesOrNull(new Animal(new Leg(new Toes(4))))); // This is a collection of 4 toes
System.out.println(getToesOrNull(new Animal(new Leg(new Toes(null))))); // This is a collection of no toes
System.out.println(getToesOrNull(new Animal(new Leg(null)))); // null
System.out.println(getToesOrNull(new Animal(null))); // null
System.out.println(getToesOrNull(null)); // null
// Trying to access 'leg':
System.out.println(getLegOrNull(new Animal(new Leg(new Toes(4))))); // This is a leg with a collection of toes
System.out.println(getLegOrNull(new Animal(new Leg(new Toes(null))))); // This is a leg with a collection of toes
System.out.println(getLegOrNull(new Animal(new Leg(null)))); // This is a leg
System.out.println(getLegOrNull(new Animal(null))); // null
System.out.println(getLegOrNull(null)); // null
}
}