173

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

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

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

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

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");
}
8
  • 14
    As an aside, note how using whitespace carefully makes code a lot easier to read - just adding spaces between the operators in your current code would significantly add to the readability IMO.
    – Jon Skeet
    Commented Jan 4, 2016 at 7:01
  • 8
    Please define "elegancy".
    – Renaud
    Commented Jan 4, 2016 at 8:43
  • You need a separate set of arguments for the SMTP authentication credentials and for the envelope sender e-mail address. The From e-mail address is not always the SMTP authentication name.
    – Kaz
    Commented Jan 4, 2016 at 20:42
  • 3
    It really can't get much more optimized, it is one line of readable code and nothing can be gained by over-optimizing it.
    – diynevala
    Commented Jan 5, 2016 at 7:38
  • 3
    Side note: if this is a shell script, won't the passwords be saved in the shell history? Commented Jan 7, 2016 at 22:39

14 Answers 14

346

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

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

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

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

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.

5
  • 155
    Is there a reason why xor on two bools is preferable to != on two bools? Commented Jan 4, 2016 at 15:35
  • 1
    Wow, I didn't realize that XOR on boolean is the same as !=. Mindblown. And that's a very high number of upvotes in the comment. And, to add quality to this comment, yes, I also think that giving different error message for different error case is better, since the user will know better how to correct the error.
    – justhalf
    Commented Jan 10, 2016 at 14:15
  • 1
    For 2 elements is fine. How to do this with >2 elements? Commented Jul 7, 2017 at 10:42
  • I want show an error message if any of the elements is > 0. By default all are set to 0. If all are >0 its a valid scenario. How to do this? Commented Jul 7, 2017 at 11:34
  • This would make a nifty interview question. I wonder what % of programmers know it. But I don't agree that it's not clear enough and warrants splitting into 2 if clauses - the message in the exception documents it nicely (I edited the question, but it won't appear until accepted)
    – Adam
    Commented Jul 20, 2017 at 10:32
296

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)
{
    ...
}
12
  • 18
    You're one of my SO heros @Kaz, but nothing says 'either this or that, but not both the same' like ^ does. :-) Commented Jan 6, 2016 at 1:19
  • 6
    @DavidBullock: When it comes to Booleans, nothing says "either this or that but not both the same" like ... "not both the same"; XOR is just another name for the "not equals" function over Booleans.
    – Kaz
    Commented Jan 6, 2016 at 1:48
  • 5
    @Kaz It's just that ^ says "Hey, my operands are booleans" in a way that != doesn't. (Although this effect is unfortunately diminished by the need to check for "my operands might be numeric, and I might not be a relational operator at this point in time", which I grant is a disadvantage). Your hero status undiminished, despite disagreeing with me :-) Commented Jan 6, 2016 at 1:59
  • 3
    After reading the requirements of the problem, then your solution, the code makes sense and is readable. But as a developer of 4 years (still in school), reading this code then trying to figure out what "business requirement" was in place would be a headache. From this code, I don't immediately understand "from and password must both be null or both be not null". Perhaps that's just me and my inexperience, but I prefer the more readable solution as in @stig-hemmer's answer, even if it costs another 3 lines of code. I guess I just don't immediately get bool != bool - it's not intuitive. Commented Jan 6, 2016 at 17:38
  • 2
    @DavidBullock The ^ operator is a bitwise operator; it actually doesn't imply that its operands are boolean. The boolean xor operator is xor.
    – Brilliand
    Commented Jan 6, 2016 at 23:55
222

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");
}
12
  • 52
    +1 for the better messages. This is important, nobody likes handwaving "something went wrong"-error messages, so nobody should cause such messages. However, in practice, one should prefer a more specific exception (particularly, an IllegalArgumentException instead of a bare RuntimeException)
    – Marco13
    Commented Jan 4, 2016 at 15:31
  • 6
    @matt it looks like your criticism is not with the code, but with the text of the exceptions. But I think the merit of this answer lies in the structure of the if statements, not in the content of the error messages. This is the best answer because it improves upon the functionality; OP could easily substitute whatever strings they like for the exception texts. Commented Jan 5, 2016 at 14:17
  • 4
    @matt The advantage is that it becomes possible to distinguish which of the two invalid states have occurred, and customize the error message. So instead of saying "you have done one of these two things wrong" you can say "you did this" or "you did that" (and then go on to provide resolution steps, if desired). The resolution might be the same in both cases, but it's never a good idea to say "you did one of these things wrong". Source: in an environment in which I was unable to provide this functionality, I fielded many questions from users who satisfied the first condition in my error text. Commented Jan 5, 2016 at 15:02
  • 4
    @DanHenderson > it's never a good idea to say "you did one of these things wrong." I disagree. Password/Username it is safer to just say the username and password don't match.
    – matt
    Commented Jan 5, 2016 at 19:50
  • 2
    @DanHenderson From a security point of view it might be better not to differentiate between the case where the username is in the directory or not as otherwise an attacker could find out valid usernames. However mixing null/not null is (in this case) always a usage error and showing a more detailed error message does not leak any more information than the user provided in the first place.
    – siegi
    Commented Jan 6, 2016 at 7:39
16

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

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.

8
  • 14
    No space saved vs ((from == null) != (password == null)) that is very simple to understand too. There is something wrong with not useful methods.
    – edc65
    Commented Jan 4, 2016 at 11:22
  • 3
    There is one line for the if statement, the second line for the throw statement and the third line for the closing brace: All replaced by one line. One more line saved if you give closing braces a new line!
    – ASA
    Commented Jan 4, 2016 at 11:25
  • 10
    When reading the code you have one method name you need to understand vs condition juggling.
    – ASA
    Commented Jan 4, 2016 at 11:25
  • 1
    definitely +1, always prefer abstracting away down-and-dirty implementation details and operators with descriptive methods and variable names that make INTENTION clear. logic contains bugs. comments are even worse. a method name shows intention and isolates logic so it's easier to find and fix errors. this solution doesn't require the reader to know or think about any syntax or logic at all, it allows us to focus on the BUSINESS REQUIREMENTS instead (which is what really matters)
    – sara
    Commented Jan 7, 2016 at 13:02
  • 1
    You would run into unnecessary trouble if you wanted to have some descriptive exception message here. Commented Jan 8, 2016 at 16:11
11

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

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.

4
  • 6
    Don't like it. from == null != password == null keeps it all on the same frame of the stack, but using Objects.isNull(Object) needlessly pushes and pops two frames. Objects.isNull(Object) is there because 'This method exists to be used as a Predicate' (ie. in streams). Commented Jan 6, 2016 at 1:01
  • 6
    A simple method like this will normally be quickly inlined by the JIT so the performance impact is most likely negligible. We could indeed debate the usage of Objects.isNull() – you can write your own if you prefer – but as far as readability is concerned I think using isNull() is better. Moreover you need additional parentheses to make the simple expression compile: from == null != (password == null).
    – Didier L
    Commented Jan 6, 2016 at 10:03
  • 2
    I agree about the JIT'ing (and the order of operations ... I was lazy). Still, (val == null) is so very much the facility provided for the purpose of comparing with null, I find it hard to get over two big fat method invocations staring me in the face, even if the method is quite functional, in-lineable, and well-named. That's just me though. I've decided recently that I'm mildy odd. Commented Jan 6, 2016 at 10:47
  • 7
    honestly, who cares about a single stack frame? the stack is only ever an issue if you're dealing with (possibly infinite) recursion, or if you have a 1000-tiered application with an object graph the size of the sahara desert.
    – sara
    Commented Jan 7, 2016 at 13:04
10

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) { .. }
2
  • 2
    Good approach, but your first "equivalent to" comment is horribly wrong (beyond the spelling mistake which exists in all the comments)
    – Ben Voigt
    Commented Jan 7, 2016 at 22:30
  • @BenVoigt Thank you for the notice, fixed now
    – Khaled.K
    Commented Jan 9, 2016 at 10:31
9

Since you want to do something special (use defaults) when both sender and password are absent, handle that first.
After that, you should have both a sender and a password to send an e-mail; throw an exception if either is missing.

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

An added benefit is that, should either of your defaults be null, that will be detected as well.


Having said that, in general I think that use of XOR should be permissible when that is the operator you need. It is a part of the language, not just some trick that works because of an arcane compiler-bug.
I once had a cow-orker who found the ternary operator too confusing to use...

2
  • 2
    Downvoted because I made a random pick for sampling one of your answers and can't finde the promised xkcd link! shame on you!
    – dhein
    Commented Mar 15, 2016 at 14:10
  • @Zaibis In my defence, it's just a hobby, not a full time job. But I'll see if I can find one...
    – SQB
    Commented Mar 15, 2016 at 15:01
8

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.

3
  • I comment somewhat conversationally, so I might follow that else with a "// we have a null from". The brevity of the example makes this really minor. I do like the clarity of the logic and the reducing of tests this presents.
    – The Nate
    Commented Jan 7, 2016 at 12:00
  • This works perfectly well, but nesting if statements seems less clear and more cluttered to me. That is just personal opinion though, so I'm glad this answer is here as another option
    – Kevin
    Commented Jan 7, 2016 at 20:10
  • As far as elegance goes, this is probably one of the least elegant ways to do this.
    – dramzy
    Commented Jan 11, 2016 at 7:57
7

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.

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 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"
);
6
  • 2
    This code is wrong not because it doesn't work but because it is very hard to understand. Debugging that kind of code, written by someone else, is just a nightmare. Commented Jan 4, 2016 at 23:55
  • 2
    @NO_NAME I don't see why it is hard to understand. The OP provided three cases: When both form and password are provided, when neither one is provided, and the mixed case which should throw an exception. Are you referring to the the middle conditional to check if they are both null?
    – matt
    Commented Jan 5, 2016 at 6:17
  • 2
    I agree with @NO_NAME, that middle case takes too much parsing to glance over. Unless you parse the top line, you don't get that null has anything to do with the middle. The equality of from and password in that case is really just a side-effect of not being null.
    – jimm101
    Commented Jan 5, 2016 at 19:21
  • 1
    @jimm101 Yes, I could see that being an issue. The performance benefit would be minimal/ non-detectable to a more verbose solution. I'm not sure if that is what the issue is though. Ill update it.
    – matt
    Commented Jan 5, 2016 at 19:40
  • 2
    @matt There might not be a performance benefit--it's not clear what the compiler would do, and what the chip would pull from memory in this case. A lot of programmer cycles can be burned on optimizations that don't really yield anything.
    – jimm101
    Commented Jan 5, 2016 at 19:52
6

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.

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);
  }
}
5
  • 1
    you shouldn't use exceptions in place of a control flow statement. Besides being a performance hit, more importantly it decreases your code's readability because it breaks the mental flow.
    – an phu
    Commented Jan 6, 2016 at 22:28
  • 1
    @anphu No. Just no. Using exceptions increases code readability as it gets rid of if-else clauses and make the code flow clearer. docs.oracle.com/javase/tutorial/essential/exceptions/… Commented Jan 6, 2016 at 23:15
  • 1
    I think you are confusing something that is truly exceptional vs. something that happens routinely and could be considered part of normal execution. The java doc uses examples that are exceptional i.e. out of memory while reading a file; Encountering invalid params is not exceptional. "Do not use exceptions for normal flow of control." - blogs.msdn.com/b/kcwalina/archive/2005/03/16/396787.aspx
    – an phu
    Commented Jan 7, 2016 at 0:08
  • Well, first: if missing/proper arguments is not exceptional, why does the IllegalArgumentException even exist then? Second: if you truly believe that invalid arguments are not exceptional, then there should not be validation of it either. In other words, just try to do the action and when something goes wrong, then throw an exception. This approach is just fine, but the performance penalty you are talking about is incurred here, not in the approach I suggested. Java exceptions are not slow when thrown; it's the stacktrace that takes time to recover. Commented Jan 7, 2016 at 8:32
  • Context is key. In OP's context (sendmail app), forgetting either username and password is common and expected. In a missile guidance algo, an null coordinate param should throw an exception. I did not say do not validate params. In OP's context, I said do not use exception to drive the application logic. Unwinding the stacktrace is the perf hit I am talking about. Using your approach, eventually you either catch the PasswordMissingException/FromEmailMissingException i.e unwind, or worse, let it go unhandled. .
    – an phu
    Commented Jan 7, 2016 at 20:10
6

Nobody seems to have mentioned the ternary operator:

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

Works nicely for checking this particular condition, but doesn't generalize well past two variables.

3
  • 1
    Looks nice, but harder to understand than ^, != with two bools or two ifs
    – coolguy
    Commented Jan 8, 2016 at 19:02
  • @coolguy My guess is that the ternary operator is far more common than the XOR operator (not to mention the 'mental surprise' every time you see XOR in code that isn't doing bit operations), and this formulation tends to avoid the cut and paste errors that plague the double if.
    – gbronner
    Commented Jan 8, 2016 at 19:30
  • Not recommended. This will not differenciate between (a!=null && b==null) and (a==null && b!=null). If you are going to use the ternary operator: a == null ? (b == null? "both null" : "a null while b is not") : (b ==null? "b null while a is not") Commented Jan 12, 2016 at 11:09
5

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

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
}
1
  • 4
    The only problem with this is that when the user supplies password without supplying from, then they may have intended to override the password, but keep the default account. If the user does that, it's an invalid instruction and they should be told so. The program should not proceed as if the input were valid, and go ahead and try to use the default account with a password the user did not specify. I swear at programs like that. Commented Jan 6, 2016 at 1:16
4

I'm surprised nobody mentioned the simple solution of making from and password fields of a class and passing a reference to an instance of that class:

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

Here from could be null or non-null and if it's non-null, both its fields have non-null values.

One advantage of this approach is that the error of making one field but not the other field null gets triggered where the account is initially obtained, not when the code using the account runs. By the time the code using the account is executed, it's impossible for the data to be invalid.

Another advantage to this approach is more readable as it provides more semantic information. Also, it's likely that you require the name and password together in other places so the cost of defining an additional class amortizes over multiple usages.

4
  • It doesn't work as expected sincenew Account(null, null) will throw an NPE even though Account with both null name and password is still valid.
    – HieuHT
    Commented May 7, 2019 at 21:36
  • The idea is to pass null if name and password are null, whether or not in the real world you would say the account exists. Commented May 9, 2019 at 13:16
  • What I get from OP is That is to say, either both are non-null, or both are null. I just wondered how you can create an Account object with both name and password null?
    – HieuHT
    Commented May 9, 2019 at 13:39
  • @HieuHT Sorry my last comment was unclear. If name and password are null, you would use null instead of an Account. You wouldn't pass null to the Account constructor. Commented May 9, 2019 at 18:59
0
if ((from == null) == (password == null)){ //if both are true or both are false

}

(Source: Intellij IDEA)

Not the answer you're looking for? Browse other questions tagged or ask your own question.