IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Java Discussion :

Astuce pour convertir ses assert( != null) en Validate.notNull()


Sujet :

Langage Java

  1. #1
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    605
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 605
    Points : 670
    Points
    670
    Par défaut Astuce pour convertir ses assert( != null) en Validate.notNull()
    Bonjour,

    Le mot clef assert est très utile en Java pour construire du code "blindé". Cependant, il a un défaut, même utilisé à bon escient (par exemple, pour valider le contenu d'une méthode privée ou dénoncer un fait de programmation non respecté), c'est qu'il peut, en levant son Error, mettre en instabilité l'application. C'est potentiellement le cas notamment, lorsqu'elle est déployée sur un serveur d'applications ou web, parce ce que ces derniers ne vont pas nécessairement pouvoir exécuter tous les gestionnaires qu'ils devraient à l'issue de cette erreur, comme ils l'auraient fait si c'était une Exception.

    Cela est normal car une Error provoque une demande de tout arrêter en urgence et immédiatement. Les conséquences sont donc parfois un peu trop lourdes. De fait, il peut y avoir des effets désagréables à la suite de la levée de cette Error.

    L'utilisation de la classe Validate (de l'API Commons Lang d'Apache) est un choix alternatif intéressant car cette cette classe permet de lever, entre autres, une IllegalArgumentException, qui convient souvent mieux. Et parce qu'elle n'est pas débrayable, elle assure de faire son contrôle tout le temps, a contrario d'assert qui ne fonctionne que si l'exécutant a placé -ea dans sa ligne de commande Java (ce qui n'est pas si fréquent, surtout lorsqu'il ne sait pas qu'il doit le faire !)... Or, un code de contrôle qui ne s'exécute pas, c'est évidemment un code de contrôle qui ne sert à rien.

    Pour exemple, j'avais une masse d'assert faits ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assert(toto != null) : "mon message";
    Sous Eclipse, cette recherche (en mode expression régulière) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    assert\((.+) != null\) : "(.+)";
    et cette chaîne de remplacement :
    m'ont permis de faire le remplacement rapidement.

    Bien sûr, j'ai dû ajouter une directive import dans mes sources.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    import static org.apache.commons.lang3.Validate.*;
    A mon sens, bien que les utilisateurs d'assert ne soient pas si nombreux, ce mot-clef sauve pourtant presque autant que les tests unitaires. En tout cas, il aide à donner confiance dans un code que l'on lit...

    Voilà ! Si vous avez d'autres solutions, n'hésitez pas à les partager.

    Grunt.

  2. #2
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,


    Sinon à partir de Java 7 on peut utiliser Objects.requireNotNull...


    a++

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Juste pour rappel, assert ne sert pas à valider les inputs extérieurs, sur lesquels on a aucun contrôle et qui peuvent être mauvais sans qu'on se soit trompé nulle part. Auquel cas il faut juste remonter la petite erreur "c'est n'importe quoi ce que vous avez tapé là," c'est normal.

    assert sert à vérifier les conditions internes, ce qu'on suppose être vrai parce que notre programme est censé s'être assuré que c'est vrai. Dans le cas où c'est faux c'est une grave erreur interne et il n'y a rien à tenter, tout est fini.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par grunt2000 Voir le message
    Sinon, bien que les utilisateurs d'assert ne soient pas si nombreux, ce mot-clef sauve pourtant presque autant que les tests unitaires. En tout cas, il aide à donner confiance dans un code que l'on lit.
    Comme dit thelvin, ce mot clé sert à vérifier ce qui ne peux pas être. Si le assert s'évalue à false, c'est effectivement une erreur grave.

    Pour ce qui est des gestionnaires qui attrapent Exception et pas Error, ce n'est le cas que si on code mal, suivant ce genre de pattern:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    try{
    } catch (Exception e){
    }
    En effet, on ne dois catcher que les Exceptions qu'on est capable de traiter, et pas y aller à l'aveugle.

    Le nettoyage doit se faire dans un pattern
    et, éventuellement, si un traitement générique des cas d'erreurs, par exemple un ThreadPool qui doit continuer à fonctionner même si une tâche a échoué, le pattern est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    try{
    } catch (Throwable t){
    }
    Les assert n'ont rien à voir avec les tests unitaires, et mettre un assert ne dispense pas de créer des tests unitaires.

    Enfin, n'oublions pas qu'un assert ne fait rien par défaut, les assertions sont désactivées par défaut sur la JVM !

  5. #5
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    605
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 605
    Points : 670
    Points
    670
    Par défaut
    Ah, il faut que je précise.
    Je suis absolument d'accord avec tous vos arguments !

    Mais,

    j'ai constaté que quand un assert saute, alors qu'il se trouve au sein d'un ear déployé dans un JBoss ou Glassfish, il est fréquent que ce serveur d'application qui n'est pas parfaitement blindé de tous les côté face aux Error, se mette à son tour à coincer. Par exemple : il ne sera plus capable de faire le hot deploy suivant, pour un motif ténébreux, s'il ne bloque pas parfois entièrement. Un assert qui saute en plein milieu d'un EJB qui était invoqué lui-même par un autre EJB, souvent rend le serveur d'application instable.
    Il est juste là mon problème.

    Citation Envoyé par thelvin Voir le message
    Juste pour rappel, assert ne sert pas à valider les inputs extérieurs, sur lesquels on a aucun contrôle et qui peuvent être mauvais sans qu'on se soit trompé nulle part. Auquel cas il faut juste remonter la petite erreur "c'est n'importe quoi ce que vous avez tapé là," c'est normal.

    assert sert à vérifier les conditions internes, ce qu'on suppose être vrai parce que notre programme est censé s'être assuré que c'est vrai. Dans le cas où c'est faux c'est une grave erreur interne et il n'y a rien à tenter, tout est fini.
    C'est tout à fait vrai.

    Citation Envoyé par tchize_ Voir le message
    Les assert n'ont rien à voir avec les tests unitaires, et mettre un assert ne dispense pas de créer des tests unitaires.
    Je n'ai jamais écrit que les asserts remplaçaient les tests unitaires...
    J'ai dit qu'ils étaient aussi utiles qu'eux.

    Je suis d'accord (cent fois d'accord) avec le problème de fond que pose un catch(Exception e) qui ne rime à rien puisqu'il ne s'attaque à rien de précis (on ne sait pas ce que l'on intercepte et donc, on sait peu quoi faire de l'incident mentionné). En revanche, écrire un catch(Throwable t) me semble très dommageable. J'ai connu pas mal de programmes qui ont fait un foin incroyable en prenant des OutOfMemoryError et ne s'arrêtant pourtant pas, et continuaient à faire des âneries alors qu'ils n'étaient plus en état d'agir. Et cela, du fait de ces catch(Throwable t) intempestifs.

    Selon moi :
    il est légitime qu'un throw d'une Error arrête le traitement. Et un catch(Throwable t) dans un programme visant à l'empêcher (ou se sentant capable de faire des choses intelligentes avant de le quitter) me paraît toujours dangereux.

    Mais si par ailleurs, je suis heureux que lorsqu'une une Error est levée les programmes s'interrompent brutalement (c'est ce que je veux parce que c'est ce qu'il faut : l'assert doit arrêter le programme), en revanche, j'ai remarqué que les serveurs d'applications l'encaissaient mal, et que si mon EJB arrêtait son action sous le joug d'une Error, il provoquait occasionnellement par effet de bord l'arrêt ou l'instabilité du serveur d'application sur lequel il tournait (parce que les gestionnaires d'exceptions de ce serveur d'applications ne l'encaissent pas bien), et c'est pour cette raison que j'ai pris l’initiative d'abandonner les asserts au profit du Validate.

    C'est ce que j'ai voulu dire dans mon message initial.

    EDIT : @AdiGuba : Merci pour Objects.requireNonNull. Je n'avais pas vu cette nouvelle méthode.

  6. #6
    Membre chevronné
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Points : 1 855
    Points
    1 855
    Par défaut
    moui ... et alors pourquoi ne pas créer une méthode générale qui fasse qqch dans ce style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public static boolean useExceptionsForAssert = Boolean.getBoolean("useExceptionsForAssert") ;
    public static void check(boolean test, String message) {
     if(! test) {
        if(useExceptionforAssert)
         throw new SomeRuntimeException(message);
        // ici déclencher soi-même l'Error
     }
     return true ;
    }
    et ensuite dans le code appelant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
      assert Checks.check(x>0, "x positif s.v.p dans méthode smurf!")
    on peut faire plus ou moins sophistiqué (ici c'est pour l'exemple)
    J'ai des principes: je peux toujours trouver une bonne raison pour les contredire .... mais j'ai des principes!
    (mon excellent bouquin sur Java : https://eska-publishing.com/fr/livre...822407076.html)

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Si c'est pour faire des choses pareilles (validation de paramètres de méthodes avec exceptions, un peu partout dans le code), autant utiliser des api dédiées à ça, comme le JSR-303

  8. #8
    Membre chevronné
    Avatar de professeur shadoko
    Homme Profil pro
    retraité nostalgique Java SE
    Inscrit en
    Juillet 2006
    Messages
    1 257
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 75
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : retraité nostalgique Java SE

    Informations forums :
    Inscription : Juillet 2006
    Messages : 1 257
    Points : 1 855
    Points
    1 855
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Si c'est pour faire des choses pareilles (validation de paramètres de méthodes avec exceptions, un peu partout dans le code), autant utiliser des api dédiées à ça, comme le JSR-303
    dans un contexte J2SE pas trop "Beané" j'aimerai bien avoir des controles de compile time sur des annotations de type Nullable, mais après je ne vois pas trop comment implanter des contraintes annotées qui soient bien bordées.
    Mais c'est un sujet intéressant sur lequel je suis preneur de pointeurs.
    J'ai des principes: je peux toujours trouver une bonne raison pour les contredire .... mais j'ai des principes!
    (mon excellent bouquin sur Java : https://eska-publishing.com/fr/livre...822407076.html)

Discussions similaires

  1. [MySQL] y a t il une astuce pour améliorer la gestion de ses requêtes dans un projet ?
    Par razily dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 24/02/2012, 16h54
  2. convertir 0 en null pour un type int
    Par tortuegenie dans le forum ASP.NET
    Réponses: 4
    Dernier message: 23/10/2008, 15h31
  3. Réponses: 6
    Dernier message: 14/08/2006, 10h50
  4. Logiciel pour voir ses image en mode console
    Par Senaku-seishin dans le forum Applications et environnements graphiques
    Réponses: 3
    Dernier message: 28/11/2004, 22h11
  5. Utiliser Alien pour convertir un deb en rpm
    Par aA189 dans le forum Applications et environnements graphiques
    Réponses: 4
    Dernier message: 10/10/2004, 15h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo