Java est parsemé de déclarations telles que:
if(cage.getChicken() != null) {
dinner = cage.getChicken();
} else {
dinner = getFreeRangeChicken();
}
Ce qui prend deux appels à getChicken()
avant que l'objet renvoyé puisse être affecté à dinner
.
Cela pourrait aussi être écrit en une ligne comme ceci:
dinner = cage.getChicken() != null? cage.getChicken() : getFreeRangeChicken();
Mais hélas, il y a toujours deux appels à getChicken()
.
Bien sûr, nous pourrions affecter une variable locale, puis utiliser à nouveau l'opérateur ternaire pour l'affecter si ce n'est pas nul, mais il s'agit de deux lignes et pas si joli:
FutureMeal chicken = cage.getChicken();
dinner = chicken != null? chicken : getFreeRangeChicken();
Alors est-il possible de dire:
Variable var = une valeur si une valeur n'est pas nulle OR une autre valeur;
Et je suppose que je ne parle que de syntaxe ici, une fois le code compilé, la manière dont le code a été écrit n’a probablement pas beaucoup changé.
Comme ce code est si courant, il serait bon de pouvoir l'écrire en une seule ligne.
Est-ce que d'autres langues ont cette fonctionnalité?
Java manque d’opérateur coalesce, votre code avec un temporaire explicite est donc votre meilleur choix pour une affectation avec un seul appel.
Vous pouvez utiliser la variable de résultat comme temporaire, comme ceci:
dinner = ((dinner = cage.getChicken()) != null) ? dinner : getFreeRangeChicken();
Ceci, cependant, est difficile à lire.
Même principe que la réponse de Loki mais plus court. Gardez simplement à l'esprit que plus court ne signifie pas automatiquement mieux.
dinner = Optional.ofNullable(cage.getChicken())
.orElse(getFreerangeChicken());
Remarque: Cette utilisation de Optional
est explicitement déconseillée par les architectes du JDK et les concepteurs de la fonction facultative. Vous allouez un nouvel objet et le jetez immédiatement à chaque fois. Mais d'un autre côté, cela peut être assez lisible.
En utilisant Java 1.8, vous pouvez utiliser 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();
}
}
Vous devriez implémenter une logique pour getChicken
renvoyer soit Optional.empty()
au lieu de null, soit Optional.of(myReturnObject)
, où myReturnObject
est votre chicken
.
Ensuite, vous pouvez appeler getChicken()
et si elle renvoie Optional.empty()
, la orElse(fallback)
vous donnera quelle que soit la solution de secours, dans votre cas, la deuxième méthode.
Si vous n'êtes pas encore sur Java 1.8 et que cela ne vous dérange pas d'utiliser commons-lang, vous pouvez utiliser org.Apache.commons.lang3.ObjectUtils # defaultIfNull
Votre code serait:
dinner = ObjectUtils.defaultIfNull(cage.getChicken(),getFreeRangeChicken())
public static <T> T defaultWhenNull(@Nullable T object, @NonNull T def) {
return (object == null) ? def : object;
}
Exemple:
defaultWhenNull(getNullableString(), "");
Évalue toujours le default value
(en opposition à cond ? nonNull() : notEvaluated()
)
Cela pourrait être contourné en passant un Callable au lieu d'une valeur par défaut, mais en le rendant un peu plus compliqué et moins dynamique (par exemple, si les performances posent problème).
À propos, vous rencontrez le même inconvénient lorsque vous utilisez Optional.orElse()
;-)
dinner = cage.getChicken();
if(dinner == null) dinner = getFreeRangeChicken();
ou
if( (dinner = cage.getChicken() ) == null) dinner = getFreeRangeChicken();
Depuis Java 9, vous avez Objects # requireNonNullElse qui:
public static <T> T requireNonNullElse(T obj, T defaultObj) {
return (obj != null) ? obj : requireNonNull(defaultObj, "defaultObj");
}
Votre code serait
dinner = Objects.requireNonNullElse(cage.getChicken(), getFreeRangeChicken());
Ce qui correspond à 1 ligne et appelle getChicken()
une seule fois pour que les deux conditions soient satisfaites.
Notez que le deuxième argument ne peut pas être aussi null
; cette méthode force la non-nullité de la valeur renvoyée.
Examinez également l'option Objects # requireNonNullElseGet :
public static <T> T requireNonNullElseGet(T obj, Supplier<? extends T> supplier)
ce qui n'évalue même pas le deuxième argument si le premier n'est pas null
, mais entraîne la surcharge de créer un Supplier
.
Alternativement, en Java8, vous pouvez utiliser les annotations Nullable ou NotNull en fonction de vos besoins.
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);
}
}