当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《检查Java中的两个参数,要么都不为null,要么优雅为null》经验,为你挑选了12个好方法。

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

sendmail -from foo@bar.com -password  foobar -subject "hello world"  -to aaa@bbb.com

如果缺少frompassword参数,我使用默认的发件人和密码,例如noreply@bar.com123456.

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

我该如何优雅地检查?

现在我的方式是

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

coolguy.. 323

有一种使用^(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> coolguy..:

有一种使用^(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");
}

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


两个bool上的xor比两个bool上的`!=`更可取吗?

2> Jon Skeet..:

好吧,听起来你正试图检查两者的"无效"状态是否相同.你可以使用:

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

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

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


你是我的英雄@Kaz之一,但没有任何东西可以说'不管是这个还是那个,但不是两个都像'^`那样.:-)
@DavidBullock:当谈到布尔人时,没有什么能说"无论是这个还是那个都不一样",就像......"两个都不一样"; XOR**仅仅是"不等于"功能的另一个名称,而不是布尔值.
@Kaz只是说`^`说"嘿,我的操作数是布尔","!=`没有.(虽然这种效果不幸因为需要检查"我的操作数可能是数字,并且我可能在这个时间点不是关系运算符"而减少了,我认为这是一个缺点).尽管不同意我,你的英雄身份仍然没有减弱:-)
在阅读了问题的要求之后,那么您的解决方案,代码是有意义的并且是可读的.但作为一个4年的开发人员(仍然在学校),阅读这些代码,然后试图找出"业务需求"到位将是一个令人头疼的问题.从这段代码中,我不会立即理解"`from`和`password`必须都为null或者都不为null".也许这只是我和我的经验不足,但我更喜欢@ stig-hemmer的答案中更易读的解决方案,即使它需要另外3行代码.我想我不会马上*得到*`bool!= bool` - 这不直观.
@DavidBullock` ^`运算符是一个按位运算符; 它实际上并不意味着它的操作数是布尔值.布尔xor运算符是`xor`.
@Brilland nope:http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.22.2

3> Stig Hemmer..:

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

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


+1为更好的消息.这**是重要的,没有人喜欢handwaving*"出了问题"* - 错误信息,所以没有人应该*导致*这样的消息.但是,在实践中,应该更喜欢更具体的异常(特别是`IllegalArgumentException`而不是一个简单的`RuntimeException`)
此外,这提供了更好的错误消息.
@matt看起来你的批评不是代码,而是异常的文本.但我认为这个答案的优点在于if语句的结构,而不在于错误消息的内容.这是最好的答案,因为它改进了功能; OP可以轻松替换他们喜欢的任何字符串作为异常文本.
@matt优点是可以区分出现两个无效状态中的哪一个,并自定义错误消息.所以,不要说"你做了这两件事中的一件错了",你可以说"你做了这件事"或"你做了那件事"(然后继续提供解决步骤,如果需要的话).在这两种情况下,分辨率可能相同,但是说"你做了其中一件事是错误的"并不是一个好主意.来源:在我无法提供此功能的环境中,我从满足错误文本中第一个条件的用户那里收集了许多问题.
@DanHenderson>说"你做了其中一件事是错误的",这绝不是一个好主意.我不同意.密码/用户名只是说用户名和密码不匹配更安全.
@DanHenderson从安全的角度来看,[可能更好](http://security.stackexchange.com/q/40694/43248)不要区分用户名在目录中的情况,否则就是攻击者可以找到有效的用户名.但是,混合null/not null(在这种情况下)始终是_usage error_并且显示更详细的错误消息不会泄漏比首先提供的用户更多的信息.

4> Traubenfuchs..:

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

void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException

这节省了您感兴趣的实际方法的空间并使其更具可读性.稍微冗长的方法名称没有任何问题,并且非常简短的方法没有任何问题.


没有空间保存vs`((来自== null)!=(密码== null))`这也很容易理解.没有用的方法有问题.
在阅读代码时,您需要了解一个方法名称,而不是条件杂耍.
if语句有一行,throw语句有第二行,右括号有第三行:All用一行代替.如果你给关闭括号一个新线,还可以节省一条线!

5> Didier L..:

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

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

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


不喜欢它.`from == null!= password == null`将它全部保存在堆栈的同一帧上,但使用`Objects.isNull(Object)`不必要地推送和弹出两个帧.Objects.isNull(Object)之所以存在,是因为'此方法存在用作谓词'(即在流中).
像这样的简单方法通常会被JIT快速内联,因此性能影响很可能是微不足道的.我们确实可以讨论`Objects.isNull()`的用法 - 如果你愿意,你可以编写自己的 - 但就可读性而言,我认为使用`isNull()`更好.此外,您需要额外的括号来使_simple_表达式编译:`from == null!=(password == null)`.
老实说,谁关心单个堆栈框架?如果您正在处理(可能是无限的)递归,或者如果您有一个1000层的应用程序,其对象图形与撒哈拉沙漠的大小相同,那么堆栈只是一个问题.
我同意JIT'(以及操作的顺序......我很懒).仍然,`(val == null)`非常多*为了与null进行比较而提供*,我发现很难通过两个大胖方法调用来盯着我,即使方法是非常实用,可插入,并且有名.那只是我.我最近决定,我有点温和.

6> Khaled.K..:

这是任何数量的空检查的一般解决方案

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


好方法,但你的第一个"等同于"评论是非常错误的(除了所有评论中存在的拼写错误)

7> SQB..:

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

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

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


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



8> x4u..:

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

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

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

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



9> matt..:

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


这段代码错了,不是因为它不起作用,而是因为它很难理解.调试由其他人编写的那种代码只是一场噩梦.
@NO_NAME我不明白为什么这很难理解.在OP提供了三种情况:如果同时提供了形式和密码,提供没有一个时候,哪些应该抛出一个异常,混合箱.你是指中间条件检查它们是否都为空?
我同意@NO_NAME,中间案例需要太多解析才能浏览.除非你解析顶行,否则你不会得到null与中间有任何关系.在这种情况下,from和password的相等性实际上只是不为空的副作用.
@matt可能没有性能优势 - 目前还不清楚编译器会做什么,以及在这种情况下芯片会从内存中提取什么.很多程序员周期都可以在不会产生任何结果的优化上进行刻录.

10> Arnab Datta..:

这是一种相对直接的方式,不涉及任何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);
  }
}



11> 小智..:

似乎没有人提到三元运算符:

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

适用于检查此特定条件,但不能很好地概括过去两个变量.



12> JordiVilapla..:

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

用pseudo写的必须是这样的:

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
}


唯一的问题是,当用户提供`密码`而不提供`from`时,他们可能打算覆盖密码,但保留默认帐户.如果用户这样做,那么这是一个无效的指令,应该告诉他们.程序应该*不*像输入有效一样继续进行,并继续尝试使用默认帐户和用户未指定的密码.我发誓这样的节目.
推荐阅读
周扒pi
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有