web-dev-qa-db-fra.com

Récupérer une valeur sans avoir à annuler l'archivage Java

Plusieurs fois, je me retrouve à vérifier null lors de la récupération d'une valeur dans une hiérarchie de données pour éviter les NullPointerExceptions, que je trouve sujettes à des erreurs et qui nécessitent beaucoup de passe-partout.

J'ai écrit une routine très simple qui me permet d'ignorer la vérification nulle lors de la récupération d'un objet ...

public final class NoNPE {

    public static <T> T get(NoNPEInterface<T> in) {
        try {
            return in.get();
        } catch (NullPointerException e) {
            return null;
        }
    }

    public interface NoNPEInterface<T> {
        T get();
    }
}

Je l'utilise un peu comme ça ...

Room room = NoNPE.get(() -> country.getTown().getHouses().get(0).getLivingRoom());

Ce qui précède m'a permis d'obtenir un objet Room ou un null, sans avoir à vérifier tous les niveaux parent.

Que pensez-vous de ce qui précède? Suis-je en train de créer un motif problématique? Y a-t-il une meilleure façon de procéder à votre avis?

15
Eurig Jones

Votre solution est très intelligente. Le problème que je vois est le fait que vous ne savez pas pourquoi vous avez obtenu un null? Est-ce parce que la maison n'avait pas de pièces? Était-ce parce que la ville n'avait pas de maisons? Est-ce parce que le pays n'a pas de villes? Était-ce parce qu'il y avait un null dans la position 0 de la collection à cause d'une erreur même quand il y a des maisons dans les positions 1 et plus?

Si vous faites un usage extensif de la classe NonPE, vous aurez de sérieux problèmes de débogage. Je pense qu'il vaut mieux savoir où exactement la chaîne est rompue que d'obtenir silencieusement un null qui pourrait cacher une erreur plus profonde.

Cela viole également la loi de Déméter : country.getTown().getHouses().get(0).getLivingRoom(). Plus souvent qu'autrement, la violation d'un bon principe vous oblige à mettre en œuvre des solutions peu orthodoxes pour résoudre le problème causé par la violation de ce principe.

Ma recommandation est que vous l'utilisiez avec prudence et essayez de résoudre le défaut de conception qui vous oblige à encourir dans le train wreck antipattern (donc vous n'avez pas à utiliser NonPE partout) . Sinon, vous pourriez avoir des bogues difficiles à détecter.

13
Tulains Córdova

L'idée est bonne, vraiment bonne en fait. Étant donné que Java 8 les types Optional existent, une explication détaillée peut être trouvée à type Java facultatif . Un exemple avec ce que vous avez publié est

Optional.ofNullable(country)
    .map(Country::getTown)
    .map(Town::Houses);

Et plus loin.

10
J. Pichardo

Je peux ressentir votre douleur, mais la solution proposée est une mauvaise idée.

  • Si l'un des getters lance un NPE pour une autre raison, vous l'ignorerez.
  • Il y a un risque que cette lambda intérieure devienne un code horrible. Par exemple, s'il y a une nouvelle exigence pour retourner une constante spéciale quand il n'y a pas de maisons dans la ville, un programmeur paresseux peut étendre la lamda, laissant tout enveloppé dans NoNPE.get.
  • Comme déjà mentionné, Optional.map est ce que vous recherchez.
  • La pénalité de la création d'une nouvelle instance de NullPointerException est souvent importante. Cela prend plusieurs microsecondes, d'autant plus que votre pile d'appels s'agrandit. Il est difficile de prédire où votre utilitaire finira par être utilisé.

En remarque, NoNPEInterface est un doublon de Java.util.function.Supplier.

Dans certains cas, vous pourriez envisager d'utiliser une expression d'évaluation utils qui sont présents dans de nombreux cadres (par exemple: EL, SpEL):

evaluateProperty(country, "town.houses[0].livingRoom")
0
Mateusz Stefek

Votre méthode fonctionne assez bien pour son objectif, bien que renvoyer nulls lorsque vous obtenez un NullPointerException semble être une mauvaise conception.

Essayez d'éviter les nulls lorsque vous le pouvez et ne les passez que lorsqu'ils représentent quelque chose ou ont une signification spéciale et ne les renvoyez que lorsqu'ils représentent/signifient quelque chose - sinon vous devriez lancer un NullPointerException. Cela évite les bugs et la confusion. Si un Object ne doit pas être null, un NullPointer doit être jeté. Si un objet peut être null, alors rien ne se passera mal lorsqu'il est passé. Sinon, votre méthode ci-dessus fonctionne.

0
Luke Melaia