web-dev-qa-db-fra.com

Est-il préférable d'utiliser assert ou IllegalArgumentException pour les paramètres de méthode requis?

En Java, qui est plus fortement recommandé, et pourquoi? Les deux types lèveront des exceptions, donc à cet égard, leur gestion est la même. assert est légèrement plus court, mais je ne sais pas combien cela compte.

public void doStuff(Object obj) {
    assert obj != null;
    ...
}

contre

public void doStuff(Object obj) {
    if (obj == null) {
        throw new IllegalArgumentException("object was null");
    }
    ...
}
100
Daenyth

ATTENTION!

Assertions sont supprimés au moment de l'exécution, sauf si vous spécifiez explicitement pour "activer les assertions" lors de la compilation de votre code. Les assertions Java ne doivent pas être utilisées sur le code de production et doivent être limitées aux méthodes privées (voir Exception vs assertion ), car les méthodes privées devraient être connues et utilisées uniquement par les développeurs. assert lancera également AssertionError qui étend Error pas Exception, et qui indique normalement que vous avez une erreur très anormale (comme "OutOfMemoryError" qui est difficile à récupérer, n'est-ce pas?) on ne s'attend pas à ce que vous puissiez traiter.

Supprimez le drapeau "enable assertions" et vérifiez avec un débogueur et vous verrez que vous ne marcherez pas sur l'appel de levée IllegalArgumentException ... puisque ce code n'a pas été compilé (encore une fois, quand "ea" est supprimé)

Il vaut mieux utiliser la deuxième construction pour les méthodes publiques/protégées, et si vous voulez quelque chose qui est fait dans une ligne de code, il y a au moins une façon que je connaisse. J'utilise personnellement la classe Spring FrameworkAssert qui a quelques méthodes pour vérifier les arguments et qui lève "IllegalArgumentException" en cas d'échec. Fondamentalement, ce que vous faites est:

Assert.notNull(obj, "object was null");

... qui exécutera en fait exactement le même code que vous avez écrit dans votre deuxième exemple. Il existe quelques autres méthodes utiles telles que hasText, hasLength.

Je n'aime pas écrire plus de code que nécessaire, donc je suis content quand je réduis le nombre de lignes écrites de 2 (2 lignes> 1 ligne) :-)

123
Jalayn

Vous devez utiliser une exception. L'utilisation d'une assertion serait une mauvaise utilisation de la fonctionnalité.

Les exceptions non vérifiées sont conçues pour détecter les erreurs de programmation des tilisateurs de votre bibliothèque, tandis que les assertions sont conçues pour détecter les erreurs dans la logique la vôtre. Ce sont des questions distinctes qui ne devraient pas être mélangées.

Par exemple, une assertion

assert myConnection.isConnected();

signifie "Je sais que chaque chemin de code menant à cette assertion garantit que myConnection est connecté; si le code ci-dessus n'a pas réussi à obtenir une connexion valide, il aurait dû lever une exception ou retourner avant d'atteindre ce point."

D'un autre côté, un chèque

if (!myConnection.isConnected()) {
    throw new IllegalArgumentException("connection is not established");
}

signifie que "Appeler ma bibliothèque sans établir de connexion est une erreur de programmation".

47
dasblinkenlight

Si vous écrivez une fonction qui n'autorise pas null comme valeur de paramètre valide, vous devez ajouter le @Nonnull annotation à la signature et utilisation Objects.requireNonNull pour vérifier si l'argument est null et lancer un NullPointerException s'il l'est. Le @Nonnull l'annotation est pour la documentation et fournira des avertissements utiles au moment de la compilation dans certains cas. Il n'empêche pas null d'être transmis au moment de l'exécution.

void doStuff(@Nonnull Object obj) {
    Objects.requireNonNull(obj, "obj must not be null");

    // do stuff...
}

Mise à jour: Le @Nonnull l'annotation ne fait pas partie de la bibliothèque standard Java. À la place, il existe de nombreuses normes concurrentes de bibliothèques tierces (voir Which @NotNull Java = annotation dois-je utiliser? ) .Cela ne veut pas dire que c'est une mauvaise idée de l'utiliser, juste que ce n'est pas standard.

11
cambunctious

Je préfère toujours lancer IllegalArgumentException plutôt que les assertions.

Les assertions sont principalement utilisées dans JUnit ou d'autres outils de test, pour vérifier/affirmer les résultats des tests. Cela peut donc donner une fausse impression aux autres développeurs que votre méthode est une méthode de test.

Il est également judicieux de lever IllegalArgumentException lorsque ne méthode a reçu un argument illégal ou inapproprié. Ceci est plus cohérent avec la convention de gestion des exceptions suivie par les développeurs Java.

2
rai.skumar

Je n'utilise pas beaucoup d'inserts, mais une approche courante avec Lombock @NonNull: https://projectlombok.org/features/NonNull

Implémentation de Lombok: importez lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

Version Java:

 import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
  }
}

Lombok est vraiment une jolie bibliothèque que j'utilise partout

1
kensai

IMO le second est légèrement meilleur car il apporte plus d'informations et pourrait être étendu (par exemple en étendant la classe d'exception) pour être encore plus informatif, il n'utilise pas non plus de comparaison négative qui est plus facile à comprendre.

1
0lukasz0