Java Boolean Logic
Boolean Logic in Java
Boolean Logic in Java
The Java programming language supports Boolean values as a primitive data type named boolean
. It also includes Boolean keywords true
and false
to represent each possible value. Notice that these keywords are not capitalized, unlike some other programming languages.
To declare a Boolean variable in Java, we can use the same basic syntax that we used for other variable types:
boolean b;
We can then assign a value of true
or false
to that variable:
boolean b;
b = true;
We can also combine the two statements into a single statement:
boolean b = false;
Java also supports most of the Boolean operators discussed earlier in the chapter. Let’s look at a few examples.
!
In Java, the not operator is the exclamation point !
, placed before a Boolean value. It will invert the value of the variable, changing true
to false
and false
to true
.
Here is a quick example:
boolean b = true;
boolean c = !b;
System.out.println(c); // false
This program will output false
, which is the inverted value of b
.
&&
To perform the and operation, Java uses two ampersands &&
placed between Boolean values. Let’s look at an example:
boolean a = true;
boolean b = true;
boolean c = false;
System.out.println(a && b); // true
System.out.println(b && c); // false
This program will output true
on the first line, since we know that both a
and b
are true
. On the second line, it will output false
, since c
is false
, even though b
is true
.
||
Similarly, Java uses two vertical pipes ||
to represent the or operator. On most keyboards, we can find that key above the Enter key. Here’s an example of how it can be used in code:
boolean a = true;
boolean b = false;
boolean c = false;
System.out.println(a || b); // true
System.out.println(b || c); // false
Once again, this program will output true
on the first line, since a
is true
, even though b
is false
. On the second line, it will output false
, since both b
and c
are false
.
According to the Java documentation, Java also supports using a single &
for and, and a single |
for or when dealing with Boolean values. Why shouldn’t we just use these operators instead?
It turns out that there is a fundamental difference in how the Java compiler handles these operators. The double-character operators &&
and ||
are called logical operators and short-circuit operators. In some scenarios, the system only needs to look at the first value in the statement to determine the result. For example, the statement x || (y || z)
will always be true
if x
is true
, without needing to consider the values in y
or z
. The same works for x && (y && z)
when x
is false
, which will result in the entire statement being false
. For larger Boolean expressions, the use of these short-circuit operators can make our programs run much faster and more efficiently.
The single-character operators &
and |
bit-wise comparison operators and are not short-circuited. So, the system will evaluate each part of the statement before determining the outcome. For boolean values, the bit-wise operators will evaluate to the same answer as the logical operators.
However you should not use them for this purpose. First, because they will slow your programs executions. Second, because it will obscure your intent to future readers of your program. At some distance point in the future, a programmer will see you used a bit-wise operator, assume there must be a reason you did not using the logical one, and lose valuable time trying to figure out why you did not use the logical operator.
You can read more about Bitwise Operations on Wikipedia. We will not use them in this course.
Java does not support a logical exclusive or, but we can build a similar statement using other operators.
boolean a = true;
boolean b = false;
boolean c = true;
System.out.println((a || b) && !(a && b)); // true
System.out.println((a || c) && !(a && c)); // false
In this example, the first line will be true
, since a
is true
but b
is false
. However, the second line will output false
, since both a
and c
are true
.
We can also use the comparison operators ==
, !=
, <
, <=
, >
, and >=
to compare variables containing numbers, which will result in a Boolean value. Here’s an example showing those operators in action:
int x = 1;
int y = 2;
double z = 3.0;
System.out.println(x < y); // true
System.out.println(x <= 1); // true
System.out.println(x > 2); // false
System.out.println(x >= z); // false
System.out.println(x == 1); // true
System.out.println(x != y); // true
As we can see, each of the comparison operators works just as we’d expect, and outputs a Boolean value of either true
or false
, depending on the result of the comparison.
Like most high level languages, Java does not allow the chaining of comparison operators. 10 <= x <=20
, which is a pretty standard math notation for x is between 10 and 20, will not work. First the compiler will evaluate 10 <=x as a boolean, then it will throw a fit about trying to compare a boolean
and and int
for the <= 20
part.
You will need to write this as 10 <= x && x <= 20
.
Now that we’ve introduced some additional operators, we should also see where they fit in with the other operators in Java. Here is an updated list giving the appropriate operator precedence for Java, with new entries in bold:
++
& Decrement --
after variable*-
, Not !
, Increment ++
& Decrement --
before variable**
, Division /
, and Modulo %
+
, Subtraction -
<
, >
, <=
, >=
==
, !=
&&
||
=
, +=
, -=
, *=
, /=
, %=
Working with Boolean expressions in Java is the same as working with any other type of expression. So, we can use the same subgoals we learned in a previous chapter to help us evaluate and write new Boolean logic expressions. Here’s a quick review of those subgoals.
To analyze an expression involving variables and mathematical operators in code, here are some mental subgoals we can use:
First, we must determine whether the data type of the expression is compatible with the data type of the variable we want to store it in. In Java, we must be very careful to make sure we are only storing whole numbers in the integer data type, and floating point values in the double data type.
Next, we should look at the expression to determine if there are any prefixed operations that must occur first. In Java, for example, we could find a prefixed increment operator like ++x
, so we’ll need to update the value of x
before moving to the next step.
At this point, we can solve the arithmetic equation using the order of operations for our language. This simply involves the process of substituting values for variables and performing the requested operations. However, once again we must be careful to make sure that the operands provided to each operator are valid and produce the correct data type. The example we saw earlier for handling a large equation showed us a great way to work through this process.
Once we’ve solved the arithmetic equation, we should be left with a variable on the left side of the equals sign and a single value on the right side. So, once again, we should confirm that the value on the right can be stored in the data type of the variable on the left.
Finally, if the original expression included any postfix operations, such as a postfixed decrement like x--
in Java, we’ll need to update the value of x
before moving on to the next line.
Here are the subgoals for writing a new expression:
The first step is to determine which part of the problem statement will be represented by a variable. Sometimes this is obvious, and other times it is not. This may be a new variable that we are creating, or it could be an update to an existing variable.
Once we’ve found a variable to work with, we must also determine the variable’s name and data type. Once again, this may be obviously found in the problem statement, but other times we must think a bit more about what type of data will be stored in the variable. Of course, we should also make sure the variable has a descriptive and memorable name if we are creating a new one.
Now that we’ve isolated our variable, we must build an arithmetic equation and operators required to produce the desired value. This may involve using additional variables in our equations as well.
Once we have our arithmetic equation, we can then build the overall expression. This usually consists of three parts: the variable on the left, an assignment operator in the middle, and the arithmetic equation on the right.
Finally, once we’ve constructed the overall expression, we should check and make sure that all operators and operands are compatible. This means making sure we are using the correct operators and conversions to produce the desired data type as output.
Let’s look at an example to see how we can use these steps to create an evaluate a Boolean expression to match a problem statement.
Consider the following problem statement:
Create a program to determine if a user has exactly 5 apples, or fewer oranges than bananas. If so, the program should output
true
, otherwise it should outputfalse
. For this program, assume the user has 4 apples, 6 oranges, and 8 bananas.
Let’s go through the subgoal steps above to write this program.
First, we can read the problem statement to see that we should have at least three variables - one for apples, oranges, and bananas. In addition, we may need a fourth variable to store the Boolean result that we’d like to output.
The second subgoal is pretty straightforward. We can easily create three integer variables, apples
, oranges
, and bananas
for each type of fruit, and a Boolean variable result
to store the result of our Boolean logic expression.
Next, we’ll need to build our arithmetic equation. For this program, we need to determine if the user has exactly 5 apples, or apples == 5
. We also need to know if the user has fewer oranges than bananas, or oranges < bananas
. Finally, we can put those together using the or operator as indicated in the problem statement, so the final equation would be (apples == 5) || (oranges < bananas)
.
Now we can build our program itself. Here’s one possible solution:
int apples = 4;
int oranges = 6;
int bananas = 8;
boolean result = (apples == 5) || (oranges < bananas);
System.out.println(result);
||
, we see that each side is a smaller expression that will result in a Boolean value, so the data type of each operand will be correct.Using subgoals makes it very easy to work through this process, one step at a time.