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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34586109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:48:23  来源:igfitidea点击:

Check two arguments in Java, either both not null or both null elegantly

java

提问by zhuguowei

I used spring boot to develop a shell project used to send email, e.g.

我用spring boot开发了一个用来发邮件的shell项目,例如

sendmail -from [email protected] -password  foobar -subject "hello world"  -to [email protected]

If the fromand passwordarguments are missing, I use a default sender and password, e.g. [email protected]and 123456.

如果缺少fromandpassword参数,我使用默认的发件人和密码,例如[email protected]and 123456

So if the user passes the fromargument they must also pass the passwordargument and vice versa. That is to say, either both are non-null, or both are null.

因此,如果用户传递from参数,他们也必须传递password参数,反之亦然。也就是说,要么两者都非空,要么都为空。

How do I check this elegantly?

我如何优雅地检查这个?

Now my way is

现在我的方法是

if ((from != null && password == null) || (from == null && password != null)) {
    throw new RuntimeException("from and password either both exist or both not exist");
}

采纳答案by coolguy

There is a way using the ^(XOR) operator:

有一种使用^( XOR) 运算符的方法:

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

The ifcondition will be true if only one variable is null.

if要是只有一个变量是空的条件将是真实的。

But I think usually it's better to use two ifconditions with different exception messages. You can't define what went wrong using a single condition.

但我认为通常最好使用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");
}

It is more readable and is much easier to understand, and it only takes a little extra typing.

它更具可读性,更容易理解,并且只需要额外输入一点。

回答by Jon Skeet

Well, it sounds like you're trying to check whether the "nullity" condition of the two is the same or not. You could use:

好吧,听起来您正在尝试检查两者的“无效”条件是否相同。你可以使用:

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

Or make it more explicit with helper variables:

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

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

回答by JordiVilaplana

As I see your intentions, there is no need to always check both exclusive nullities but to check if passwordis null if and only if fromis not null. You can ignore the given passwordargument and use your own default if fromis null.

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

Written in pseudo must be like this:

写成伪必须是这样的:

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
}

回答by Traubenfuchs

Put that functionality in a 2 argument method with the signature:

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

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

This saves space in the actual method you are interested in and makes it more readable. There is nothing wrong with slightly verbose method names and there is nothing wrong with very short methods.

这可以节省您感兴趣的实际方法中的空间并使其更具可读性。稍微冗长的方法名称没有错,非常短的方法也没有错。

回答by Stig Hemmer

Personally, I prefer readable to elegant.

就个人而言,我更喜欢可读而不是优雅。

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

回答by matt

I think a correct way to handle this is to consider three situations: both 'from' and 'password' are provided, neither are provided, a mix of the two are provided.

我认为处理这个问题的正确方法是考虑三种情况:提供“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.
}

It sounds like the original question wants to break the flow if it is incorrect input, but then they will have to repeat some of the logic later. Perhaps a good throw statement might be:

听起来如果输入不正确,原始问题想要中断流程,但随后他们将不得不重复一些逻辑。也许一个好的 throw 语句可能是:

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

回答by x4u

I would like to suggest another alternative which is how I would actually write this piece of code:

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

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

To me this seems to be the most natural way to express this condition which makes it easy to understand for somebody who might have to read it in the future. It also allows you to give more helpful diagnostic messages and treat the unnecessary password as less serious and it makes it easy to modify which is rather likely for such a condition. I.e. you may find out that giving a password as a command line argument is not the best idea and may want allow reading the password from standard input optionally if the argument is missing. Or you may want to silently ignore the superfluous password argument. Changes like these would not require you to rewrite the whole thing.

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

Besides that it executes only the minimum number of comparisons, so it's not more expensive than the more "elegant"alternatives. Although performance is very unlikely a problem here because starting a new process is already much more expensive than a extra null check.

除此之外,它只执行最少数量的比较,因此它并不比更“优雅”的替代方案更昂贵。虽然性能在这里不太可能成为问题,因为启动一个新进程已经比额外的空检查昂贵得多。

回答by Didier L

A Java 8 solution would be to use Objects.isNull(Object), assuming a static import:

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

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

For Java < 8 (or if you don't like using Objects.isNull()), you can easily write your own isNull()method.

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

回答by Khaled.K

Here is a general solution for any number of null checks

这是任意数量的空检查的通用解决方案

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

Uses

用途

// 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) { .. }

回答by Arnab Datta

Here's a relatively straight-forward way that does not involve any Xor og lengthy ifs. It does however require you to be slightly more verbose, but on the upside, you can use the custom Exceptions I suggested to get a more meaningful error message.

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

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