-
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
60: Practice Exercise: Building a Robust Input Validator
Alright, we've talked about the Scanner class before, but in the real world, users are unpredictable. They'll type "twenty" when you asked for 20, or they'll leave the field blank, or they'll try to enter -500 as their birth year. If we aren't careful, our programs don't just fail—they crash spectacularly with an InputMismatchException.
I want to build a validator for a user's age. It sounds simple, but let's actually try to code it and see where it breaks.
The "Happy Path" that fails
My first instinct is usually to keep it lean. I'll just ask for the age and store it. Here is how I'd start:
Scanner sc = new Scanner(System.in);
System.out.print("Enter your age: ");
int age = sc.nextInt();
System.out.println("You are " + age + " years old.");
This works great if I type 25. But I'm the user now, and I'm feeling chaotic, so I'll type "twenty-five". Boom. InputMismatchException. The program dies instantly. That's not a robust application; that's a fragile one.
Falling into the Infinite Loop trap
Okay, so I need a loop. I'll use hasNextInt() to check if the input is actually a number before I try to grab it. This seems like the logical fix:
System.out.print("Enter your age: ");
while (!sc.hasNextInt()) {
System.out.println("That's not a number! Try again: ");
}
int age = sc.nextInt();
I run this, I type "abc", and then... nothing happens. Well, not nothing. My console is suddenly screaming "That's not a number! Try again: " a thousand times a second. I've created an infinite loop.
Why? Because hasNextInt() only checks the token; it doesn't consume it. The "abc" is still sitting there in the scanner's buffer. The loop checks it, sees it's not an int, prints the error, and then checks the exact same "abc" again. To fix this, I have to manually clear the "junk" out of the buffer.
while (!sc.hasNextInt()) {
System.out.println("That's not a number! Try again: ");
sc.next(); // This consumes the invalid token and clears the way
}
int age = sc.nextInt();
Now the loop actually terminates. We've solved the crashing and the looping, but we've only solved the type problem. We haven't solved the logic problem.
Correct type, impossible value
Now I run the program and enter -150. The program accepts it because -150 is technically an integer. But nobody is negative 150 years old. I need to wrap this in a layer of business logic. I don't want to just check for an integer; I want to check for a valid integer.
I'll wrap the whole thing in a do-while loop. This way, I can check both the type and the value in one go:
int age;
do {
System.out.print("Enter your age (0-120): ");
if (sc.hasNextInt()) {
age = sc.nextInt();
if (age < 0 || age > 120) {
System.out.println("Please enter a realistic age.");
}
} else {
System.out.println("Invalid input. Please use numbers.");
sc.next();
}
} while (age < 0 || age > 120 || !sc.hasNextInt()); // Wait, this logic is getting messy.
Looking at that while condition, I realize I'm repeating myself and it's becoming hard to read. When the logic gets this clunky, it's a signal that I should move the validation into its own method. I don't want to write this loop every single time I need a number in my app.
The Professional Approach: The Helper Method
I'll create a dedicated method that handles the "dirty work" of cleaning the buffer and validating the range. This keeps my main logic clean and makes the validator reusable.
public static int getValidInt(Scanner sc, String prompt, int min, int max) {
int value;
while (true) {
System.out.print(prompt);
if (sc.hasNextInt()) {
value = sc.nextInt();
if (value >= min && value <= max) {
return value; // Success! Exit the method and return the value
}
System.out.println("Error: Value must be between " + min + " and " + max + ".");
} else {
System.out.println("Error: Invalid input. Please enter a whole number.");
sc.next(); // Clear the buffer
}
}
}
Now, using this in my main program is a breeze:
int age = getValidInt(sc, "Enter your age: ", 0, 120);
int quantity = getValidInt(sc, "How many items? ", 1, 99);
By abstracting the "try-fail-clear-retry" cycle into a method, we've turned a crash-prone piece of code into a robust utility. We handled the exception (implicitly), managed the buffer, and enforced business rules, all while keeping the main flow of the program readable.
📋 Practical Task
Exercise: The Secure Bank Account Deposit Validator
You are building a banking module that allows users to deposit money into their account. You need to ensure that the deposit amount is valid before it is added to the balance.
Requirements:
- Create a method called
getValidDepositthat takes aScannerand aString prompt. - The method must return a
double. - The validator must reject:
- Non-numeric input (e.g., "ten dollars").
- Negative numbers (you can't deposit negative money).
- Amounts greater than 10,000.00 (bank policy limits single deposits).
- If the input is invalid, the program should print a specific error message explaining why it was rejected and prompt the user again.
- In your
mainmethod, callgetValidDepositand print the final accepted amount to the console.
There are no comments for now.