我使用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
参数,我会使用默认发件人和密码,例如password
和noreply@bar.com
。
因此,如果用户传递123456
参数,则他们还必须传递from
参数,反之亦然。也就是说,两者都是非null,或者两者都是null。
如何优雅地检查?
现在我的方式是
password
答案 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)
答案 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)
我很惊讶没有人提到制作类的from
和password
字段并将引用传递给该类的实例的简单解决方案:
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,则其两个字段都具有非空值。
这种方法的一个优点是,在最初获得帐户时,而不是在使用帐户的代码运行时,会触发使一个字段而非另一个字段为空的错误。当执行使用帐户的代码时,数据无法无效。
这种方法的另一个优点是更具可读性,因为它提供了更多的语义信息。此外,您可能需要在其他地方一起使用名称和密码,因此定义其他类的成本会因多次使用而摊销。