更清洁的IF声明

All*_*lan 28 java if-statement

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

if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
    //Do something
Run Code Online (Sandbox Code Playgroud)

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

注意:x,y和z只是任何长度的任何字符串的占位符.这里可能有20个字符串的变量长度,如果条件各自被OR在一起

谢谢

Kev*_*man 46

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

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

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

  • 我认为这是唯一有效的答案.所有其他人只是解决一个示例问题,总的来说无论如何都没有帮助. (10认同)
  • @crush我笑着读这个.没有人同意你的看法. (6认同)
  • 我同意@noone.问题太模糊,无法妥善回答. (2认同)
  • OP并不关心它,但将其分解为另一个功能也有助于单元测试. (2认同)

Hah*_*ess 45

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

如果这是一个紧密循环,您可以使用静态集.

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
}
Run Code Online (Sandbox Code Playgroud)

如果你想要更加确定在你不看的时候没有任何东西被修改.

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

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

  • 更短版本:`Collections.addAll(stuff,"x","y","z");` (42认同)
  • 您应该很高兴我没有使用集合的XML配置发布Spring解决方案. (15认同)
  • 如果你有很多字符串,那么它的可读性仍然很差,因为它占用了很多行 (7认同)
  • 我是SO上唯一一个认为这个答案很可怕的用户吗?这么多开销.并且`stuff`与`if`语句的逻辑分离,因此变得难以阅读. (4认同)
  • 先生,你可以侮辱我的家人,我的身体,种族,宗教,政治,但我不会让你侮辱XML. (3认同)

Lak*_*gha 26

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

         switch (str) {

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

    }
Run Code Online (Sandbox Code Playgroud)

这是链接

  • @downvoter - 你能说明原因吗? (13认同)
  • @keshlam - 你错过了OP的注释"x,y和z只是任何长度的字符串的占位符." (4认同)

Bat*_*eba 24

使用正则表达式

If (a.matches("[xyz]")){
    // matches either "x", "y", or "z"
Run Code Online (Sandbox Code Playgroud)

或者,对于更长的弦乐,

If (a.matches("one|two|three")){
    // matches either "one", "two" or "three"
Run Code Online (Sandbox Code Playgroud)

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

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

if (a.equals("x") || 
    a.equals("y") || 
    a.equals("z")
    ){
Run Code Online (Sandbox Code Playgroud)

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

  • 您应该以["Everybody stand back!"](http://xkcd.com/208/)开始您的回答. (4认同)
  • @crush不,`matches`需要匹配完整的输入序列. (3认同)

Mar*_*nik 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;
Run Code Online (Sandbox Code Playgroud)

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

  • 列表是O(N)来检查成员资格,设置为O(1).更大的收藏速度要快得多. (11认同)

Rea*_*lar 11

可读性主要是格式化

不可读......

if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
    //Do something
Run Code Online (Sandbox Code Playgroud)

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

if(a.equals("x") || 
   a.equals("y") || 
   a.equals("z") ||
   Any number of terms...... )
    //Do something
Run Code Online (Sandbox Code Playgroud)

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

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

将逻辑从问题中分离出来

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

 if(validState(a))
     // Do something
Run Code Online (Sandbox Code Playgroud)

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

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

if(!isCreditCard(a)) {
    return false;
}
if(isExpired(a)) {
    return false;
}
return paymentAuthorized(a);
Run Code Online (Sandbox Code Playgroud)

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

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


nac*_*okk 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);
    }
}    
Run Code Online (Sandbox Code Playgroud)

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

if(Utils.contains(a,"x","y","z","n")){
  //execute some code
}
Run Code Online (Sandbox Code Playgroud)

  • @DoorknobofSnow更可能是`Arrays.asList("a","b","c");` (4认同)
  • 这是一个语法错误......它应该是`Arrays.asList(new String [] {"a","b","c"...})` (2认同)

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

}
Run Code Online (Sandbox Code Playgroud)

你的if语句看起来像这样:

if( Identity.of( a ).matchesAny( "x", "y", "z" ) ) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

这在具有这种条件匹配的通用语法和使表达式描述特定意图之间具有中间意义.遵循此模式还允许您使用除相等之外的条件执行相同类型的匹配,就像Comparator设计s 一样.

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

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

public boolean isImportant( String term ) {
  return Identity.of( term ).matchesAny( IMPORTANT_TERMS );
}
Run Code Online (Sandbox Code Playgroud)

......而你原来的if语句最终将被简化为......

if( isImportant( a ) ) {
  ...
}
Run Code Online (Sandbox Code Playgroud)

这样做要好得多,现在包含条件表达式的方法可以更容易地关注"做一件事".

  • 添加额外的抽象层并赋予其简洁的名称是提高可读性的好方法.+1 (2认同)

Jes*_* R. 6

这与你想要实现的目标无关

if(a.equals("x") || a.equals("y") || a.equals("z") || Any number of terms...... )
    //Do something
Run Code Online (Sandbox Code Playgroud)

总是凌乱和不洁的.首先,它很快就能很快理解它.

最简单的解决方案,我会表达你的意图,而不是被明确.

尝试这样做:

   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......    )
      }
   }
Run Code Online (Sandbox Code Playgroud)

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

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

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


Bor*_*ski 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) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

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

在ruby中,您可以使用运算符||=来实现此目的cond ||= a.equals("x").