avatarUğur Taş

Summarize

Bitwise Operator vs Logical Operator in Java

How to benefit from lazy evaluation

Developers use logical operators to combine boolean expressions and control program flow based on their evaluation in programming languages. Two common logical operators in Java are the AND operator (& and &&) and the OR operator (| and ||). There are some key differences in how they work that developers should understand. Even though they may seem interchangeable at first glance, they are different.

If you don’t have a medium membership, you can use this link to reach the article without a paywall.

Bitwise Operators: & and |

Bitwise operators in Java operate on individual bits of integer types. Two primary bitwise operators are & (bitwise AND) and | (bitwise OR).

The Bitwise AND Operator (&)

The & operator compares each bit of its operands. If both bits are 1, it gives 1; otherwise, it returns 0.

int a = 12; // Binary: 1100
int b = 5;  // Binary: 0101
// Bitwise AND
int result = a & b; // Binary: 0100, Decimal: 4

The Bitwise OR Operator (|)

The | operator also compares each bit of its operands. If at least one bit is 1, it gives 1; otherwise, it returns 0.

int a = 12; // Binary: 1100
int b = 5;  // Binary: 0101
// Bitwise OR
int result = a | b; // Binary: 1101, Decimal: 13

Bitwise operators can also perform logical operations.

The AND Operator

The AND operator combines two boolean expressions and returns true only if both expressions evaluate to true. Java has two versions of the AND operator: Bitwise And (&) and logical And (&&).

The & Operator

The single & operator performs a boolean AND operation on the two surrounding expressions. However, it differs from && in that it does not short-circuit. This implies that both the left and right sub-expressions undergo evaluation, regardless of their boolean outcome.

    public static void main(String... args) {

        // Bitwise AND (&) operator will execute both of the expressions
        if(isEven(1) & isEven(3)) {
            // This code will not execute
        }
    }

    public static boolean isEven(int number) {
        System.out.println("Number to check " + number);
        return number % 2 == 0;
    }

Output of the above code is :

Number to check 1
Number to check 3

The && Operator

The && operator also performs a boolean AND operation. However, it uses short-circuit evaluation. This means that if the first sub-expression evaluates to false, the second sub-expression will not be evaluated at all.

    public static void main(String... args) {

        // Logical AND (&&) operator does lazy evaluation
        // So only the first statement will be executed
        if(isEven(5) && isEven(7)) {
            // This code will not execute
        }
    }

    public static boolean isEven(int number) {
        System.out.println("Number to check " + number);
        return number % 2 == 0;
    }

Output of the above code is :

Number to check 5

In this case, since isEven(5) is false, the overall expression can never equate to true. So the && short-circuits and does not bother evaluating isEven(7) at all.

This can provide performance optimizations in cases where the second sub-expression is computationally expensive. Short-circuit evaluation avoids unnecessary computations if the overall outcome is obvious from the first sub-expression.

The OR Operator

Similar to the AND operator, Java also has two versions of the OR operator: | and ||. They differ in their use of short-circuit evaluation.

The | Operator

The | operator performs a boolean OR operation without short-circuiting. This means that evaluation will take place for both of the expressions, even if the first one equates to true.

// Bitwise OR (|) operator will execute both of the expressions
if(isEven(2) | isEven(4)) {
    // This code will not execute
}

Output of the above code is :

Number to check 2
Number to check 4

Even though the overall expression is true because isEven(2) is true, isEven(4) will still be evaluated unnecessarily.

The || Operator

The || operator also performs a boolean OR, but uses short-circuit evaluation. This means that if the first sub-expression evaluates to true, the second one will not be evaluated.

// Logical OR (||) operator does lazy evaluation
// So only the first statement will be executed
if(isEven(6) || isEven(8)) {
    // This code will not execute
}

Output of the above code is :

Number to check 6

Because isEven(6) is true, the overall expression equates to true regardless of what isEven(8) evaluates to. So isEven(8) is not evaluated, avoiding unnecessary computation.

Usage Recommendations

Based on their behaviors, here are some recommendations on when to use which logical operator:

  • Use && over & when possible for performance gains from short-circuit evaluation. Only use & when you specifically need both sides evaluated.
  • Use || over | when possible, again for gains from short-circuit evaluation. Only use | when you specifically need both sub-expressions evaluated.
  • Avoid side effects in sub-expressions, since short-circuit operators will bypass evaluation.
  • Use & and | for bitwise boolean operations on integers.
  • Use && and || for evaluative boolean logic flow control.
  • !!!DO NOT USE BITWISE OPERATORS WITH NULL CHECK!!!
String text = null;
// This code will throw and exception 
// Because both of the expressions will be executed
if(text != null & text.length() > 1) {

}

Let’s look at some examples of using these operators effectively:

// Use && to avoid null check if the short-circuit will prevent exceptions
if (obj != null && obj.method() > 0) {
  // Do something
}

// Use || to short-circuit and avoid expensive operations
if (checkCache() || performExpensiveLookup() > 0) {
  // Do something
} 

// Use & for bitwise AND when needed 
int flags = FLAG_A & FLAG_B;

// Use | for bitwise OR when needed
int flags = FLAG_A | FLAG_B;

By understanding the different behaviors of & vs && and | vs ||, developers can write logical expressions that are both clean and performant. The short-circuit operators help avoid unnecessary computations and exceptions, while the non-short-circuit versions allow full control when required.

The logical operators in Java provide versatile options for boolean logic, with some key distinctions:

  • Bitwise operators (& and |) evaluate both sides unconditionally
  • Logical operators (&& and ||) use short-circuit evaluation and only evaluate the minimum needed
  • Logical operators (&& and ||) are best for most evaluative use cases
  • Bitwise operators (& and |) allow bitwise operations and full control when needed

By mastering these operators, developers can make good choices about which to use in different situations. Short-circuit versions will generally provide better performance, while non-short-circuit may be necessary for certain bitwise and low-level operations. Applying these ideas will lead to clean, efficient boolean logic control in Java code.

👏 Thank You for Reading!

👨‍💼 I appreciate your time and hope you found this story insightful. If you enjoyed it, don’t forget to show your appreciation by clapping 👏 for the hard work!

📰 Keep the Knowledge Flowing by Sharing the Article!

✍ Feel free to share your feedback or opinions about the story. Your input helps me improve and create more valuable content for you.

✌ Stay Connected! 🚀 For more engaging articles, make sure to follow me on social media:

🔍 Explore More! 📖 Dive into a treasure trove of knowledge at Codimis. There’s always more to learn, and we’re here to help you on your journey of discovery.

If you enjoyed this article, consider trying out the AI service I recommend. It provides the same performance and functions to ChatGPT Plus(GPT-4) but more cost-effective, at just $6/month (Special offer for $1/month). Click here to try ZAI.chat.

Java
Bitwise Operator
Logicaloperators
Lazy Evaluation
Short Circuit Evaluation
Recommended from ReadMedium