1
votes

Raccourci pour la vérification de null avant l'invocation de la méthode en Java

Lors de l'écriture de code java simple ou complexe, il semble assez courant d'écrire du code comme celui-ci:

public class NullHelper
{
    private static <T> boolean check(T object)
    {
        return object == null;
    }

    public static <T> void nullOrExecute(T object, Consumer<T> func)
    {
        if (!check(object))
            func.accept(object);
    }

    public static <T, R> R nullOrCompute(T object, Function<T, R> func)
    {
        return check(object)
            ? null
            : func.apply(object);
    }

    public static <T, P0, R> R nullOrCompute(T object, BiFunction<T, P0, R> func, P0 param0)
    {
        return check(object)
            ? null
            : func.apply(object, param0);
    }

    // more params
}

Ou plus spécifique:

Foo someValue = nullOrCompute(valueObject, valueObject::getSomeValue);

Ce qui signifierait que someValue reste nul lorsque l'objet de valeur est nul. Maintenant, comme je rencontre assez souvent ce type de code (et cela augmente la complexité cognitive / cyclique), je me suis demandé s'il y avait un moyen de simplifier ces déclarations de quelque manière que ce soit. J'ai cherché une solution qui ressemble à:

Foo someValue = null;
if (valueObject != null) {
    someValue = valueObject.getSomeValue();
}

Après quelques recherches, il semble que Java ne propose pas une fonctionnalité similaire. Donc, comme test, j'ai écrit le raccourci moi-même, qui ressemble à ceci:

if (obj != null) {
    obj.someMethod();
}

Notez que vous devrez écrire votre propre " NFunction code > "Interfaces si vous souhaitez inclure des versions avec plus de paramètres car Java ne fournit pas de TriFunction ou plus.

Ma question est: p >

Ce code est-il un bon moyen de simplifier une grande base de code existante? Et si non, est-ce parce qu'il existe une fonctionnalité Java plus pratique que je ne connais pas, ou est-ce parce que j'ai besoin d'améliorer ma version personnalisée (et comment)?

Veuillez garder à l'esprit que je je ne parle pas de la solution la plus pratique en général , mais d'une solution qui peut être appliquée à une grande base de code existante.

Merci d'avance.

p>


4 commentaires

"il semble assez courant d'écrire du code" avec NULL. La cause première est que vous utilisez NULL. Ceci est une pratique terrible dans un objet paradigme orienté et doit être évité à tout prix.


@Boris Vous suggérez donc de refactoriser toute la grande base de code pour vous débarrasser des nulls? Bien sûr, les valeurs nulles ne sont pas géniales, mais de toutes les terribles pratiques orientées objet, c'est loin d'être la pire. Les NullPointerExceptions font partie des problèmes les plus faciles à trouver et à résoudre dans un code typique.


@Malt c'est vrai, je ne cherche pas le paradigme parfait, mais une solution simple et évolutive


@RaphaelTarita J'ai mis mes 2 cents dans ... C'est impopulaire, juste les idées sur lesquelles réfléchir. Regarde.


3 Réponses :


2
votes

Pensez à utiliser Facultatif au lieu de null pour représenter quelque chose qui ne peut légitimement pas être présent.

Foo someValue = Optional.ofNullable(valueObject).map(Bar::getSomeValue).orElse(null);

Facultatif a un poignée de méthodes ( map , ifPresent , orElse , et orElseGet ) pour effectuer différentes actions selon qu'il a une valeur.

Si vous souhaitez limiter vos modifications à des portées plus petites (une méthode, voire une ligne), vous pouvez toujours accomplir ce que vous recherchez sans avoir à écrire de méthodes utilitaires personnalisées.

Optional<Bar> valueObject = getValueObject();
Optional<Foo> someValue = valueObject.map(o -> o.getSomeValue());

Mais je pense que ce que vous trouverez, c'est que si vous commencez de cette façon, le paradigme Optional va naturellement s'étendre dans le temps et la qualité du code de votre projet dans son ensemble.


9 commentaires

l'OP a souligné qu'il s'agit d'une grande base de code existante, donc réécrire le type de retour de chaque méthode de T à Facultatif serait fastidieux


@Tobilko c'est vrai. Je connaissais Optional <> (et les avantages d'utiliser un langage non nul comme Rust), mais à mon avis, c'est probablement beaucoup trop de refactorisation pour la base de code massive, principalement parce que si vous voulez le faire correctement, les problèmes se répandre donc vous devez mettre en œuvre la technique partout


Vous pouvez toujours utiliser Optionnel sans modifier les signatures de méthode. En utilisant la méthode ofNullable () , vous pouvez toujours transformer la plupart de votre logique de vérification de null en one-liners et utiliser un paradigme plus largement accepté que l'écriture de vos propres utilitaires.


Je suis pro en option, +1. C'est clair, les changements n'oublieront pas par hasard une gestion nulle, car l'API changera avec le temps. Les outils d'analyse de code mettront en garde contre les nullables. C'est un refactoring propre que vous ne pourrez pas réaliser avec des utils nuls.


@RaphaelTarita: J'ai mis à jour ma réponse pour montrer que vous pouvez toujours limiter vos modifications à une seule ligne si c'est ce que vous voulez. Vous n'êtes pas obligé de tout refactoriser. Mais ce que vous décrivez comme «les problèmes se propagent», je le vois personnellement comme «le bon schéma se répand pour rendre les vrais problèmes plus visibles».


@RaphaelTarita il est difficile d'appeler "encapsuler une valeur dans une autre classe juste pour utiliser ses méthodes" une technique appropriée ...


@StriplingWarrior oui, je pourrais vraiment l'utiliser dans la version restreinte. Et oui, il serait probablement préférable de refactoriser l'ensemble de la base de code en Optionals. Mais avec la taille de la base de code dont je parle, cela pourrait littéralement prendre des années à refactoriser. J'essaie de trouver une solution que je peux utiliser dans un seul emplacement dans la base de code, afin que l'équipe puisse examiner les avantages et les inconvénients du raccourci. Ensuite, nous pouvons parler de son application dans d'autres emplacements de code


@RaphaelTarita: Je comprends tout à fait. Je serais la dernière personne à recommander la refactorisation de l'ensemble de votre base de code pour arrêter d'utiliser les valeurs nulles en même temps. C'est pourquoi je pense que vous devriez commencer petit, en changeant les morceaux de code que vous prévoyez déjà de changer. La diffusion du modèle facultatif se produira naturellement et organiquement au fil du temps.


@StriplingWarrior c'est essentiellement le plan. Merci de m'avoir aidé!



3
votes

Votre code:

Optional.ofNullable(foo).isPresent();
Optional.ofNullable(foo).ifPresent(consumer);
Optional.ofNullable(foo).map(mapper)

Code équivalent utilisant des options:

check(foo)
nullOrExecute(foo, consumer)
nullOrCompute(foo, mapper)
nullOrCompute(foo, func, param)


3 commentaires

Cela fonctionne-t-il également pour les méthodes avec plusieurs paramètres? Au fait, cela semble être la solution que je recherche, merci


@RaphaelTarita: Oui, vous pouvez utiliser un lambda qui se ferme sur d'autres valeurs pour passer plusieurs paramètres dans les méthodes que vous essayez d'appeler. Facultatif.ofNullable (foo) .map (f -> f.getSomething (oneValue, anotherValue)) . C'est ce que tu veux dire?


Oui, merci beaucoup. Il semble que j'ai trouvé la solution que j'ai recherchée



1
votes

Facultatif est plus rapide et permet le chaînage de champs non présents.

Entièrement avec des objets Nullable hérités:

Optional<Baz> someValue = valueObject.map(Bar::getSomeValue).map(Fuz::getSub);

someValue.ifPresent(v -> ... non-null v);

En partie: p>

Optional<Foo> someValue = valueObject.map(Bar::getSomeValue);

Porté vers des options:

Optional<Foo> someValue = Optional.ofNullable(valueObject).map(Bar::getSomeValue);

Avantages:

Foo someValue = Optional.ofNullable(valueObject).map(Bar::getSomeValue).orElse(null);

Code les vérificateurs de style peuvent maintenant détecter finement les nullables et les nonullables. On peut également annoter des non-nullables. On peut progressivement passer aux options, comme vous le souhaitiez pour la gestion étendue des null.


0 commentaires