Concepts / Relational Operators in Java

Relational Operators in Java

Boolean operators form complicated conditions from boolean values.

  • Programming

Why Single Comparisons Are Not Enough

Programs make decisions by asking questions that have a true or false answer. Is the score high enough to pass? Is the user name empty? Is the price below the budget? In English we join these questions with the words and, or, and not. Java provides boolean operators for the same purpose. They combine or change boolean values so that a program can make a decision using more than one condition.

This article builds that toolkit in four parts: the relational operators that produce a boolean value from two values, the logical operators && and || that combine boolean values, the ! operator that reverses one, and the special cases where a comparison that looks correct does not behave the way you expect.

What do you think happens?

What does the following line print? System.out.println('Z' < 'a');

  • true

  • false

Reveal answer
Answer:

true

A char compares through its numeric Unicode value. The character 'Z' has a smaller numeric code than 'a', because all uppercase letters come before all lowercase letters. So 'Z' < 'a' is true, even though Z comes after a in the alphabet.

The Six Relational Operators

Definition

A relational operator compares two values and produces a boolean value, either true or false. Java's relational operators are ==, !=, <, >, <=, and >=.

OperatorTests whetherExampleResult
<the left value is less than the right value5 < 7true
<=the left value is less than or equal to the right value7 <= 7true
>the left value is greater than the right value5 > 7false
>=the left value is greater than or equal to the right value5 >= 7false
==the two values are equal5 == 7false
!=the two values are not equal5 != 7true

The six relational operators in Java, applied to the numbers 5 and 7

The operators are read from left to right. In each row, the left operand is compared with the right operand. Notice that == tests equality, not assignment. A single equals sign stores a value in a variable, while a double equals sign asks whether two values match. Relational operators can compare values of any numeric type, and they can also compare char values, which the next section covers.

Comparing Numbers and Characters

Relational operators work on numeric values of any numeric type. The following program applies all six operators to the same pair of int values. Before reading the output, try to predict each line.

Code walkthrough
public class NumericComparisons {
    public static void main(String[] args) {
        int a = 5;
        int b = 7;
        System.out.println(a < b);
        System.out.println(a <= b);
        System.out.println(a > b);
        System.out.println(a >= b);
        System.out.println(a == b);
        System.out.println(a != b);
    }
}
  1. 1
    a < b asks whether 5 is less than 7. It is, so the result is true.
  2. 2
    a <= b asks whether 5 is less than or equal to 7. The result is true.
  3. 3
    a > b asks whether 5 is greater than 7. It is not, so the result is false.
  4. 4
    a >= b asks whether 5 is greater than or equal to 7. The result is false.
  5. 5
    a == b asks whether 5 equals 7. The result is false.
  6. 6
    a != b asks whether 5 differs from 7. The result is true.
  • a and b hold the values 5 and 7
  • Each println prints the boolean result of one comparison
Output
true
true
false
false
false
true

A char value is compared through its numeric Unicode value, not through its position in the alphabet. This is why the ordering of characters can surprise a beginner. All uppercase letters come before all lowercase letters, so 'Z' is less than 'a', and 'A' is less than 'a'. Comparisons between characters that share the same case do follow alphabetical order, because their numeric codes increase through the alphabet.

java
Output
true
true
true

Combining Conditions with && and ||

The operator && (and) produces true only when both operands are true. The operator || (or) produces true when at least one operand is true. Each operand is itself a boolean value, often the result of a relational comparison. Because the operators combine boolean values, a single condition can test several facts at once.

aba && ba || b!a
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

Truth table for the operators &&, ||, and ! over every combination of two boolean inputs

Worked example

Deciding whether a value is in a range

A program should accept a temperature t only if it is at least 0 and less than 100. Write a condition that is true exactly when t is in that range, and decide the result for t = 25 and t = 100.

  1. 1
    Split the requirement into two tests

    The first test is t >= 0. The second test is t < 100. Both must hold, so the two tests are joined with &&.

  2. 2
    Write the combined condition

    The condition is t >= 0 && t < 100. Each side is a relational comparison that produces a boolean value, and && combines them.

  3. 3
    Evaluate for t = 25

    25 >= 0 is true. 25 < 100 is true. Both operands are true, so the complete result is true.

  4. 4
    Evaluate for t = 100

    100 >= 0 is true. 100 < 100 is false. One operand is false, so && produces false. The value 100 is outside the range.

Result

The condition t >= 0 && t < 100 is true for 25 and false for 100.

How Short-Circuit Evaluation Skips Work

Java evaluates && and || with short-circuit evaluation. Java reads the expression from left to right and stops as soon as the final result is known. For &&, once the left operand is false, the whole expression must be false, so Java does not evaluate the right operand. For ||, once the left operand is true, the whole expression must be true, so the right operand is again skipped. The second operand may therefore not be evaluated at all.

x != 0first operand of &&Result: falsereturned immediatelyResult: true or falsefrom the second operandy / x > 1second operand, skippedfalse, because x is 0true, only when x is not 0evaluated only on that path
When x is 0, does Java still evaluate y / x > 1, and what would that evaluation do?

This behavior is useful as a guard. The source's example reads the expression from left to right: the first operand asks whether x is not zero, and the second asks whether y divided by x is greater than 1. Because the first operand protects the division, the division happens only when x is not zero. If Java evaluated both operands unconditionally, a zero value of x would cause a divide-by-zero error with integer values.

Code walkthrough
public class ShortCircuitGuard {
    public static void main(String[] args) {
        int x = 0;
        int y = 10;
        if (x != 0 && y / x > 1) {
            System.out.println("Condition is true");
        } else {
            System.out.println("Condition is false");
        }
    }
}
  1. 1
    x != 0 is evaluated first. Because x is 0, the result is false.
  2. 2
    Since the left operand of && is false, the whole condition is false.
  3. 3
    Java skips y / x > 1 entirely, so no division by zero occurs and no exception is thrown.
  4. 4
    The else branch runs and prints Condition is false.
  • x is 0, so the first operand is false
  • The division y / x is never evaluated
Output
Condition is false

Reversing a Boolean Value with !

The ! operator reverses the value of a boolean. A true value becomes false, and a false value becomes true. Unlike && and ||, the ! operator does not combine two boolean values. It changes one boolean value. This makes it useful for asking the opposite question, such as whether a condition does not hold.

java
Output
true
true
true
Notes on the code
  • !done reverses the value false to true
  • !(5 > 7) reverses false to true
  • 5 > 3 && 2 > 4 is false, so ! turns it into true

Negating a compound condition changes each result. Because ! applies to the whole value it is given, the parentheses matter. The expression !(5 > 3 && 2 > 4) reverses the result of the entire && comparison, not just one side of it.

Finding the Cause of an Unexpected Result

When a compound condition produces an unexpected value, evaluate it in pieces. Find the grouping first: parentheses show which sub-expression is computed first, and the usual precedence of && over || decides the rest. Then compute each leaf comparison, then each combination, working toward the final result. The sub-result that determines the final value is the place to look.

||final result: true&&falsea > btrue!etruec != dfalseefalseleft operandright operandleft operandright operandoperand
With a = 5, b = 3, c = 2, d = 2, and e = false, which sub-result makes the whole expression true?

Trace the tree from the bottom up. a > b is true, and c != d is false. Combining them with && gives false, so the left side of || is false. The right side, !e, is true because e is false. The || then has a true operand, so the final result is true. The true result comes from !e, not from the && part, and that is the sub-result to inspect when the outcome surprises you.

Comparing Boolean Values with == and !=

The operators == and != can compare boolean values, including the results of other comparisons. This allows a program to check whether two conditions agree with each other. The comparison is itself a boolean expression, so its result can be combined with other operators.

java
Output
true
false
Notes on the code
  • 5 > 3 is true, so it matches p
  • p != true is false because the two values are equal

Comparing String Contents Correctly

String contents should be compared with equals() or compareTo(). The == operator does not compare the characters inside two strings. It checks object storage location, meaning whether two variables refer to the same String object. Two different String objects can contain identical text and still fail an == test.

s1reference to a StringobjectString object: Javafirst objects2reference to a StringobjectString object: Javasecond objectrefers torefers to
Why does s1 == s2 return false even though both variables hold the text Java?
Code walkthrough
public class StringComparison {
    public static void main(String[] args) {
        String s1 = new String("Java");
        String s2 = new String("Java");
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
        System.out.println(s1.compareTo(s2));
    }
}
  1. 1
    s1 == s2 checks whether s1 and s2 refer to the same object. They do not, so the result is false.
  2. 2
    s1.equals(s2) checks whether the contents match. Both contain Java, so the result is true.
  3. 3
    s1.compareTo(s2) compares the contents and returns 0, which indicates that the two strings are equal.
  • s1 and s2 refer to two different String objects with the same characters
  • compareTo returns 0 when the contents are equal
Output
false
true
0

Choose equals() when you need a yes or no answer about whether two strings have the same contents. Choose compareTo() when you also need the ordering of two strings. Use relational operators such as < and > for numeric values and char values, not for String contents.

Testing for Double.NaN

Double.NaN is a special floating-point value that stands for not a number. The source identifies Double.NaN as one of the two cases that require special care. A relational comparison with it does not behave like a comparison with an ordinary number, so x == Double.NaN cannot be used to detect a NaN value. The reliable test is Double.isNaN(x), which returns true when x holds NaN.

Code walkthrough
public class NaNCheck {
    public static void main(String[] args) {
        double x = Double.NaN;
        System.out.println(x == Double.NaN);
        System.out.println(Double.isNaN(x));
    }
}
  1. 1
    x == Double.NaN returns false, even though x is NaN. A NaN value is not equal to NaN in a relational comparison.
  2. 2
    Double.isNaN(x) examines x and returns true, which is the correct answer for this test.
  • x holds NaN
  • The relational operator gives the wrong answer for this test
  • Double.isNaN gives the correct answer
Output
false
true

Mistakes Beginners Make with Comparisons

  • Common mistake

    Comparing String contents with ==

    What it looks like
    if (name == "Ada") where name was read from user input
    Why it fails

    == checks whether two variables refer to the same object, not whether their characters match.

    Do this instead
    Use name.equals("Ada") to compare the contents.
  • Common mistake

    Using == to test for NaN

    What it looks like
    if (x == Double.NaN)
    Why it fails

    The comparison returns false even when x holds NaN, so the test never detects the value.

    Do this instead
    Use Double.isNaN(x).
  • Common mistake

    Placing the risky operation before its guard

    What it looks like
    if (y / x > 1 && x != 0)
    Why it fails

    The left operand is evaluated first, so the division runs even when x is 0.

    Do this instead

    Write x != 0 && y / x > 1 so the guard is evaluated first and short-circuit evaluation skips the division.

  • Common mistake

    Assuming char ordering is alphabetical across cases

    What it looks like
    'Z' < 'a' is expected to be false
    Why it fails

    A char compares through its numeric Unicode value, and all uppercase letters come before all lowercase letters.

    Do this instead

    Predict with the numeric codes, or compare characters of the same case when alphabetical order is needed.

  • Common mistake

    Forgetting that ! applies to the whole value it is given, so parentheses are needed when negating a compound condition

Practice: Predict Each Result

MEDIUM

Without running the code, predict the output of the following program, then check your answer. Write down the result of each comparison first, and then decide whether the if statement prints yes or no. int x = 0; int y = 8; boolean flag = false; System.out.println(x != 0 && y / x > 2); System.out.println(!flag || y > 10); System.out.println(Double.isNaN(0.0 / 0.0));

Hints
  • For the first line, the left operand x != 0 is false, so check whether the right operand is evaluated.
  • For the second line, !flag is true, and || needs only one true operand.
  • The expression 0.0 / 0.0 produces NaN in Java floating-point arithmetic.
MEDIUM

A program should print yes when a student's name equals Ada, ignoring nothing else, and the score is between 60 and 100 inclusive. Write a single if condition using equals(), relational operators, and &&. Put the test that cannot cause an error first where a guard is needed.

Hints
  • Use name.equals("Ada") for the string test, not ==.
  • Between 60 and 100 inclusive means score >= 60 and score <= 100.

Key Takeaways

  • Java's six relational operators, ==, !=, <, >, <=, and >=, compare values and produce a boolean result, and they work on numeric and char values, where char values compare through their Unicode numeric codes.
  • && is true only when both operands are true, || is true when at least one is true, and ! reverses a single boolean value.
  • Short-circuit evaluation stops && and || as soon as the result is known, so the second operand may be skipped; this lets a guard protect a risky operation such as division by zero.
  • Use equals() or compareTo() to compare String contents, because == checks object storage location, and use Double.isNaN(x) to test for NaN, because a relational comparison with Double.NaN does not detect it.
  • When a compound condition gives an unexpected result, evaluate its sub-expressions one at a time, from the innermost comparisons outward, to find which sub-result determines the final value.