-
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
283: Practice Exercise: Building a Contact Management CLI
How should I organize the Contact data so it's easy to manage?
When you're building something like this, resist the urge to just use a bunch of parallel arrays—like one for names and one for phone numbers. That's a recipe for a headache the moment you try to sort or delete a record. Instead, create a dedicated Contact class. It keeps the data bundled together as a single object, which makes your list much easier to handle.
public class Contact {
private String name;
private String phoneNumber;
public Contact(String name, String phoneNumber) {
this.name = name;
this.phoneNumber = phoneNumber;
}
public String getName() { return name; }
public String getPhoneNumber() { return phoneNumber; }
@Override
public String toString() {
return "Name: " + name + " | Phone: " + phoneNumber;
}
}
Once you have this, you can just use an ArrayList<Contact> to store everything. It's flexible, and since we're building a CLI, the performance overhead of an ArrayList is negligible compared to the convenience it gives you.
What's the best way to handle the main menu loop?
I've seen a lot of beginners write massive, nested if-else chains inside their main method. It becomes unreadable fast. The cleaner approach is a while loop combined with a switch statement. This separates the "navigation" of your app from the "logic" of adding or removing contacts.
boolean running = true;
while (running) {
System.out.println("\n1. Add Contact\n2. View All\n3. Search\n4. Exit");
int choice = scanner.nextInt();
scanner.nextLine(); // Consume the leftover newline!
switch (choice) {
case 1 -> addContact();
case 2 -> listContacts();
case 3 -> searchContact();
case 4 -> running = false;
default -> System.out.println("Invalid option, try again.");
}
}
Notice that scanner.nextLine() after nextInt()? That's a crucial detail. If you forget it, your next call to read a name will capture the "Enter" key from the previous input and skip right past your prompt. It's a classic Java Scanner quirk that trips everyone up at least once.
How do I implement a "search" feature efficiently?
Since we're using an ArrayList, the simplest way to find a contact is to iterate through the list. However, if you want to write this like a pro, use Java Streams. It allows you to filter the list in a single, readable line of code rather than writing a clunky for loop with a bunch of boolean flags.
public void searchContact(String targetName) {
contacts.stream()
.filter(c -> c.getName().equalsIgnoreCase(targetName))
.findFirst()
.ifPresentOrElse(
c -> System.out.println("Found: " + c),
() -> System.out.println("Contact not found.")
);
}
Using equalsIgnoreCase is a small touch, but it makes the app feel much more polished. Users hate it when "John" and "john" are treated as two different people.
Should I worry about saving this data to a file yet?
For this specific exercise, keep it in memory. Your goal here is to master the interaction between your objects, the list, and the user input. Adding file I/O (Input/Output) introduces a whole new set of exceptions you'll have to catch, which can distract you from the core logic of the management system.
Once you have the CLI working perfectly—meaning you can add, view, and search without the program crashing—then you can look into PrintWriter or Files.write to persist that data to a .txt or .csv file. One step at a time.
📋 Practical Task
Exercise: Implementing the Contact Deletion Feature
Your Contact Management CLI is almost complete, but it's missing a way to remove contacts. Your task is to implement a deleteContact method and integrate it into the main menu loop.
- Modify the
ContactManagerclass to include a method that takes a contact name as a string. - The method should search for the contact; if found, remove it from the
ArrayListand print a confirmation message. - If the contact doesn't exist, notify the user that the name was not found.
- Add a new option ("5. Delete Contact") to your
switchstatement in the main menu loop to trigger this functionality.
Bonus Challenge: Implement the deletion using removeIf() to see how it differs from the stream-based search approach.
There are no comments for now.