web-dev-qa-db-fra.com

Forme abrégée pour Java instruction If Else

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;
    }

}
28
userit1985
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;
}
61
Manh Le

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);
}
33
Eran

É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 .

25
Konrad Rudolph

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;
9
default locale

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)));
5
SachinSarawgi

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;
}
4
Dancrumb

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);
1
Erik Madsen

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;
}
0
user7507190

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:

  • la 1ère version est plus rapide
  • la 2ème version est plus maladroite (ou plus lente)

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.

0
Voodoo

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));
    }

}
0
Mark Chorley