Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
11: Operator Precedence
I’ve spent a lot of time reviewing pull requests over the years, and one of the most frustrating bugs to spot is the "hidden" math error. It usually happens when a developer writes a complex logical or mathematical expression and assumes Java will evaluate it in the order they read it—from left to right. But Java, like most C-style languages, follows a strict hierarchy of operator precedence. If you aren't conscious of that hierarchy, you're basically gambling with your data.
The "Trust the Compiler" Gamble
Let's look at a real-world scenario: calculating the final price of an item after a discount and adding sales tax. Imagine you have a subtotal, a discount amount, and a taxRate. A naive approach might look something like this:
double finalPrice = subtotal - discount + subtotal - discount * taxRate;
At a glance, a tired developer might read this as "subtract the discount, then add the tax on the remaining amount." But the compiler doesn't read; it parses. Because multiplication (*) has higher precedence than addition (+) or subtraction (-), Java calculates discount * taxRate first. Then it performs the subtractions and additions from left to right. You end up subtracting a tiny fraction of the discount rather than applying the tax to the discounted total. It's a subtle bug that won't throw an exception; it'll just give you the wrong number, and you might not notice it until the accounting department starts calling you.
Explicit Intent with Parentheses
The better way—the way I expect to see in any professional codebase—is to use parentheses to dictate exactly how the expression should be evaluated. I don't care if you've memorized the precedence table perfectly. I want to see your intent on the screen so I don't have to mentally simulate the JVM's order of operations just to understand your logic.
double discountedPrice = subtotal - discount;
double finalPrice = discountedPrice + (discountedPrice * taxRate);
Or, if you prefer a single line:
double finalPrice = (subtotal - discount) * (1 + taxRate);
By wrapping subtotal - discount in parentheses, you force that operation to happen first. Now the multiplication applies to the actual discounted amount. The trade-off here is a few extra keystrokes, but the gain is massive. You've eliminated ambiguity. When you're working on a team, "clever" code that relies on implicit precedence is a liability. "Obvious" code that uses parentheses is an asset.
This applies to boolean logic too. The && (AND) operator has higher precedence than || (OR). If you're mixing them in a complex if statement without parentheses, you're asking for a logic leak. My rule of thumb is simple: if an expression uses more than one type of operator, wrap the logical groupings in parentheses. It makes the code self-documenting and saves you from a very embarrassing debugging session.
📋 Practical Task
Debugging the High-Score Bonus Calculation
You are working on a game where the player's final score is calculated based on their base score, a flat bonus, and a multiplier for "perfect play." However, the current implementation is buggy: the multiplier is only being applied to the bonus, not the entire score.
The Buggy Code:
int baseScore = 1000;
int bonus = 200;
int multiplier = 2;
// This is currently resulting in 1200, but it should be 2400
int finalScore = baseScore + bonus * multiplier;
Your Task: Rewrite the finalScore calculation using parentheses to ensure the baseScore and bonus are summed together before the multiplier is applied. Then, test it with a System.out.println to verify the result is 2400.
There are no comments for now.