Check if returned value is not null and if so assign it, in one line, with one method call
JavaSyntaxNullVariable AssignmentMethod CallJava Problem Overview
Java is littered with statements like:
if(cage.getChicken() != null) {
dinner = cage.getChicken();
} else {
dinner = getFreeRangeChicken();
}
Which takes two calls to getChicken()
before the returned object can be assigned to dinner
.
This could also be written in one line like so:
dinner = cage.getChicken() != null? cage.getChicken() : getFreeRangeChicken();
But alas there are still two calls to getChicken()
.
Of course we could assign a local variable then use the ternary operator again to assign it if it is not null, but this is two lines and not so pretty:
FutureMeal chicken = cage.getChicken();
dinner = chicken != null? chicken : getFreeRangeChicken();
So is there any way to say:
> Variable var = some value if some value is not null OR some other > value;
And I guess I'm just talking syntax here, after the code is compiled it probably doesn't make much difference how the code was written in a performance sense.
As this is such common code it'd be great to have a one-liner to write it.
Do any other languages have this feature?
Java Solutions
Solution 1 - Java
Same principle as Loki's answer but shorter. Just keep in mind that shorter doesn't automatically mean better.
dinner = Optional.ofNullable(cage.getChicken())
.orElse(getFreerangeChicken());
Note: This usage of Optional
is explicitly discouraged by the architects of the JDK and the designers of the Optional feature. You are allocating a fresh object and immediately throwing it away every time. But on the other hand it can be quite readable.
Solution 2 - Java
Java lacks coalesce operator, so your code with an explicit temporary is your best choice for an assignment with a single call.
You can use the result variable as your temporary, like this:
dinner = ((dinner = cage.getChicken()) != null) ? dinner : getFreeRangeChicken();
This, however, is hard to read.
Solution 3 - Java
Since Java 9 you have Objects#requireNonNullElse which does:
public static <T> T requireNonNullElse(T obj, T defaultObj) {
return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
}
Your code would be
dinner = Objects.requireNonNullElse(cage.getChicken(), getFreeRangeChicken());
Which is 1 line and calls getChicken()
only once, so both requirements are satisfied.
Note that the second argument cannot be null
as well; this method forces non-nullness of the returned value.
Consider also the alternative Objects#requireNonNullElseGet:
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
which does not even evaluate the second argument if the first is not null
, but does have the overhead of creating a Supplier
.
Solution 4 - Java
If you're not on java 1.8 yet and you don't mind to use commons-lang you can use org.apache.commons.lang3.ObjectUtils#defaultIfNull
Your code would be:
dinner = ObjectUtils.defaultIfNull(cage.getChicken(),getFreeRangeChicken())
Solution 5 - Java
Using Java 1.8 you can use Optional
public class Main {
public static void main(String[] args) {
//example call, the methods are just dumb templates, note they are static
FutureMeal meal = getChicken().orElse(getFreeRangeChicken());
//another possible way to call this having static methods is
FutureMeal meal = getChicken().orElseGet(Main::getFreeRangeChicken); //method reference
//or if you would use a Instance of Main and call getChicken and getFreeRangeChicken
// as nonstatic methods (assume static would be replaced with public for this)
Main m = new Main();
FutureMeal meal = m.getChicken().orElseGet(m::getFreeRangeChicken); //method reference
//or
FutureMeal meal = m.getChicken().orElse(m.getFreeRangeChicken()); //method call
}
static Optional<FutureMeal> getChicken(){
//instead of returning null, you would return Optional.empty()
//here I just return it to demonstrate
return Optional.empty();
//if you would return a valid object the following comment would be the code
//FutureMeal ret = new FutureMeal(); //your return object
//return Optional.of(ret);
}
static FutureMeal getFreeRangeChicken(){
return new FutureMeal();
}
}
You would implement a logic for getChicken
to return either Optional.empty()
instead of null, or Optional.of(myReturnObject)
, where myReturnObject
is your chicken
.
Then you can call getChicken()
and if it would return Optional.empty()
the orElse(fallback)
would give you whatever the fallback would be, in your case the second method.
Solution 6 - Java
Use your own
public static <T> T defaultWhenNull(@Nullable T object, @NonNull T def) {
return (object == null) ? def : object;
}
Example:
defaultWhenNull(getNullableString(), "");
Advantages
- Works if you don't develop in Java8
- Works for android development with support for pre API 24 devices
- Doesn't need an external library
Disadvantages
-
Always evaluates the
default value
(as oposed tocond ? nonNull() : notEvaluated()
)This could be circumvented by passing a Callable instead of a default value, but making it somewhat more complicated and less dynamic (e.g. if performance is an issue).
By the way, you encounter the same disadvantage when using
Optional.orElse()
;-)
Solution 7 - Java
dinner = cage.getChicken();
if(dinner == null) dinner = getFreeRangeChicken();
or
if( (dinner = cage.getChicken() ) == null) dinner = getFreeRangeChicken();
Solution 8 - Java
Alternatively in Java8 you can use Nullable or NotNull Annotations according to your need.
public class TestingNullable {
@Nullable
public Color nullableMethod(){
//some code here
return color;
}
public void usingNullableMethod(){
// some code
Color color = nullableMethod();
// Introducing assurance of not-null resolves the problem
if (color != null) {
color.toString();
}
}
}
public class TestingNullable {
public void foo(@NotNull Object param){
//some code here
}
...
public void callingNotNullMethod() {
//some code here
// the parameter value according to the explicit contract
// cannot be null
foo(null);
}
}
Solution 9 - Java
You could use
Objects.requireNonNullElse(cage.getChicken(), getFreerangeChicken())
even nicer with static import:
import static java.util.Objects.requireNonNullElse;
requireNonNullElse(cage.getChicken(), getFreerangeChicken())