Boolean Operators in Java
Java's relational operators are ==, !=, <, >, <=, and >=.
Why a Comparison Can Surprise You
Comparisons are the foundation of decision making in a program. An if statement asks a question, and the answer decides which code runs. In Java, the question is usually written with a relational operator such as < or ==, or with a boolean operator such as && that combines several questions. Most comparisons behave the way you would expect, but some do not. Two cases need special care: String objects and the special value Double.NaN. This article builds the rules step by step so you can predict the result of a comparison before you run the code.
What do you think happens?
Two String variables hold the same text. What do you think a == comparison returns, and what does equals() return?
Reveal answer
== is false and equals() is true
The == operator checks the storage location of the objects, not their text. Two separate String objects with identical text are different objects, so == returns false. equals() compares the contents, so it returns true. This is explored in detail in the String section below.
The Six Relational Operators
Java's relational operators are ==, !=, <, >, <=, and >=. Each one compares two values and produces a boolean result, true or false. Together they cover equality, inequality, less than, greater than, less than or equal, and greater than or equal. Because each comparison produces a boolean value, you can use it directly as the condition of an if statement, store it in a boolean variable, or combine it with other conditions.
| Operator | Name | True when | Example with a = 5, b = 3 |
|---|---|---|---|
| == | equal to | both values are the same | a == b is false |
| != | not equal to | the values differ | a != b is true |
| < | less than | the left value is smaller | a < b is false |
| > | greater than | the left value is larger | a > b is true |
| <= | less than or equal to | the left value is smaller or the same | a <= b is false |
| >= | greater than or equal to | the left value is larger or the same | a >= b is true |
The six relational operators and what each one tests
false
true
false
true
false
true- Each println prints the boolean result of one comparison
- Reading the output in order matches the rows of the table above
Comparing Numbers and Characters
Relational operators can compare values of any numeric type, so you can mix the same comparison pattern across int, long, double, and other numeric values. They can also compare char values. When characters are compared with < and >, Java uses each character's numeric Unicode value. This ordering is not the same as dictionary order. Every uppercase letter has a smaller Unicode value than every lowercase letter, so an uppercase letter is always less than a lowercase one, regardless of the letter itself.
true
true
false- 'Z' has a smaller Unicode value than 'a', so the first comparison is true
- Any uppercase letter, including 'B', is less than any lowercase letter such as 'a'
- The third line is false because 'a' is larger than 'B' in Unicode order
Comparing Boolean Values
The operators == and != can compare boolean values, including the results of other comparisons. This means a comparison such as a > b can itself be one side of another comparison. The result is still a boolean value. Comparing with == to true or false is valid Java, but it is usually unnecessary, because a boolean value can already be used directly as a condition.
true
true
true- done holds the result of the comparison a > b, which is true
- Both done == true and done != false are true because done is true
- The last line compares one comparison result with another
Testing for Double.NaN
Double.NaN is a special double value that represents a result which is not a number. Ordinary relational comparisons cannot be trusted to detect it. The expression x == Double.NaN is false for every value of x, including when x is itself NaN, so you cannot test for NaN by comparing to Double.NaN. The reliable test is the method call Double.isNaN(x), which returns true when x is NaN and false otherwise.
false
true
false- The division 0.0 / 0.0 produces NaN
- The == comparison with
Double.NaNis false even though x holds NaN Double.isNaN(x)correctly reports that x is NaN
String Comparison and Object Storage
A String in Java is an object, and a variable of type String holds a reference to that object. The == operator checks where the objects are stored rather than comparing the text they contain. Two variables can hold different String objects that contain the same characters, and == will report them as unequal. To compare the contents of Strings, use equals() or compareTo() instead of a relational operator. equals() tells you whether two Strings contain the same text, and compareTo() tells you how two Strings are ordered.
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println(s1.compareTo(s2));- 1Line 1 creates the first String object and stores its reference in s1
- 2Line 2 creates a second String object with the same text and stores its reference in s2
- 3Line 3 asks whether the two references point to the same object, which they do not, so the result is false
- 4Line 4 asks whether the text is the same, which it is, so the result is true
- 5Line 5 asks how the two Strings are ordered; equal Strings give 0
- Two separate String objects are created, each holding the text hello
- == returns false because the variables refer to different objects
equals()returns true because the contents matchcompareTo()returns 0 because the two Strings are equal in ordering
false
true
0When you want to know whether two Strings contain the same text, call equals(). When you need an ordering, call compareTo(). Reserve == for checking whether two references point to the same object.
Combining Conditions with && and ||
In English, complicated conditions use the words and, or, and not. Java provides boolean operators for the same purpose. The operator && means both conditions must be true, and || means at least one condition may be true. Read a compound expression from left to right. An && expression is true only when both operands are true. An || expression is true when at least one operand is true. Use && when every condition must hold, and use || when any one of several conditions is enough.
A && B is true only when A is true and B is true; A || B is true when A is true or B is true or both are trueDeciding Whether a Condition Is True
Given age = 20, hasTicket = false, and isStaff = true, is the condition (age >= 18 && hasTicket) || isStaff true?
- 1Evaluate the first comparison
age >= 18 is 20 >= 18, which is true.
- 2Evaluate the && group
true &&
hasTicketbecomes true && false, which is false, because both operands must be true. - 3Evaluate the || with isStaff
false ||
isStaffbecomes false || true, which is true, because one true operand is enough. - 4State the result
The whole condition is true, and the decision came from
isStaff.
true
Short-Circuit Evaluation
The operators && and || use short-circuit evaluation. Java evaluates the left operand first. If that value already determines the result, the right operand is not evaluated at all. For && the result is already false when the left operand is false, so the right operand is skipped. For || the result is already true when the left operand is true, so the right operand is skipped. This matters in two ways: it saves work, and it prevents an invalid evaluation that would otherwise fail. Because the second operand may not run, it should not contain an action you depend on happening.
The source describes the expression x != 0 && y / x > 1. Read it from left to right. The first operand asks whether x is not zero. The second asks whether y divided by x is greater than 1. Because the first operand guards the division, the division happens only when x is not zero.
int x = 0;
int y = 10;
if (x != 0 && y / x > 1) {
System.out.println("big");
} else {
System.out.println("skipped");
}
boolean ok = (x == 0) || (y / x > 1);
System.out.println(ok);- 1Line 1 and 2 store the values 0 and 10
- 2The if condition evaluates x != 0 first, which is false
- 3Because the left operand of && is false, Java does not evaluate y / x > 1, so the else branch runs and skipped is printed
- 4Line 8 evaluates x == 0 first, which is true
- 5Because the left operand of || is true, Java skips y / x > 1 and ok becomes true
- x is zero, so x != 0 is false
- The && skips y / x entirely, so no division by zero occurs
- x == 0 is true, so the || skips y / x and ok is true
skipped
trueWhat do you think happens?
If the right operand of && divides by zero, will the program fail when the left operand is false?
Reveal answer
No, the right operand is skipped
When the left operand of && is false, short-circuit evaluation skips the right operand, so the division never executes.
Reversing a Value with the ! Operator
Use ! to reverse a boolean value. Applying ! turns true into false and false into true. Unlike && and ||, the ! operator does not combine two boolean values. It changes one boolean value, so it takes a single operand. Because it can be applied to any boolean expression, parentheses matter. The expression !(a && b) reverses the whole result of the && test, while !a && b reverses only a before combining it with b.
boolean test = (score > 50);
boolean result = test;With score equal to 70, test is true, so result is true
boolean test = (score > 50);
boolean result = !test;With the ! operator applied, result becomes false
false
true
false- !a reverses true to false
- a && b is false, so !(a && b) is true
- !a is false, so !a && b is false; the parentheses change the grouping
Mistakes Beginners Make with Boolean Operators
Common mistake Comparing String contents with ==
What it looks likeif (name == "Ada") used on a String read from inputWhy it fails== checks where the objects are stored, not the text they contain, so two Strings with identical text can compare as unequal.
Do this insteadUse name.equals("Ada") to compare contents.Common mistake Testing for NaN with ==
What it looks likeif (x == Double.NaN)Why it failsThe comparison with
Double.NaNis false even when x holds NaN.Do this insteadUse Double.isNaN(x).Common mistake Assuming alphabetical order for mixed-case characters
What it looks like'a' < 'B' expected to be trueWhy it failschar comparison uses Unicode values, and all uppercase letters come before all lowercase letters, so 'a' < 'B' is false.
Do this insteadRemember the Unicode ordering when you compare chars with < or >.
Common mistake Putting a risky action on the right of && or ||
What it looks likex != 0 && y / x > 1 where x could be zeroWhy it failsOnly the left operand is guaranteed to run; the right operand may be skipped and must not be needed for correctness of the guard.
Do this insteadPlace the safety check on the left, as in x != 0 && y / x > 1.
Common mistake Forgetting that ! applies to the nearest operand unless parentheses change the grouping
Given int p = 4 and int q = 9, and given boolean flag = true, write the result of each expression before running it: p < q, p == q, !flag, flag || (p > q), and flag && (p > q). Then explain which operand of the last two expressions determined the result.
Hints
- Compare each pair of numbers using the six relational operators
- For || the result is true as soon as one operand is true
- For && the result is false as soon as one operand is false
Locating the Cause of an Unexpected Result
When a compound condition gives an unexpected result, split it into its parts and evaluate each part separately, from left to right, using the grouping rules you have learned. Find the first sub-expression whose value you did not expect. Check whether a String was compared with == when equals() was needed, whether a NaN was tested with ==, whether a char comparison was assumed to be alphabetical, or whether a ! was applied to a larger expression than intended. Short-circuit evaluation also explains why a later part of an expression may never have run at all, so check whether the operand you expected to see was skipped.
A condition reads !(age < 18) || hasPermission. Explain whether the expression is true for a 16-year-old without permission, and state which operand decides the result for a 30-year-old with permission.
Hints
- Evaluate age < 18 first, then apply ! to that result
- Short-circuit evaluation applies to the || operator
Key Takeaways
- The six relational operators are ==, !=, <, >, <=, and >=, and each produces a boolean result that can be used as a condition.
- Compare String contents with
equals()orcompareTo(), because == checks the object storage location rather than the text, and test forDouble.NaNwithDouble.isNaN(x). - The && operator requires both operands to be true, || requires at least one, and ! reverses a single boolean value.
- Short-circuit evaluation skips the right operand of && when the left is false and of || when the left is true, which can prevent an unnecessary or invalid evaluation.
- To find the cause of an unexpected result, evaluate each sub-expression in grouping order and check the operand that was actually evaluated.