web-dev-qa-db-fra.com

Vérifier si la valeur renvoyée n'est pas nulle et si c'est le cas l'affecter, sur une ligne, avec un seul appel de méthode

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é?

32
Continuity8

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.

40
dasblinkenlight

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.

44
jhyot

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.

11
Loki

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())
10
Pieter De Bie

Utilise le tien

public static <T> T defaultWhenNull(@Nullable T object, @NonNull T def) {
    return (object == null) ? def : object;
}

Exemple:

defaultWhenNull(getNullableString(), "");

Avantages

  • Fonctionne si vous ne développez pas en Java8  
  • Fonctionne pour le développement Android avec le support de pre API 24 devices
  • N'a pas besoin d'une bibliothèque externe

Désavantages

  • É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() ;-)

1
Levit
dinner = cage.getChicken();
if(dinner == null) dinner = getFreeRangeChicken();

ou

if( (dinner = cage.getChicken() ) == null) dinner = getFreeRangeChicken();
1
crashxxl

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.

0
user1803551

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);
        }
    }

http://mindprod.com/jgloss/atnullable.html

0
shan