Friday, November 14, 2014

Hooray for Boo..leans

I've mentioned booleans before, and it's critical to understand both boolean variables and boolean logic.  A great deal can be accomplished with booleans, for good or for ill.  You can make your programs sing or you can make yourself cry depending on how well you understand what you're doing.

I'm going to use the good old 'if' statement a lot in this post, but the same concepts apply to any conditional, such as while loops.

About the simplest possible boolean tests would be:

if (true) {

or

if (false) {

In fact, they're so simple that the java compiler should entirely remove either the test (in the first case) or the entire code block (in the second).  But logically, the first conditional should simply always execute whatever statement follows, and the second should just bypass the statement.

A more likely scenario would be this:

while(true) {

This is what is known as an infinite loop, which is handy when you mean it and devastating when you don't.  Create a while loop with a boolean condition that, due to some error, never switches to false, and you've got yourself a program that looks like it has 'locked up', when really it's happily executing the same thing over and over and over again.

Of course, most of the time you're going to be using logic, not constants, to determine how a conditional statement behaves.  This sort of thing is extremely common:

if ( someValue > 5 ) {

This expression, using the 'greater-than' conditional operator, evaluates to true if someValue is 6, or 22, or 25,101,793.  Just so long as it's more than five.  If it's five (or less) , it evaluates to false.  Say, that could come in handy...

Of course, you can also check for a value being less than another value with '<', or equal to another value with '=='.  You can get quickly more complex if you wish:

if ( value1 * 3 < value2 / 2 ) {

Is a perfectly valid expression.  Of course, you'd have to work out what values will do what, but it's not too conceptually difficult to understand that this will pass if value1 is 1 and value2 is 36, but fail if value1 is 1 and value2 is 2.

Boolean expressions can also be subjected to boolean operators, to evaluate more complex conditions.  For instance, let's say you've offering a discount to people who have been customers longer than five years AND have total orders of more than 1,000 dollars.  While you could write that as nested if statements:

if ( yearsAsCustomer > 5 ) {
    if ( totalOrders > 1000 ) {
        discountPercent = 1;
    }
}

(Note, I never said it was a GOOD discount)

You can simplify this to:

if ( yearsAsCustomer > 5 && totalOrders > 1000 ) {
    discountPercent = 1;
}

The '&&' operator joins two boolean values into one, and gives back true if and only if both of the values are true.

Boolean logic is generally summed up in a table like this:


OperatorValue1Value2Result
&&truetruetrue
&&falsetruefalse
&&truefalsefalse
&&falsefalsefalse


Note that last line:  && does NOT a check that both values are the same, it wants both values to be true before it gives up a true value.

The other operators are OR (||) and EQUALS (==).


OperatorValue1Value2Result
||truetruetrue
||falsetruetrue
||truefalsetrue
||falsefalsefalse

The OR operator is friendly.  As long as one of the operands is true, it gives you true.

OperatorValue1Value2Result
==truetruetrue
==falsetruefalse
==truefalsefalse
==falsefalsetrue
I think this one should be rather easy to understand.  If both operands have the same value, you get back that value.  Equals is a bit of a special case though, because you can use it with non-boolean operands as well.   (5 == 5) evaluates to true, as does (true == true).

So technically, you can do this (although my compiler warns me that I'm being silly when I do it, it reluctantly compiles and this can be run:

if ((5==5) == (true == true)) {
    System.out.println("Imagine that");
}

Note my use of parentheses to prioritize expressions.  I wanted to be absolutely sure that 5==5 and true == true both evaluated first, and I didn't want it to look like I was comparing 5 == true.  Now, the compiler follows standard rules for prioritizing mathematical operations, but extra parentheses can be very useful for we poor humans.

Expressions with booleans can be nested arbitrarily deep, although once you've got more than a few terms, they can be a bit difficult to work out.  Try to always give some thought to the next poor sod who has to modify your code, especially if that poor sod might be you again.

if ((isACustomer && (years > 10 || (years > 5 && sales > 1000))) || runningSpecialIncentives) {

Might be logically correct, and work just fine.  But do you want to add another condition to it first thing in the morning before you've had a cup of coffee?  Do you want to test it when someone is breathing down your neck?  This is probably a candidate for breaking up.  You can always create new booleans to act as placeholders:

boolean meetsQuotas = years > 10 || (years > 5 && sales > 1000);

Which would give the more readable:

if ((isACustomer && meetsQuotas) || runningSpecialIncentives ) {

Not only is it more readable as code, it almost makes sense as English.

The final boolean operator is !

No, that wasn't an expression of surprise.  The exclamation point is the 'NOT' operator.  It turns around the sense of any boolean expression, turning true into false and false into true.  Unlike the others I discussed above, which are binary operators (they work with two values), ! is a unary operator.  

!false == true

and

!true == false

So you can write:

if ( ! meetsQuotas && specialIncentives ) {
    System.out.println("We're giving a discount due to the special incentives program, but this guy is a cheapskate.");

That's about all I have to say about booleans for now.  Learn them, use them, love them.

No comments:

Post a Comment