更清洁的IF声明

时间:2014-01-06 14:39:39

标签: java if-statement

在Java中,当你有很多术语时,以下陈述看起来非常混乱:

if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
    //Do something

是否有更简洁的方法来执行相同的操作,我希望我的代码尽可能可读。

注意:x,y和z只是任何长度的任何字符串的占位符。这里有20个可变长度的字符串术语,如果条件各自一起进行OR运算

由于

17 个答案:

答案 0 :(得分:46)

你觉得什么看起来“不干净”?

如果你有一堆复杂的布尔逻辑,你可以将它的不同部分分成单独的布尔变量,并在if语句中引用它们。

或者您可以创建一个带有'a'变量并返回布尔值的函数。你只是将你的逻辑隐藏在方法中,但它会清理你的if语句。

答案 1 :(得分:45)

Set<String> stuff = new HashSet<String>();
stuff.add("x");
stuff.add("y");
stuff.add("z");
if(stuff.contains(a)) {
    //stuff
}

如果这是一个紧凑的循环,你可以使用静态集。

static Set<String> stuff;
static {
    stuff = new HashSet<String>();
    stuff.add("x");
    stuff.add("y");
    stuff.add("z");
}

//Somewhere else in the cosmos

if(stuff.contains(a)) {
    //stuff
}

如果你想要更加确定在你不看的时候没有任何改变。

Set<String> test = Collections.unmodifiableSet(new HashSet<String>() {
        {
            add("x");
            add("y");
            add("z");
        }
    });

如果您只想在少数硬编码条件中获得一些逻辑,那么切换或if语句中的一个使用换行解决方案可能会更好。但是如果你有很多条件,那么将配置与逻辑分离可能会很好。

答案 2 :(得分:26)

或者,如果您使用的是Java 7+,则可以在switch / case中使用字符串。例如(我从Oracle文档中提取并修改了它)

         switch (str) {

             case "x":
             case "y":
             case "z":
                 //do action
                 break;
             default:
              throw new IllegalArgumentException("argument not matched "+str);

    }

以下是link

答案 3 :(得分:24)

使用正则表达式

If (a.matches("[xyz]")){
    // matches either "x", "y", or "z"

或者,对于更长的字符串,

If (a.matches("one|two|three")){
    // matches either "one", "two" or "three"

但这在计算上很昂贵,但可能并不比实例化set等差。但这是我能想到的最清晰的方式。

最后,最好的方法可能是保持原样,并调整格式:

if (a.equals("x") || 
    a.equals("y") || 
    a.equals("z")
    ){

然后,代码的作用绝对没有歧义,因此您的代码将更容易维护。如果性能很重要,您甚至可以将最可能出现的事件放在列表的顶部。

答案 4 :(得分:21)

达到语义

在语义层面上,您要检查的是设置成员资格。但是,您在非常低的级别上实现它,基本上内联实现检查所需的所有代码。除了强迫读者推断出这种大规模条件背后的意图之外,这种方法的一个突出问题是一般布尔表达式中的大量自由度:确保整个事物相当于只需检查集合成员资格,就必须仔细检查每个子句,注意任何括号,重复变量名称的拼写错误等等。

每个松散的自由度意味着不仅会接触到另外一个bug,而且还会接触到另外一个的bug。

使用显式集的方法具有以下优点:

  • 清晰明确的语义;
  • 严格限制照顾的自由度;
  • O(1)时间复杂度与代码的O(n)复杂性。

这是实现基于集合的习语所需的代码:

static final Set<String> matches = 
                            unmodifiableSet(new HashSet<>(asList("a","b","c")));
...

if (matches.contains(a)) // do something;

* 我暗示import static java.util.Arrays.asListimport static java.util.Collections.unmodifiableSet

答案 5 :(得分:11)

可读性主要是格式化

不可读......

if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
    //Do something

现在很容易实现......

if(a.equals("x") || 
   a.equals("y") || 
   a.equals("z") ||
   Any number of terms...... )
    //Do something

可读性对于阅读源代码的人来说非常主观。

如果我遇到了实现集合,循环或其他许多复杂答案的代码。我不相信地摇头。

将逻辑与问题分开

你混合了两件不同的东西。存在使业务逻辑易于阅读的问题,以及实现业务逻辑的问题。

 if(validState(a))
     // Do something

如何实施validState并不重要。重要的是带有if语句的代码可以作为业务逻辑读取。它不应该是一个长链的布尔运算,隐藏正在发生的事情。

以下是可读业务逻辑的示例。

if(!isCreditCard(a)) {
    return false;
}
if(isExpired(a)) {
    return false;
}
return paymentAuthorized(a);

在某种程度上,必须有处理基本逻辑,字符串,数组等的代码..等等。它不应该处于这个级别。

如果你发现你经常要检查一个字符串是否等于一堆其他字符串。将该代码放入字符串实用程序类中。将它与您的工作分开并保持您的代码可读性。通过确保它显示您真正想要做的事情。

答案 6 :(得分:8)

您可以使用Arrays.asList()。这是最简单的方法,而且不那么详细。

Arrays.asList("x","y","z"...).contains(a)

出于性能原因,如果您的收藏太大,您可以将数据放入HashSet因为搜索有恒定的时间。

示例制作您自己的util方法

public final class Utils{

    private Utils(){}//don't let instantiate

    public static <T> boolean contains(T a,T ... x){
      return new HashSet<>(Arrays.asList(x)).contains(a);
    }
}    

然后在您的客户端代码中:

if(Utils.contains(a,"x","y","z","n")){
  //execute some code
}

答案 7 :(得分:7)

通过一些帮助,你可以获得一个更好的if语句的语法糖,只需要一点点开销。详细说明蒂姆的建议和耶稣的建议...... ...

public abstract class Criteria {

  public boolean matchesAny( Object... objects ) {
    for( int i = 0, count = objects.length; i < count; i++ ) {
      Object object = objects[i];
      if( matches( object ) ) {
        return true;
      }
    }
    return false;
  }

  public boolean matchesAll( Object... objects ) {
    for( int i = 0, count = objects.length; i < count; i++ ) {
      Object object = objects[i];
      if( !matches( object ) ) {
        return false;
      }
    }
    return true;
  }

  public abstract boolean matches( Object object );

}

public class Identity extends Criteria {

  public static Identity of( Object self ) {
    return new Identity( self );
  }

  private final Object self;

  public Identity( Object self ) {
    this.self = self;
  }

  @Override
  public boolean matches( Object object ) {
    return self != null ? self.equals( object ) : object == null;
  }

}

您的if语句将如下所示:

if( Identity.of( a ).matchesAny( "x", "y", "z" ) ) {
  ...
}

这是为这种条件匹配提供通用语法并使表达式描述特定意图之间的中间立场。遵循此模式还允许您使用除相等之外的条件执行相同类型的匹配,就像Comparator的设计方式一样。

即使使用改进的语法,这个条件表达式仍然有点过于复杂。进一步的重构可能会导致术语"x", "y", "z"外部化并将表达式移动到一个名称明确定义其意图的方法中:

private static final String [] IMPORTANT_TERMS = {
  "x",
  "y",
  "z"
};

public boolean isImportant( String term ) {
  return Identity.of( term ).matchesAny( IMPORTANT_TERMS );
}

...而你原来的if语句最终将被缩减为......

if( isImportant( a ) ) {
  ...
}

那要好得多,现在包含你的条件表达式的方法可以更容易地专注于做一件事。

答案 8 :(得分:6)

独立于你想要实现的目标,这个

if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
    //Do something

总是凌乱而且不洁净。首先,它很快就无法理解它。

最简单的解决方案对我来说就是表达你的意图而不是明确的。

尝试改为:

   public class SomeClass{
    public void SomeMethod(){
        if ( matchesSignificantChar(a) ){
          //doSomething
        }    
    }
    private bool matchesSignificantChar(String s){
        return (s.equals("x") || s.equals("y") || s.equals("z") || Any number of terms......    )
      }
   }

这个简化了条件语句的范围,使其更容易理解,同时将复杂性转移到一个由您的意图引导的更小且命名范围。

但是,这仍然不是很容易扩展。如果你试图使它更干净,你可以将布尔方法提取到另一个类中,并将其作为委托传递给SomeClass'es构造函数,甚至是SomeMethod。此外,您还可以查看策略模式,以获得更高的实用性。

请记住,作为程序员,您将花费更多时间阅读代码(不仅仅是您的代码)而不是编写代码,因此从长远来看,创建更易理解的代码将获得回报。

答案 9 :(得分:5)

我使用以下模式

boolean cond = false; // Name this variable reasonably

cond = cond || a.equals("x");
cond = cond || a.equals("y");
cond = cond || a.equals("z");

// Any number of terms......

if (cond) {
    // ...
}

注意:堆上没有创建对象。您也可以使用任何条件,而不仅仅是“等于”。

在ruby中,您可以像||=一样使用运算符cond ||= a.equals("x")

答案 10 :(得分:4)

Set答案很好。如果不比较集合的成员资格,您还可以将部分或全部条件语句分离为方法。例如

if (inBounds(x) && shouldProcess(x) ) {
}

答案 11 :(得分:3)

如果a保证长度为1,你可以这样做:

if ("xyz".indexOf(a) != -1)

答案 12 :(得分:1)

假设您的"x""y""z"可以是任意长度,您可以使用

if (0 <= java.util.Arrays.binarySearch(new String[] { "x", "y", "z" }, a)) {
    // Do something
}

请确保按照binarySearch()的要求按字典顺序列出项目。这应该与Java 1.2一直兼容,并且它应该比使用Java Collections的解决方案更有效。

当然,如果您的"x""y""z"都是单个字符,并且a也是一个字符,则可以使用if (0 <= "xyz".indexOf(a)) { ... }

switch (a) {
  case 'x': case 'y': case 'z':
    // Do something
}

答案 13 :(得分:1)

我更喜欢使用regexp,就像少数guys写的一样。 但你也可以使用下一个代码

private boolean isOneMoreEquals(Object arg, Object... conditions) {
    if (conditions == null || arg == null) {
        return false;
    }
    for (int i = 0, d = conditions.length; i < d; i++) {
        if (arg.equals(conditions[i])) {
            return true;
        }
    }
    return false;
}

所以你的代码将是下一个:

if (isOneMoreEquals(a, "x", "y", "z") {
    //do something
}

答案 14 :(得分:1)

这样做的一个非常好的方法是使用ASCII值,假设你的实际情况是a是char或单个字符串。将a转换为等效的ASCII整数,然后使用以下内容:

如果你想检查a是&#34; t&#34;,&#34; u&#34;,&#34; v&#34;,...,&#34; z&#34 ;,然后做.....

if(val&gt; = 116&amp;&amp; val&lt; = 122){// code here}

答案 15 :(得分:0)

我认为最干净,最快捷的方法是将值放在数组中。

String[] values={"value1","value2","value3"};
for (string value : values) {
    if (a.equals(value){
        //Some code
    }
}

答案 16 :(得分:0)

如果x,y,z ......是连续的,你可以使用if(a&gt; ='x'&amp;&amp; a&lt; ='...'),如果没有,你可以使用ArrayList或者只是阵列。