Est-il un moyen élégant pour obtenir la première valeur non nulle de plusieurs méthode retourne en Java?

Vous l'avez déjà vu à de nombreuses reprises vous-même, de qui je suis sûr:

public SomeObject findSomeObject(Arguments args) {
    SomeObject so = queryFirstSource(args); //the most likely source first, hopefully
    if (so != null) return so;

    so = querySecondSource(args); //a source less likely than the first, hopefully
    if (so != null) return so;

    so = queryThirdSource(args); //a source less likely than the previous, hopefully
    if (so != null) return so;

    //and so on
}

Nous avons différentes sources où un objet de recherche pourrait être. Comme un exemple frappant nous pourrions image que nous avons d'abord vérifier si un utilisateur est dans la liste des utilisateurs privilégiés. Si pas, nous vérifions si le nom est dans la liste des utilisateurs autorisés. D'autre nous retourner la valeur null. (C'est pas le meilleur exemple, mais j'espère que c'est un vif-assez.)

Goyave nous offre quelques aides que l'on pourrait embellir le code ci-dessus:

public SomeObject findSomeObject(Arguments args) {
    //if there are only two objects
    return com.google.common.base.Objects.firstNonNull(queryFirstSource(args), querySecondSource(args));

    //or else
    return com.google.common.collect.Iterables.find(
        Arrays.asList(
            queryFirstSource(args)
            , querySecondSource(args)
            , queryThirdSource(args)
            //, ...
        )
        , com.google.common.base.Predicates.notNull()
    );
 }

Mais, comme les plus expérimentés d'entre nous ont déjà vu, cela peut mal fonctionner si les recherches (c'est à dire queryXXXXSource(args)) prendre un certain temps. C'est parce que nous avons maintenant la requête de toutes les sources d'abord, puis de transmettre les résultats à la méthode qui trouve le premier parmi ces résultats, qui n'est pas null.

Contrairement au premier exemple, où la source suivante n'est évaluée que lorsque le premier n'a pas de retour de quelque chose, cette deuxième solution peut regarder mieux au début, mais pourrait faire bien pire.

Voici où nous en venir à ma question et à qui je suggère quelque chose, j'espère que quelqu'un a déjà mis en place la base de la ou des que quelqu'un pourrait proposer un même smarted solution.

En anglais: quelqu'un A déjà mis en place une telle defferedFirstNonNull (voir ci-dessous) ou quelque chose de similaire? Est-il facile de la plaine-Java solution à réaliser avec les nouvelles Flux cadre? Pouvez-vous proposer une autre solution élégante qui permet d'obtenir le même résultat?

Règles: Java 8 est autorisé ainsi que active entretenus et bien connu des bibliothèques tierces comme Google Goyave ou Apache Commons Lang avec la Licence Apache ou similaires (Pas de GPL!).

La solution proposée:

public SomeObject findSomeObject(Arguments args) {
    return Helper.deferredFirstNonNull(
        Arrays.asList(
            args -> queryFirstSource(args)
            , args -> querySourceSource(args)
            , args -> queryThirdSource(args)
        )
        , x -> x != null
     )
 }

Donc la méthode defferedFirstNonNull d'évaluer chaque expression lambda après l'autre, et dès que le prédicat (x -> x != null) est vrai (c'est à dire, nous avons trouvé une correspondance), la méthode retourne le résultat immédiatement, et ne serait pas de requête de tout autre source.

PS: je sais que les expressions args -> queryXXXXSource(args) pourrait être réduit à queryXXXXSource. Mais cela rendrait la solution proposée plus difficile à lire parce qu'il n'est pas évident, à première vue, qu'est-ce que va se passer.

OriginalL'auteur cimnine | 2014-09-30