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
162: Code Review Habits for Java Projects
Code reviews aren't about catching syntax errors—the compiler does that for us. They're about mentorship, consistency, and preventing the "technical debt" that keeps you awake at 3:00 AM on a Tuesday. When I review a junior's PR, or when a senior tears into mine, we aren't looking for "correctness" in the mathematical sense; we're looking for maintainability.
To show you what I mean, let's build a small DiscountService. This service will decide how much of a discount to give a customer based on their membership tier. I'll write this as if I'm rushing to meet a deadline, and then I'll "review" my own code to show you the habits I actually use in production.
Writing the first draft of the DiscountService
Here is my initial implementation. It works. If you run it with a "GOLD" member, they get 20% off. Simple, right?
public class DiscountService {
public double calculateDiscount(User user, double totalAmount) {
if (user.getMembershipLevel().equals("GOLD")) {
return totalAmount * 0.20;
} else if (user.getMembershipLevel().equals("SILVER")) {
return totalAmount * 0.10;
}
return 0.0;
}
}
Now, if I were reviewing this in a GitHub PR, my first thought wouldn't be "this works," but "how easily can this break?"
Catching the obvious crash
Wait—I just spotted a classic mistake. Look at user.getMembershipLevel().equals("GOLD"). I've fallen into the "NullPointerException Trap." If getMembershipLevel() returns null, the whole application crashes. I've seen this happen in production more times than I care to admit.
A seasoned Java developer avoids this by putting the constant first. It's a small habit, but it's a lifesaver. Let's fix that immediately.
// Much safer: "GOLD" is never null, so this won't throw an NPE
if ("GOLD".equals(user.getMembershipLevel())) {
return totalAmount * 0.20;
}
Eliminating "Magic Strings" and Rigid Logic
Even with the null fix, this code is brittle. Those strings—"GOLD" and "SILVER"—are what we call "Magic Strings." If someone typos "GOLS" elsewhere in the app, the discount fails silently. In a real review, I'd insist on moving these to an Enum. It makes the code self-documenting and type-safe.
I'm also noticing that the logic is just a series of if-else blocks. If we add ten more membership levels, this method becomes a nightmare to read. I'll refactor this to use a Map or a switch expression (available in modern Java) to keep the mapping clean.
public enum MembershipLevel {
GOLD, SILVER, BRONZE, NONE
}
public class DiscountService {
private static final Map<MembershipLevel, Double> DISCOUNTS = Map.of(
MembershipLevel.GOLD, 0.20,
MembershipLevel.SILVER, 0.10,
MembershipLevel.BRONZE, 0.05
);
public double calculateDiscount(User user, double totalAmount) {
MembershipLevel level = user.getMembershipLevel();
double rate = DISCOUNTS.getOrDefault(level, 0.0);
return totalAmount * rate;
}
}
Reviewing for API Intent
The final habit is questioning the API design. Is calculateDiscount returning the amount *to be subtracted* or the *final price*? The name is slightly ambiguous. In a professional project, I'd ask the author to be explicit. Let's rename it to calculateDiscountAmount to remove any doubt.
I'd also check for final modifiers. In Java, if a variable shouldn't change, mark it final. It tells the next developer, "Don't touch this value," and helps the JVM optimize the code. Look at the final version below:
public class DiscountService {
private static final Map<MembershipLevel, Double> DISCOUNTS = Map.of(
MembershipLevel.GOLD, 0.20,
MembershipLevel.SILVER, 0.10,
MembershipLevel.BRONZE, 0.05
);
public double calculateDiscountAmount(final User user, final double totalAmount) {
final MembershipLevel level = user.getMembershipLevel();
final double rate = DISCOUNTS.getOrDefault(level, 0.0);
return totalAmount * rate;
}
}
The difference between the first version and the last isn't just "cleaner code"—it's the difference between a system that crashes on edge cases and one that is robust, scalable, and easy for a teammate to understand without needing a meeting to explain it.
📋 Practical Task
Refactoring the Legacy UserValidator
You have been assigned to review a piece of legacy code in the UserValidator class. The current implementation is functional but violates several of the code review habits discussed in this lesson. It is prone to NullPointerException, uses magic strings, and lacks finality.
public class UserValidator {
public boolean isValid(User user) {
if (user.getRole().equals("ADMIN")) {
return user.getPermissions() != null;
}
if (user.getRole().equals("USER")) {
return user.getEmail() != null && user.getEmail().contains("@");
}
return false;
}
}
Your Task: Refactor this class to implement professional Java habits. You must:
- Replace the "Magic Strings" ("ADMIN", "USER") with a
RoleEnum. - Fix the potential
NullPointerExceptionwhen checking the role. - Apply the
finalkeyword to parameters and local variables that do not change. - Improve the method's robustness (e.g., handling a null
userobject at the start of the method).
There are no comments for now.