Maybe I'm overlooking something, but is there a reason that you can't use Optional#map?
The following example prints nothing, as Optional is short-circuiting in the sense that, if the value inside the Optional doesn't exist (it's null or the Optional is empty), it's treated as empty.
Optional.ofNullable("test")
.map(s -> null)
.ifPresent(System.out::println);
For that reason, I'd think you could just do the following:
return Optional.ofNullable(thing)
.map(x -> x.nullableMethod1(a))
.map(y -> y.nullableMethod2(b))
.map(Z::nullableMethod3);
This would map your thing if it exists, or return an empty Optional otherwise.
Maybe I'm overlooking something, but is there a reason that you can't use Optional#map?
The following example prints nothing, as Optional is short-circuiting in the sense that, if the value inside the Optional doesn't exist (it's null or the Optional is empty), it's treated as empty.
Optional.ofNullable("test")
.map(s -> null)
.ifPresent(System.out::println);
For that reason, I'd think you could just do the following:
return Optional.ofNullable(thing)
.map(x -> x.nullableMethod1(a))
.map(y -> y.nullableMethod2(b))
.map(Z::nullableMethod3);
This would map your thing if it exists, or return an empty Optional otherwise.
In Java 8, the Elvis operator can be simulated by chaining .map(...) calls on an Optional.ofNullable(...) and capping it with .orElse(...):
Optional.ofNullable(dataObject)
.map(DataObject::getNestedDataObject)
.map(NestedDataObject::getEvenMoreNestedDataObject)
...
.orElse(null);
A full example:
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
}
}
Videos
Many popular mainstream languages that focus at least somewhat on conciseness have a similar operator, so I'd say that it is fairly common.
First, some notes:
- For the purposes of this answer, it doesn't matter whether the syntax is
?:,??,||oror, especially since all are equally concise. - What is a "true value" for this operator differs from language to language, and may not be the same as what is considered a "true value" in other contexts (like in an
ifcondition).
Now, let's go though some languages and see what we find:
- C and C++: no Elvis in the standards, since concise syntax sugar does not seem to be focus for these languages
- Java: Elvis was explicitly rejected, seemingly also because syntax sugar is not a focus for Java.
- C#:
??is anull-checking Elvis - Python:
orworks as truthy-checking Elvis - JavaScript:
||works as an Elvis operator that checks for truthiness,??is an Elvis operator that only checks fornullandundefined - PHP:
?:is a truthy-checking Elvis,??is anull-checking Elvis - Ruby:
||works as a truthy-checking Elvis - Go: no Elvis, since Go prefers simplicity of language to conciseness of code
- Swift:
??is anil-checking Elvis - Rust: no Elvis, presumably because Rust does not have concepts similar to truthiness or
null
Some languages simply don't have (a relevant type of) nulls, or don't have the concept of non-Boolean thruthiness, making it a not applicable feature.