J'ai une méthode qui vérifie les valeurs nulles. Existe-t-il un moyen de réduire le nombre de lignes dans la méthode? Actuellement, le code semble "sale":
private int similarityCount (String one, String two) {
if (one == null && two == null) {
return 1;
} else if (one == null && two != null) {
return 2;
} else if (one != null && two == null) {
return 3;
} else {
if(isMatch(one, two))
return 4;
return 5;
}
}
private int similarityCount (String one, String two) {
if (one == null && two == null) {
return 1;
}
if (one == null) {
return 2;
}
if (two == null) {
return 3;
}
if (isMatch(one, two)) {
return 4;
}
return 5;
}
Je préfère les conditions imbriquées dans de tels cas:
private int similarityCount (String one, String two) {
if (one==null) {
if (two==null) {
return 1;
} else {
return 2;
}
} else {
if (two==null) {
return 3;
} else {
return isMatch(one, two) ? 4 : 5;
}
}
}
Bien sûr, vous pouvez obtenir une version plus courte en utilisant des opérateurs conditionnels plus ternaires.
private int similarityCount (String one, String two) {
if (one==null) {
return (two==null) ? 1 : 2;
} else {
return (two==null) ? 3 : isMatch(one, two) ? 4 : 5;
}
}
Ou même (maintenant cela devient moins lisible):
private int similarityCount (String one, String two) {
return (one==null) ? ((two==null) ? 1 : 2) : ((two==null) ? 3 : isMatch(one, two) ? 4 : 5);
}
Étant donné que le but réel de la fonction semble être de gérer les objets nonnull
en les faisant correspondre, je gérerais toutes les vérifications null
dans une instruction de garde au début.
Ensuite, une fois que vous avez établi qu'aucun argument n'est null
, vous pouvez gérer la logique réelle:
private int similarityCount(String a, String b) {
if (a == null || b == null) {
return a == b ? 1 : a == null ? 2 : 3;
}
return isMatch(a, b) ? 4 : 5;
}
C'est à la fois plus concis et plus lisible que les autres options.
Cela dit, les fonctions réelles ne renverraient généralement pas de tels codes numériques. À moins que votre méthode ne soit simplifiée pour illustrer le problème, je vous exhorte fortement à reconsidérer la logique et à la place écrire quelque chose qui ressemble à ce qui suit:
private boolean similarityCount(String a, String b) {
if (a == null || b == null) {
throw new NullPointerException();
}
return isMatch(a, b);
}
Ou:
private boolean similarityCount(String a, String b) {
if (a == null) {
throw new IllegalArgumentException("a");
}
if (b == null) {
throw new IllegalArgumentException("b");
}
return isMatch(a, b);
}
Ces approches seraient plus conventionnelles. D'un autre côté, ils peuvent déclencher une exception. Nous pouvons éviter cela en renvoyant un Java.util.Optional<Boolean>
in Java 8:
private Optional<Boolean> similarityCount(String a, String b) {
if (a == null || b == null) {
return Optional.empty();
}
return Optional.of(isMatch(a, b));
}
À première vue, cela peut sembler ne pas être mieux que de renvoyer null
mais les options sont en fait bien supérieures .
Le code me semble assez clair. Vous pouvez le raccourcir avec les opérateurs d'imbrication et ternaires:
if(one==null) {
return two==null ? 1 : 2;
}
if(two==null) {
return 3;
}
return isMatch(one,two) ? 4 : 5;
Cela peut être fait sur une seule ligne en utilisant Java opérateur conditionnel:
return (one==null?(two==null?1:2):(two==null?3:(isMatch(one,two)?4:5)));
Vous pouvez créer une pseudo-table de recherche. Certaines personnes froncent les sourcils sur les opérateurs ternaires imbriqués et cela dépend fortement des espaces blancs pour la lisibilité, mais ce peut être une approche très lisible du retour conditionnel:
private int similarityCount (String one, String two) {
return (one == null && two == null) ? 1
: (one == null && two != null) ? 2
: (one != null && two == null) ? 3
: isMatch(one, two) ? 4
: 5;
}
J'aime les expressions.
private static int similarityCount (String one, String two) {
return one == null ?
similarityCountByTwoOnly(two) :
two == null ? 3 : (isMatch(one, two) ? 4 : 5)
;
}
private static int similarityCountByTwoOnly(String two) {
return two == null ? 1 : 2;
}
En passant, je contesterais probablement pourquoi vous faites cela. Je suppose que vous feriez une sorte de vérification sur l'entier renvoyé après l'avoir évalué et branchez votre logique sur cette base. Si tel est le cas, vous venez de faire une vérification moins lisible de null où l'utilisateur de votre méthode doit comprendre le contrat implicite dans la valeur de l'entier.
En outre, voici une solution simple lorsque vous devez vérifier si les chaînes sont égales lorsqu'elles peuvent être nulles:
boolean same = one == null ? two == null : one.equals(two);
Cela devrait être légèrement plus rapide si aucun n'est nul, car il n'exécute qu'une seule instruction "if" dans ce cas.
private int similarityCount (String one, String two) {
if (one == null || two == null) { // Something is null
if (two != null) { // Only one is null
return 2;
}
if (one != null) { // Only two is null
return 3;
}
return 1; // Both must be null
}
return isMatch(one, two) ? 4 : 5;
}
LOL ... La programmation n'est pas un concours de beauté. Vos codes
if (one == null && two == null) {
return 1;
} else if (one == null && two != null) {
return 2;
} else if (one != null && two == null) {
return 3;
} else {
if(isMatch(one, two))
return 4;
return 5;
}
ne sont PAS sales, mais assez beaux pour les profanes et les experts aussi. Que pensez-vous du codage suivant
return one == null && two == null ? 1:
one == null && two != null ? 2:
one != null && two == null ? 3:
isMatch(one, two) ? 4 : 5;
Super, non? Eh bien, pour les profanes, c'est "vaudou", pour les "experts" ... il ne faut pas discuter de "goût", de "politique" et de "religion". MAIS du point de vue de la performance, il en est ainsi:
POURQUOI? Il suffit de le compiler "javac -g: aucun Test5 * .Java" et de comparer les bytecodes générés. Je l'ai fait et voici les résultats:
Première version:
public class Test5 {
public static void main(String[] args) {
String one = "1";
String two = "2";
System.out.println(check(one, two));
}
private static int check(String one, String two) {
if (one == null && two == null) {
return 1;
} else if (one == null && two != null) {
return 2;
} else if (one != null && two == null) {
return 3;
} else {
if(isMatch(one, two))
return 4;
return 5;
}
}
public static boolean isMatch(String a, String b) {
return true;
}
}
produit 570 octets
Deuxième version:
public class Test5a {
public static void main(String[] args) {
String one = "1";
String two = "2";
System.out.println(check(one, two));
}
private static int check(String one, String two) {
return one == null && two == null ? 1:
one == null && two != null ? 2:
one != null && two == null ? 3:
isMatch(one, two) ? 4 : 5;
}
public static boolean isMatch(String a, String b) {
return true;
}
}
produit 581 octets
Il est clair que 11 octets doivent être traités et cela prend du temps ... plus une application a de codes "excessifs", plus ses performances seront mauvaises.
Se débarrasser des instructions IF est très amusant. L'utilisation d'une carte est une façon de procéder. Cela ne correspond pas exactement à ce cas en raison de l'appel à isMatch, mais je le propose comme alternative qui coupe le corps de la méthode similarityCount sur une seule ligne avec un IF
Le code suivant a deux IF. Si GetOrDefault n'a pas évalué le deuxième argument, il pourrait être réduit à un. Malheureusement, la vérification nulle dans isMatch est nécessaire.
Vous pourriez aller beaucoup plus loin avec cela si vous le vouliez. Par exemple, isMatch pourrait renvoyer 4 ou 5 plutôt qu'un booléen qui vous aiderait à simplifier davantage.
import com.google.common.collect.ImmutableMap;
import org.Apache.commons.lang3.builder.EqualsBuilder;
import org.Apache.commons.lang3.builder.HashCodeBuilder;
import Java.util.Map;
public class SimilarityCount {
private Map<SimilarityCountKey, Integer> rtn = ImmutableMap.of(new SimilarityCountKey(null, null), 1, new SimilarityCountKey(null, ""), 2, new SimilarityCountKey("", null), 3);
public int similarityCount(String one, String two) {
return rtn.getOrDefault(new SimilarityCountKey(one, two), isMatch(one, two) ? 4 : 5);
}
private boolean isMatch(String one, String two) {
if (one == null || two == null) {
return false;
}
return one.equals(two);
}
private class SimilarityCountKey {
private final boolean one;
private final boolean two;
public SimilarityCountKey(String one, String two) {
this.one = one == null;
this.two = two == null;
}
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
}
}
Dans le cas où quelqu'un d'autre aurait envie d'une fissure à une autre solution, voici quelques tests pour vous aider à démarrer
import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.CoreMatchers.is;
public class SimilarityCountTest {
@Test
public void one(){
Assert.assertThat(new SimilarityCount().similarityCount(null,null), is(1));
}
@Test
public void two(){
Assert.assertThat(new SimilarityCount().similarityCount(null,""), is(2));
}
@Test
public void three(){
Assert.assertThat(new SimilarityCount().similarityCount("",null), is(3));
}
@Test
public void four(){
Assert.assertThat(new SimilarityCount().similarityCount("",""), is(4));
}
@Test
public void five(){
Assert.assertThat(new SimilarityCount().similarityCount("a","b"), is(5));
}
}