我使用spring boot来开发用于发送电子邮件的shell项目,例如
sendmail -from foo@bar.com -password foobar -subject "hello world" -to aaa@bbb.com
如果缺少from
和password
参数,我使用默认的发件人和密码,例如noreply@bar.com
和123456
.
因此,如果用户传递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"); }
它更易读,更容易理解,只需要额外输入一点.
有一种使用^
(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"); }
它更易读,更容易理解,只需要额外输入一点.
好吧,听起来你正试图检查两者的"无效"状态是否相同.你可以使用:
if ((from == null) != (password == null)) { ... }
或者使用辅助变量使其更明确:
boolean gotFrom = from != null; boolean gotPassword = password != null; if (gotFrom != gotPassword) { ... }
就个人而言,我更喜欢可读性和优雅.
if (from != null && password == null) { throw new RuntimeException("-from given without -password"); } if (from == null && password != null) { throw new RuntimeException("-password given without -from"); }
将该功能放在带有签名的2参数方法中:
void assertBothNullOrBothNotNull(Object a, Object b) throws RuntimeException
这节省了您感兴趣的实际方法的空间并使其更具可读性.稍微冗长的方法名称没有任何问题,并且非常简短的方法没有任何问题.
Objects.isNull(Object)
假设静态导入,将使用Java 8解决方案:
if (isNull(from) != isNull(password)) { throw ...; }
对于Java <8(或者如果您不喜欢使用Objects.isNull()
),您可以轻松编写自己的isNull()
方法.
这是任何数量的空检查的一般解决方案
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) { .. }
由于您希望在发送者和密码都不存在时执行特殊操作(使用默认值),请先处理.
之后,您应该同时拥有发件人和密码来发送电子邮件; 如果丢失则抛出异常.
// 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而起作用的一些技巧.
我曾经有过一个牛犊发现这个三元运算符太混乱了......
我想建议另一种方法,就是我实际编写这段代码的方法:
if( from != null ) { if( password == null ) error( "password required for " + from ); } else { if( password != null ) warn( "the given password will not be used" ); }
对我来说,这似乎是表达这种情况的最自然的方式,这使得很容易理解将来可能需要阅读它的人.它还允许您提供更有用的诊断消息,并将不必要的密码视为不太严重,并且可以轻松修改,这很可能适用于这种情况.也就是说,您可能会发现将密码作为命令行参数并不是最好的主意,如果参数缺失,可能需要允许从标准输入中读取密码.或者您可能希望默默地忽略多余的密码参数.像这样的变化不需要你重写整个事情.
除此之外,它只执行最少数量的比较,因此它并不比更"优雅"的替代品更昂贵.虽然性能不太可能成为问题,因为启动新进程已经比额外的空检查昂贵得多.
我认为处理这个问题的正确方法是考虑三种情况:提供'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" );
这是一种相对直接的方式,不涉及任何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); } }
似乎没有人提到三元运算符:
if (a==null? b!=null:b==null)
适用于检查此特定条件,但不能很好地概括过去两个变量.
当我看到你的意图时,没有必要总是检查两个独占的无效,但是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 }