web-dev-qa-db-fra.com

Quel est l'intérêt de la classe facultative de Guava

J'ai récemment lu à ce sujet et vu des gens utiliser cette classe, mais dans presque tous les cas, utiliser null aurait aussi bien fonctionné - si ce n'est plus intuitivement. Quelqu'un peut-il fournir un exemple concret où Optional permettrait d'atteindre quelque chose que null ne pourrait pas ou d'une manière beaucoup plus propre? La seule chose à laquelle je peux penser est de l'utiliser avec Maps qui n'acceptent pas les clés null, mais même cela pourrait être fait avec un côté "mapping" de la valeur null. Quelqu'un peut-il me fournir un argument plus convaincant? Merci.

87
RAY

Membre de l'équipe de goyave ici.

Le plus gros inconvénient de null est probablement qu'il n'est pas évident de savoir ce que cela devrait signifier dans un contexte donné: il n'a pas de nom illustratif. Il n'est pas toujours évident que null signifie "pas de valeur pour ce paramètre" - diable, comme valeur de retour, parfois cela signifie "erreur", ou même "succès" (!!), ou simplement "la bonne la réponse est rien ". Optional est souvent le concept que vous entendez réellement lorsque vous rendez une variable nullable, mais pas toujours. Dans le cas contraire, nous vous recommandons d'écrire votre propre classe, similaire à Optional mais avec un schéma de dénomination différent, pour préciser ce que vous voulez réellement dire.

Mais je dirais que le plus grand avantage de Optional n'est pas en termes de lisibilité: l'avantage est sa résistance à l'idiot. Cela vous oblige à penser activement au cas absent si vous voulez que votre programme compile, car vous devez déballer activement le Optional et traiter ce cas. Null, il est troublant facilement d'oublier simplement des choses, et bien que FindBugs aide, je ne pense pas qu'il résout le problème presque aussi bien. Cela est particulièrement pertinent lorsque vous renvoyez des valeurs qui peuvent ou non être "présentes". Vous (et d'autres) êtes beaucoup plus susceptibles d'oublier que other.method(a, b) pourrait retourner une valeur null que vous oublierez probablement que a pourrait être null lorsque vous implémentez other.method. Le retour de Optional empêche les appelants d'oublier ce cas, car ils doivent déballer l'objet eux-mêmes.

Pour ces raisons, nous vous recommandons d'utiliser Optional comme type de retour pour vos méthodes, mais pas nécessairement dans vos arguments de méthode.

(Ceci est totalement corrigé, soit dit en passant, de la discussion ici .)

154
Louis Wasserman

Il ressemble vraiment au modèle Maybe Monad de Haskell.

Vous devriez lire ce qui suit, Wikipedia Monad (programmation fonctionnelle) :

Et lisez De l'option à la monade avec la goyave sur Blog de Kerflyn, qui traite de l'option de la goyave utilisée comme une monade:


Edit: Avec Java8, il existe une option intégrée qui a des opérateurs monadiques comme flatMap. Ce sujet a été controversé mais a finalement été mis en œuvre.

Voir http://www.nurkiewicz.com/2013/08/optional-in-Java-8-cheat-sheet.html

public Optional<String> tryFindSimilar(String s)  //...

Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

L'opérateur flatMap est essentiel pour permettre les opérations monadiques et permet de chaîner facilement les appels qui renvoient tous des résultats facultatifs.

Pensez-y, si vous utilisiez l'opérateur map 5 fois, vous vous retrouvez avec un Optional<Optional<Optional<Optional<Optional<String>>>>>, tout en utilisant flatMap vous donnerait Optional<String>

Depuis Java8, je préfère ne pas utiliser Guava's Optional, qui est moins puissant.

9
Sebastien Lorber

Une bonne raison de l'utiliser est qu'elle rend vos null très significatifs. Au lieu de retourner un null qui pourrait signifier beaucoup de choses (comme une erreur ou un échec, ou vide, etc.), vous pouvez mettre un "nom" à votre null. Regardez cet exemple:

permet de définir un POJO de base:

class PersonDetails {

String person;
String comments;

public PersonDetails(String person, String comments) {
    this.person = person;
    this.comments = comments;
}

public String getPerson() {
    return person;
}


public String getComments() {
    return comments;
}

}

Utilisons maintenant ce POJO simple:

public Optional<PersonDetails> getPersonDetailstWithOptional () {

  PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,
  lets make the return value more meaningful*/


    if (details == null) {
      //return an absent here, caller can check for absent to signify details are not present
        return Optional.absent();
    } else {
      //else return the details wrapped in a guava 'optional'
        return Optional.of(details);   
    }
}

Permet maintenant d'éviter d'utiliser null et de faire nos vérifications avec Facultatif afin que sa signification

public void checkUsingOptional () {

    Optional<PersonDetails> details = getPersonDetailstWithOptional();

    /*below condition checks if persons details are present (notice we dont check if person details are null,
    we use something more meaningful. Guava optional forces this with the implementation)*/
    if (details.isPresent()) {

      PersonDetails details = details.get();

        // proceed with further processing
        logger.info(details);

    } else {
        // do nothing
        logger.info("object was null"); 
    }

    assertFalse(details.isPresent());
}

ainsi, à la fin, c'est un moyen de rendre les null significatifs et moins d'ambiguïté.

6
j2emanue

L'avantage le plus important d'Optional est qu'il ajoute plus de détails au contrat entre l'implémenteur et l'appelant d'une fonction. Pour cette raison, est à la fois utile pour les paramètres et le type de retour.

Si vous faites en sorte que la convention ait toujours Optional pour les objets null possibles, vous ajoutez plus de précisions à des cas comme:

  1. Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)

    Le contrat ici spécifie clairement qu'il y a une chance qu'un résultat ne soit pas retourné mais montre également qu'il fonctionnera avec from et to comme absents.

  2. Optional<Integer> maxPrime(Optional<Integer> from, Integer to)

    Le contrat spécifie que le from est facultatif, donc une valeur absent peut avoir une signification spéciale comme commencer à partir de 2. Je peux m'attendre à ce qu'une valeur nulle pour le paramètre to lève une exception.

Donc, la bonne partie de l'utilisation d'Optional est que le contrat est devenu à la fois descriptif (similaire avec l'annotation @NotNull) Mais aussi formel puisque vous devez écrire le code .get() pour faire face à Optional.

4
raisercostin