检查Java中的两个参数,要么都不为null,要么优雅为null

时间:2016-01-04 06:57:24

标签: java

我使用spring boot来开发用于发送电子邮件的shell项目,例如

unit_id = models.AutoField(primary_key=True)

如果缺少sendmail -from foo@bar.com -password foobar -subject "hello world" -to aaa@bbb.com from参数,我会使用默认发件人和密码,例如passwordnoreply@bar.com

因此,如果用户传递123456参数,则他们还必须传递from参数,反之亦然。也就是说,两者都是非null,或者两者都是null。

如何优雅地检查?

现在我的方式是

password

13 个答案:

答案 0 :(得分:318)

有一种方法可以使用^XOR)运算符:

if (from == null ^ password == null) {
    // Use RuntimeException if you need to
    throw new IllegalArgumentException("message");
}

如果只有一个变量为空,则if条件为真。

但我认为通常使用两个if条件和不同的异常消息会更好。您无法使用单一条件来定义出错的地方。

if ((from == null) && (password != null)) {
    throw new IllegalArgumentException("If from is null, password must be null");
}
if ((from != null) && (password == null)) {
    throw new IllegalArgumentException("If from is not null, password must not be null");
}

它更易读,更容易理解,只需要额外输入一点。

答案 1 :(得分:283)

嗯,听起来你正试图检查"无效"两者的条件是否相同。你可以使用:

if ((from == null) != (password == null))
{
    ...
}

或者使用辅助变量使其更明确:

boolean gotFrom = from != null;
boolean gotPassword = password != null;
if (gotFrom != gotPassword)
{
    ...
}

答案 2 :(得分:221)

就个人而言,我更喜欢可读性和优雅。

if (from != null && password == null) {
    throw new RuntimeException("-from given without -password");
}
if (from == null && password != null) {
    throw new RuntimeException("-password given without -from");
}

答案 3 :(得分:16)

将该功能放在带有签名的2参数方法中:

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

这样可以节省您感兴趣的实际方法的空间,并使其更具可读性。稍微详细的方法名称没有任何问题,非常简短的方法没有任何问题。

答案 4 :(得分:11)

Java 8解决方案是使用Objects.isNull(Object),假设是静态导入:

if (isNull(from) != isNull(password)) {
    throw ...;
}

对于Java< 8(或者如果你不喜欢使用Objects.isNull()),你可以轻松编写自己的isNull()方法。

答案 5 :(得分:9)

以下是任意数量空检查的一般解决方案

public static int nulls(Object... objs)
{
    int n = 0;
    for(Object obj : objs) if(obj == null) n++;
    return n;
}

public static void main (String[] args) throws java.lang.Exception
{
    String a = null;
    String b = "";
    String c = "Test";

    System.out.println (" "+nulls(a,b,c));
}

用途

// equivalent to (a==null & !(b==null|c==null) | .. | c==null & !(a==null|b==null))
if (nulls(a,b,c) == 1) { .. }

// equivalent to (a==null | b==null | c==null)
if (nulls(a,b,c) >= 1) { .. }

// equivalent to (a!=null | b!=null | c!=null)
if (nulls(a,b,c) < 3) { .. }

// equivalent to (a==null & b==null & c==null)
if (nulls(a,b,c) == 3) { .. }

// equivalent to (a!=null & b!=null & c!=null)
if (nulls(a,b,c) == 0) { .. }

答案 6 :(得分:9)

由于您希望在发送者和密码都不存在时执行特殊操作(使用默认值),请先处理 之后,您应该同时拥有发件人和密码来发送电子邮件;如果丢失则抛出异常。

// use defaults if neither is provided
if ((from == null) && (password == null)) {
    from = DEFAULT_SENDER;
    password = DEFAULT_PASSWORD;
}

// we should have a sender and a password now
if (from == null) {
    throw new MissingSenderException();
}
if (password == null) {
    throw new MissingPasswordException();
}

另一个好处是,如果您的任何一个默认值为空,那么也会检测到它。

话虽如此,一般我认为当你需要的操作员时,应该允许使用XOR。它语言的一部分,而不仅仅是因为一个神秘的编译器错误而起作用的一些技巧。
我曾经有过一个发现三元运算符太混乱的牛犊......

答案 7 :(得分:8)

我想建议另一种方法,就是我实际编写这段代码的方法:

if( from != null )
{
    if( password == null )
        error( "password required for " + from );
}
else
{
    if( password != null )
        warn( "the given password will not be used" );
}

对我来说,这似乎是表达这种情况的最自然的方式,这使得很容易理解将来可能需要阅读它的人。它还允许您提供更有用的诊断消息,并将不必要的密码视为不太严重,并且可以轻松修改,这很可能适用于这种情况。即您可能会发现将密码作为命令行参数并不是最好的主意,如果参数缺失,可能需要允许从标准输入中读取密码。或者您可能希望默默地忽略多余的密码参数。像这样的变化不需要你重写整个事情。

除此之外,它只执行最少数量的比较,因此它并不比更多&#34;优雅&#34; 替代品贵。虽然性能不太可能成为问题,因为启动新进程已经比额外的空检查要昂贵得多。

答案 8 :(得分:7)

我认为处理这个问题的正确方法是考虑三种情况:提供'from'和'password',两者都没有提供,两者都是混合的。

if(from != null && password != null){
    //use the provided values
} else if(from == null && password == null){
    //both values are null use the default values
} else{
   //throw an exception because the input is not correct.
}

听起来原始问题想要在输入不正确的情况下打破流程,但是之后他们将不得不重复一些逻辑。也许一个好的抛出声明可能是:

throw new IllegalArgumentException("form of " + form + 
    " cannot be used with a "
    + (password==null?"null":"not null") +  
    " password. Either provide a value for both, or no value for both"
);

答案 9 :(得分:6)

这是一种相对直接的方式,不涉及任何Xor og冗长的ifs。但它确实需要您稍微冗长一点,但从好的方面来说,您可以使用我建议的自定义异常来获得更有意义的错误消息。

private void validatePasswordExists(Parameters params) {
   if (!params.hasKey("password")){
      throw new PasswordMissingException("Password missing");
   }
}

private void validateFromExists(Parameters params) {
   if (!params.hasKey("from")){
      throw new FromEmailMissingException("From-email missing");
   }
}

private void validateParams(Parameters params) {

  if (params.hasKey("from") || params.hasKey("password")){
     validateFromExists(params);
     validatePasswordExists(params);
  }
}

答案 10 :(得分:6)

似乎没有人提到ternary operator

if (a==null? b!=null:b==null)

很好地检查这个特定条件,但是并没有很好地概括过两个变量。

答案 11 :(得分:5)

当我看到你的意图时,没有必要总是检查两个独占无效,但是当且仅当password不为空时才检查from是否为空。如果password为空,您可以忽略给定的from参数并使用您自己的默认值。

写入伪必须是这样的:

if (from == null) { // form is null, ignore given password here
    // use your own defaults
} else if (password == null) { // form is given but password is not
    // throw exception
} else { // both arguments are given
    // use given arguments
}

答案 12 :(得分:4)

我很惊讶没有人提到制作类的frompassword字段并将引用传递给该类的实例的简单解决方案:

class Account {
    final String name, password;
    Account(String name, String password) {
        this.name = Objects.requireNonNull(name, "name");
        this.password = Objects.requireNonNull(password, "password");
    }
}

// the code that requires an account
Account from;
// do stuff

此处from可以为null或非null,如果它为非null,则其两个字段都具有非空值。

这种方法的一个优点是,在最初获得帐户时,而不是在使用帐户的代码运行时,会触发使一个字段而非另一个字段为空的错误。当执行使用帐户的代码时,数据无法无效。

这种方法的另一个优点是更具可读性,因为它提供了更多的语义信息。此外,您可能需要在其他地方一起使用名称和密码,因此定义其他类的成本会因多次使用而摊销。