Java If Else 语句的缩写形式

Short form for Java If Else statement

我有一个检查空值的方法。有没有办法减少方法中的行数?目前,代码看起来 "dirty":

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

}

代码对我来说看起来很清楚。您可以使用嵌套和三元运算符使其更短:

if(one==null) {
    return two==null ? 1 : 2;
}
if(two==null) {
    return 3;
} 
return isMatch(one,two) ? 4 : 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;
}

在这种情况下我更喜欢嵌套条件:

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

当然你可以通过使用更多的三元条件运算符来实现更短的版本。

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

甚至(现在可读性越来越差):

private int similarityCount (String one, String two) {  
    return (one==null) ? ((two==null) ? 1 : 2) : ((two==null) ? 3 : isMatch(one, two) ? 4 : 5);
}

可以使用 Java 条件运算符在一行中完成:

return (one==null?(two==null?1:2):(two==null?3:(isMatch(one,two)?4:5)));

由于该函数的实际目的似乎是通过匹配非null 对象来处理它们,所以我会在开头的 guard 语句中处理所有 null 检查。

然后,一旦你确定没有参数是 null,你就可以处理实际的逻辑:

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

这比其他选项更简洁、更易读。

也就是说,真正的函数通常不会return这样的数字代码。除非你的方法被简化来举例说明问题,否则我强烈建议你重新考虑逻辑,而不是写一些类似于以下内容的东西:

private boolean similarityCount(String a, String b) {
    if (a == null || b == null) {
        throw new NullPointerException();
    }

    return isMatch(a, b);
}

或:

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

这些方法会更传统。另一方面,它们可能会触发异常。我们可以通过 returning a 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));
}

乍一看,这似乎并不比 returning null 好,但 optionals are in fact far superior.

摆脱 IF 语句很有趣。使用地图是执行此操作的一种方法。它不完全适合这种情况,因为调用了 isMatch,但我提供它作为一种替代方法,它将 similarityCount 方法主体削减到一行,其中包含一个 IF

以下代码有两个 IF。如果 GetOrDefault 没有评估第二个参数,它可以减少为一个。不幸的是,它确实需要 isMatch 内部的空检查。

如果你愿意,你可以更进一步。例如,isMatch 可以 return 4 或 5 而不是布尔值,这将帮助您进一步简化。

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

如果其他人想破解另一种解决方案,这里有一些测试可以帮助您入门

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

}

我喜欢表情

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

顺便说一句,我可能会质疑你为什么这样做。我假设您在评估返回的整数并根据它分支您的逻辑后会对返回的整数进行某种检查。如果是这种情况,您只是对 null 进行了可读性较差的检查,您的方法的用户需要了解整数值中隐含的合同。

另外,这里有一个简单的解决方案,当您需要检查字符串是否相等时它们可能为 null:

boolean same = one == null ? two == null : one.equals(two);

可以创建一个pseudo-lookup-table。有些人不赞成嵌套的三元运算符,它高度依赖空格来提高可读性,但它可以成为一种非常可读的条件返回方法:

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

如果两者都不为空,这应该会稍微快一些,因为在这种情况下它只执行一个 'if' 语句。

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