173 votes

Vérifier deux arguments en Java, soit les deux ne sont pas nuls, soit les deux sont nuls, de manière élégante.

J'ai utilisé spring boot pour développer un projet shell utilisé pour envoyer des emails, par exemple.

sendmail -from foo@bar.com -password  foobar -subject "hello world"  -to aaa@bbb.com

Si le from y password sont manquants, j'utilise un expéditeur et un mot de passe par défaut, par ex. noreply@bar.com y 123456 .

Ainsi, si l'utilisateur passe le test from ils doivent également passer l'argument password et vice versa. En d'autres termes, soit les deux sont non nuls, soit les deux sont nuls.

Comment puis-je vérifier cela de manière élégante ?

Maintenant, mon chemin est

if ((from != null && password == null) || (from == null && password != null)) {
    throw new RuntimeException("from and password either both exist or both not exist");
}

14 votes

Par ailleurs, notez que l'utilisation des espaces blancs rend le code beaucoup plus facile à lire. Le simple fait d'ajouter des espaces entre les opérateurs dans votre code actuel améliorerait considérablement la lisibilité.

8 votes

Veuillez définir le terme "élégance".

0 votes

Vous devez disposer d'un ensemble distinct d'arguments pour les informations d'authentification SMTP et pour l'adresse électronique de l'expéditeur de l'enveloppe. L'adresse From L'adresse électronique n'est pas toujours le nom d'authentification SMTP.

346voto

coolguy Points 1982

Il existe un moyen d'utiliser le ^ ( XOR ) :

if (from == null ^ password == null) {
    // Use RuntimeException if you need to
    throw new IllegalArgumentException("message");
}

El if La condition sera vraie si une seule variable est nulle.

Mais je pense qu'en général, il est préférable d'utiliser deux if avec des messages d'exception différents. Vous ne pouvez pas définir ce qui a mal tourné en utilisant une seule condition.

if ((from == null) && (password != null)) {
    throw new IllegalArgumentException("If from is null, password must be null");
}
if ((from != null) && (password == null)) {
    throw new IllegalArgumentException("If from is not null, password must not be null");
}

Il est plus lisible et beaucoup plus facile à comprendre, et il suffit d'un peu plus de frappe.

155 votes

Y a-t-il une raison pour laquelle le xor sur deux bools est préférable à != sur deux bools ?

1 votes

Wow, je n'avais pas réalisé que XOR sur un booléen est la même chose que != . Hallucinant. Et c'est un nombre très élevé de upvotes dans le commentaire. Et, pour ajouter de la qualité à ce commentaire, oui, je pense aussi que donner un message d'erreur différent pour différents cas d'erreur est mieux, puisque l'utilisateur saura mieux comment corriger l'erreur.

1 votes

Pour 2 éléments, c'est bien. Comment faire avec >2 éléments ?

296voto

Jon Skeet Points 692016

Eh bien, il semble que vous essayez de vérifier si la condition de "nullité" des deux est la même ou non. Vous pourriez utiliser :

if ((from == null) != (password == null))
{
    ...
}

Ou rendez-le plus explicite avec des variables d'aide :

boolean gotFrom = from != null;
boolean gotPassword = password != null;
if (gotFrom != gotPassword)
{
    ...
}

0 votes

J'aime bien cette méthode parce que tout sera optimisé par la JVM de toute façon et que cela ne perturbera pas les jeunes développeurs. Bien sûr, cela suppose qu'il y ait aussi un bon commentaire.

0 votes

J'ai aimé celui-là parce qu'il fonctionne aussi pour d'autres langues.

18 votes

Tu es l'un de mes SO heros @Kaz, mais rien ne dit "soit ceci, soit cela, mais pas les deux en même temps" comme ^ fait. :-)

222voto

Stig Hemmer Points 2175

Personnellement, je préfère "lisible" à "élégant".

if (from != null && password == null) {
    throw new RuntimeException("-from given without -password");
}
if (from == null && password != null) {
    throw new RuntimeException("-password given without -from");
}

52 votes

+1 pour les meilleurs messages. Ce es important, personne n'aime la paperasserie "quelque chose a mal tourné" -des messages d'erreur, donc personne ne devrait cause de tels messages. Cependant, dans la pratique, il faut préférer une exception plus spécifique (notamment, un IllegalArgumentException au lieu d'un simple RuntimeException )

1 votes

@PauloEbermann c'est peut-être "plus joli", mais ce n'est pas correct. Il faut soit spécifier à la fois le nom d'utilisateur et le mot de passe, soit n'en spécifier aucun et une valeur par défaut sera utilisée. Cela ne dit pas comment le problème doit être résolu, mais la solution fournie le fait... en quelque sorte.

0 votes

@matt les messages ici donnent plus d'informations que le message dans la question - à savoir, lequel des deux cas s'est produit. (Je suppose qu'ils pourraient être étendus un peu pour rendre les choses encore plus claires).

16voto

Traubenfuchs Points 181

Mettez cette fonctionnalité dans une méthode à 2 arguments avec la signature :

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

Cela permet de gagner de la place dans la méthode qui vous intéresse et de la rendre plus lisible. Il n'y a rien de mal à avoir des noms de méthodes légèrement verbeux et il n'y a rien de mal à avoir des méthodes très courtes.

14 votes

Pas de gain de place par rapport à ((from == null) != (password == null)) qui est aussi très simple à comprendre. Il y a un problème avec les méthodes inutiles.

3 votes

Il y a une ligne pour l'instruction if, une deuxième ligne pour l'instruction throw et une troisième ligne pour l'accolade fermante : Toutes remplacées par une seule ligne. Une ligne de plus économisée si vous donnez aux accolades fermantes une nouvelle ligne !

10 votes

Lorsque vous lisez le code, vous devez comprendre le nom d'une méthode plutôt que de jongler avec les conditions.

11voto

Didier L Points 1408

Une solution Java 8 serait d'utiliser Objects.isNull(Object) en supposant une importation statique :

if (isNull(from) != isNull(password)) {
    throw ...;
}

Pour Java < 8 (ou si vous n'aimez pas utiliser la fonction Objects.isNull() ), vous pouvez facilement écrire votre propre isNull() méthode.

6 votes

Je n'aime pas ça. from == null != password == null garde tout sur la même frame de la pile, mais en utilisant Objects.isNull(Object) pousse et fait sauter inutilement deux cadres. Objects.isNull(Object) est là parce que "Cette méthode existe pour être utilisée comme prédicat" (c'est-à-dire dans les flux).

6 votes

Une méthode simple comme celle-ci sera normalement rapidement intégrée par le JIT, de sorte que l'impact sur les performances est très probablement négligeable. Nous pourrions en effet débattre de l'utilisation de Objects.isNull() - vous pouvez écrire le vôtre si vous préférez - mais en ce qui concerne la lisibilité, je pense que l'utilisation de isNull() est préférable. De plus, vous avez besoin de parenthèses supplémentaires pour rendre le système de la simple expression compiler : from == null != (password == null) .

2 votes

Je suis d'accord sur le JIT'ing (et l'ordre des opérations ... j'étais paresseux). Quand même, (val == null) est si très bien l'installation fournie dans le but de comparer avec null, j'ai du mal à me passer de deux grosses invocations de méthodes qui me regardent en face, même si la méthode est tout à fait fonctionnelle, in-lineable et bien nommée. Mais ce n'est que moi. J'ai décidé récemment que je suis un peu bizarre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X