Robust applications must handle errors gracefully and persist data. In this codelab, you'll master Java's exception handling mechanisms and file I/O operations by building a real-world contact management system.
A Contact Management System featuring:
Exceptions are events that disrupt normal program flow. Let's understand how Java handles them.
Throwable
├── Error (unchecked - system errors)
│ ├── OutOfMemoryError
│ ├── StackOverflowError
│ └── ...
└── Exception
├── RuntimeException (unchecked)
│ ├── NullPointerException
│ ├── ArrayIndexOutOfBoundsException
│ ├── IllegalArgumentException
│ └── ...
└── Checked Exceptions
├── IOException
├── SQLException
├── ClassNotFoundException
└── ...
Checked Exceptions:
Unchecked Exceptions (RuntimeException):
NullPointerException:
public class NullPointerDemo {
public static void main(String[] args) {
String name = null;
System.out.println(name.length()); // NullPointerException!
}
}
ArrayIndexOutOfBoundsException:
public class ArrayDemo {
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
System.out.println(numbers[5]); // ArrayIndexOutOfBoundsException!
}
}
NumberFormatException:
public class ParseDemo {
public static void main(String[] args) {
String text = "abc";
int number = Integer.parseInt(text); // NumberFormatException!
}
}
The try-catch-finally block is the foundation of exception handling.
public class BasicExceptionHandling {
public static void main(String[] args) {
try {
int result = 10 / 0; // ArithmeticException
System.out.println("Result: " + result);
} catch (ArithmeticException e) {
System.out.println("Error: Cannot divide by zero!");
System.out.println("Exception message: " + e.getMessage());
}
System.out.println("Program continues...");
}
}
Output:
Error: Cannot divide by zero! Exception message: / by zero Program continues...
public class MultipleCatch {
public static void main(String[] args) {
String[] data = {"10", "20", "abc", "30"};
for (String item : data) {
try {
int number = Integer.parseInt(item);
int result = 100 / number;
System.out.println("Result: " + result);
} catch (NumberFormatException e) {
System.out.println("'" + item + "' is not a valid number");
} catch (ArithmeticException e) {
System.out.println("Cannot divide by zero for value: " + item);
}
}
}
}
Handle multiple exceptions in one catch block:
try {
// risky code
} catch (IOException | SQLException e) {
System.out.println("Database or file error: " + e.getMessage());
}
Always executes, whether exception occurs or not:
public class FinallyDemo {
public static void main(String[] args) {
java.util.Scanner scanner = null;
try {
scanner = new java.util.Scanner(System.in);
System.out.print("Enter a number: ");
int number = scanner.nextInt();
System.out.println("You entered: " + number);
} catch (Exception e) {
System.out.println("Invalid input!");
} finally {
if (scanner != null) {
scanner.close();
System.out.println("Scanner closed");
}
}
}
}
import java.io.*;
public class FileReadDemo {
public static void main(String[] args) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("data.txt"));
String line = reader.readLine();
System.out.println("First line: " + line);
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
System.out.println("Error closing file: " + e.getMessage());
}
}
}
}
Try-with-resources automatically closes resources, making code cleaner and safer.
try (ResourceType resource = new ResourceType()) {
// Use resource
} catch (Exception e) {
// Handle exception
}
// resource is automatically closed here
Old way (verbose):
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("file.txt"));
String line = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
New way (clean):
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
String line = reader.readLine();
System.out.println(line);
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
try (
FileReader fileReader = new FileReader("input.txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
FileWriter fileWriter = new FileWriter("output.txt");
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter)
) {
String line;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line.toUpperCase());
bufferedWriter.newLine();
}
} catch (IOException e) {
System.out.println("Error processing files: " + e.getMessage());
}
Any class implementing AutoCloseable or Closeable can be used with try-with-resources:
public class CustomResource implements AutoCloseable {
public CustomResource() {
System.out.println("Resource opened");
}
public void doWork() {
System.out.println("Working...");
}
@Override
public void close() {
System.out.println("Resource closed");
}
}
// Usage
try (CustomResource resource = new CustomResource()) {
resource.doWork();
}
The throws clause declares exceptions, while throw explicitly throws them.
Declare that a method might throw exceptions:
public class FileProcessor {
// Declares it might throw IOException
public String readFile(String filename) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader(filename));
String content = reader.readLine();
reader.close();
return content;
}
// Multiple exceptions
public void processData(String filename)
throws IOException, SQLException {
// Method implementation
}
}
Caller must handle or declare:
public class Main {
public static void main(String[] args) {
FileProcessor processor = new FileProcessor();
// Option 1: Handle the exception
try {
String content = processor.readFile("data.txt");
System.out.println(content);
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
// Option 2: Propagate the exception
public static void anotherMethod() throws IOException {
FileProcessor processor = new FileProcessor();
String content = processor.readFile("data.txt");
}
}
Explicitly throw an exception:
public class ValidationExample {
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException(
"Age must be between 0 and 150, got: " + age
);
}
this.age = age;
}
public void processPayment(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Amount must be positive");
}
if (amount > 10000) {
throw new IllegalStateException("Amount exceeds transaction limit");
}
// Process payment
}
private int age;
}
public void processFile(String filename) throws IOException {
try {
// File operations
BufferedReader reader = new BufferedReader(new FileReader(filename));
// ... processing ...
} catch (FileNotFoundException e) {
System.out.println("File not found: " + filename);
throw e; // Re-throw for caller to handle
} catch (IOException e) {
System.out.println("Error reading file");
throw new IOException("Failed to process: " + filename, e);
}
}
Create your own exception classes for domain-specific errors.
InvalidContactException.java:
public class InvalidContactException extends Exception {
// No-arg constructor
public InvalidContactException() {
super("Invalid contact data");
}
// Constructor with message
public InvalidContactException(String message) {
super(message);
}
// Constructor with message and cause
public InvalidContactException(String message, Throwable cause) {
super(message, cause);
}
// Constructor with cause
public InvalidContactException(Throwable cause) {
super(cause);
}
}
FileOperationException.java:
public class FileOperationException extends Exception {
private String filename;
private String operation;
public FileOperationException(String filename, String operation) {
super("Failed to " + operation + " file: " + filename);
this.filename = filename;
this.operation = operation;
}
public FileOperationException(String filename, String operation, Throwable cause) {
super("Failed to " + operation + " file: " + filename, cause);
this.filename = filename;
this.operation = operation;
}
public String getFilename() {
return filename;
}
public String getOperation() {
return operation;
}
}
ContactNotFoundException.java:
public class ContactNotFoundException extends RuntimeException {
private String contactId;
public ContactNotFoundException(String contactId) {
super("Contact not found: " + contactId);
this.contactId = contactId;
}
public String getContactId() {
return contactId;
}
}
public class ContactValidator {
public void validateEmail(String email) throws InvalidContactException {
if (email == null || email.trim().isEmpty()) {
throw new InvalidContactException("Email cannot be empty");
}
if (!email.contains("@")) {
throw new InvalidContactException("Invalid email format: " + email);
}
}
public void validatePhone(String phone) throws InvalidContactException {
if (phone == null || phone.trim().isEmpty()) {
throw new InvalidContactException("Phone cannot be empty");
}
// Remove non-digits
String digitsOnly = phone.replaceAll("[^0-9]", "");
if (digitsOnly.length() < 10) {
throw new InvalidContactException(
"Phone number must have at least 10 digits: " + phone
);
}
}
public void validateName(String name) throws InvalidContactException {
if (name == null || name.trim().isEmpty()) {
throw new InvalidContactException("Name cannot be empty");
}
if (name.length() < 2) {
throw new InvalidContactException("Name too short: " + name);
}
}
}
Let's explore Java's file I/O capabilities.
import java.io.File;
public class FileBasics {
public static void main(String[] args) {
File file = new File("contacts.csv");
// Check file properties
System.out.println("Exists: " + file.exists());
System.out.println("Is File: " + file.isFile());
System.out.println("Is Directory: " + file.isDirectory());
System.out.println("Can Read: " + file.canRead());
System.out.println("Can Write: " + file.canWrite());
System.out.println("Size: " + file.length() + " bytes");
System.out.println("Absolute Path: " + file.getAbsolutePath());
System.out.println("Name: " + file.getName());
// Create new file
try {
if (file.createNewFile()) {
System.out.println("File created: " + file.getName());
} else {
System.out.println("File already exists");
}
} catch (IOException e) {
System.out.println("Error creating file: " + e.getMessage());
}
// Delete file
if (file.delete()) {
System.out.println("File deleted");
}
}
}
import java.io.File;
public class DirectoryOperations {
public static void main(String[] args) {
// Create directory
File dir = new File("contacts_data");
if (dir.mkdir()) {
System.out.println("Directory created");
}
// Create nested directories
File nestedDir = new File("data/contacts/archive");
if (nestedDir.mkdirs()) {
System.out.println("Nested directories created");
}
// List files in directory
File currentDir = new File(".");
String[] files = currentDir.list();
System.out.println("Files in current directory:");
for (String filename : files) {
System.out.println(" " + filename);
}
// List with File objects
File[] fileObjects = currentDir.listFiles();
for (File f : fileObjects) {
String type = f.isDirectory() ? "[DIR]" : "[FILE]";
System.out.println(type + " " + f.getName());
}
}
}
Using FileWriter:
import java.io.*;
public class FileWriteDemo {
public static void main(String[] args) {
// Simple write
try (FileWriter writer = new FileWriter("output.txt")) {
writer.write("Hello, World!\n");
writer.write("This is a test.\n");
} catch (IOException e) {
System.out.println("Error writing file: " + e.getMessage());
}
// Append mode
try (FileWriter writer = new FileWriter("output.txt", true)) {
writer.write("Appended line\n");
} catch (IOException e) {
System.out.println("Error appending to file: " + e.getMessage());
}
}
}
Using BufferedWriter (More Efficient):
import java.io.*;
public class BufferedWriteDemo {
public static void main(String[] args) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter("data.txt"))) {
writer.write("Line 1");
writer.newLine(); // Platform-independent newline
writer.write("Line 2");
writer.newLine();
writer.write("Line 3");
writer.newLine();
// Write multiple lines
String[] lines = {"Line 4", "Line 5", "Line 6"};
for (String line : lines) {
writer.write(line);
writer.newLine();
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Using FileReader:
import java.io.*;
public class FileReadDemo {
public static void main(String[] args) {
try (FileReader reader = new FileReader("data.txt")) {
int character;
while ((character = reader.read()) != -1) {
System.out.print((char) character);
}
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
Using BufferedReader (More Efficient):
import java.io.*;
public class BufferedReadDemo {
public static void main(String[] args) {
try (BufferedReader reader = new BufferedReader(new FileReader("data.txt"))) {
String line;
int lineNumber = 1;
while ((line = reader.readLine()) != null) {
System.out.println(lineNumber + ": " + line);
lineNumber++;
}
} catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
}
}
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class CSVOperations {
public static void writeCSV(String filename, List<String[]> data) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
for (String[] row : data) {
writer.write(String.join(",", row));
writer.newLine();
}
}
}
public static List<String[]> readCSV(String filename) throws IOException {
List<String[]> data = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
String line;
while ((line = reader.readLine()) != null) {
String[] fields = line.split(",");
data.add(fields);
}
}
return data;
}
public static void main(String[] args) {
// Write CSV
List<String[]> contacts = new ArrayList<>();
contacts.add(new String[]{"Name", "Email", "Phone"});
contacts.add(new String[]{"Alice", "alice@email.com", "555-0001"});
contacts.add(new String[]{"Bob", "bob@email.com", "555-0002"});
try {
writeCSV("contacts.csv", contacts);
System.out.println("CSV file created");
// Read CSV
List<String[]> readData = readCSV("contacts.csv");
for (String[] row : readData) {
System.out.println(String.join(" | ", row));
}
} catch (IOException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Now let's build the complete Contact Management System integrating all concepts!
Contact.java:
public class Contact {
private String id;
private String name;
private String email;
private String phone;
private String address;
public Contact(String id, String name, String email, String phone, String address) {
this.id = id;
this.name = name;
this.email = email;
this.phone = phone;
this.address = address;
}
// Convert to CSV format
public String toCSV() {
return id + "," + name + "," + email + "," + phone + "," +
address.replace(",", ";"); // Replace commas in address
}
// Create from CSV format
public static Contact fromCSV(String csvLine) throws InvalidContactException {
String[] parts = csvLine.split(",");
if (parts.length != 5) {
throw new InvalidContactException("Invalid CSV format: " + csvLine);
}
return new Contact(
parts[0].trim(),
parts[1].trim(),
parts[2].trim(),
parts[3].trim(),
parts[4].trim().replace(";", ",")
);
}
@Override
public String toString() {
return "Contact{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", email='" + email + '\'' +
", phone='" + phone + '\'' +
", address='" + address + '\'' +
'}';
}
// Getters and setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public String getAddress() { return address; }
public void setAddress(String address) { this.address = address; }
}
ContactManager.java:
import java.io.*;
import java.util.*;
public class ContactManager {
private static final String DATA_FILE = "contacts.csv";
private Map<String, Contact> contacts;
private ContactValidator validator;
private int nextId;
public ContactManager() {
this.contacts = new HashMap<>();
this.validator = new ContactValidator();
this.nextId = 1;
loadContacts();
}
public void addContact(String name, String email, String phone, String address)
throws InvalidContactException, FileOperationException {
// Validate inputs
validator.validateName(name);
validator.validateEmail(email);
validator.validatePhone(phone);
// Create contact
String id = "C" + String.format("%04d", nextId++);
Contact contact = new Contact(id, name, email, phone, address);
// Add to map
contacts.put(id, contact);
// Save to file
saveContacts();
System.out.println("Contact added successfully: " + id);
}
public Contact getContact(String id) {
Contact contact = contacts.get(id);
if (contact == null) {
throw new ContactNotFoundException(id);
}
return contact;
}
public void updateContact(String id, String name, String email,
String phone, String address)
throws InvalidContactException, FileOperationException {
Contact contact = getContact(id);
// Validate new values
validator.validateName(name);
validator.validateEmail(email);
validator.validatePhone(phone);
// Update contact
contact.setName(name);
contact.setEmail(email);
contact.setPhone(phone);
contact.setAddress(address);
// Save to file
saveContacts();
System.out.println("Contact updated successfully: " + id);
}
public void deleteContact(String id) throws FileOperationException {
Contact contact = contacts.remove(id);
if (contact == null) {
throw new ContactNotFoundException(id);
}
// Save to file
saveContacts();
System.out.println("Contact deleted successfully: " + id);
}
public List<Contact> searchByName(String name) {
List<Contact> results = new ArrayList<>();
String searchLower = name.toLowerCase();
for (Contact contact : contacts.values()) {
if (contact.getName().toLowerCase().contains(searchLower)) {
results.add(contact);
}
}
return results;
}
public List<Contact> getAllContacts() {
return new ArrayList<>(contacts.values());
}
private void loadContacts() {
File file = new File(DATA_FILE);
if (!file.exists()) {
System.out.println("No existing contacts file. Starting fresh.");
return;
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
try {
Contact contact = Contact.fromCSV(line);
contacts.put(contact.getId(), contact);
// Update nextId
int contactNum = Integer.parseInt(contact.getId().substring(1));
if (contactNum >= nextId) {
nextId = contactNum + 1;
}
} catch (InvalidContactException e) {
System.out.println("Skipping invalid contact: " + e.getMessage());
}
}
System.out.println("Loaded " + contacts.size() + " contacts from file.");
} catch (FileNotFoundException e) {
System.out.println("Contacts file not found: " + e.getMessage());
} catch (IOException e) {
System.out.println("Error loading contacts: " + e.getMessage());
}
}
private void saveContacts() throws FileOperationException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(DATA_FILE))) {
for (Contact contact : contacts.values()) {
writer.write(contact.toCSV());
writer.newLine();
}
} catch (IOException e) {
throw new FileOperationException(DATA_FILE, "save", e);
}
}
public void exportToFile(String filename) throws FileOperationException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filename))) {
// Write header
writer.write("ID,Name,Email,Phone,Address");
writer.newLine();
// Write contacts
for (Contact contact : contacts.values()) {
writer.write(contact.toCSV());
writer.newLine();
}
System.out.println("Contacts exported to: " + filename);
} catch (IOException e) {
throw new FileOperationException(filename, "export", e);
}
}
public void displayAllContacts() {
if (contacts.isEmpty()) {
System.out.println("No contacts found.");
return;
}
System.out.println("\n=== ALL CONTACTS ===");
System.out.printf("%-8s %-20s %-30s %-15s %-30s%n",
"ID", "Name", "Email", "Phone", "Address");
System.out.println("-".repeat(100));
for (Contact contact : contacts.values()) {
System.out.printf("%-8s %-20s %-30s %-15s %-30s%n",
contact.getId(),
contact.getName(),
contact.getEmail(),
contact.getPhone(),
contact.getAddress()
);
}
}
}
ContactManagementApp.java:
import java.util.*;
public class ContactManagementApp {
private static ContactManager manager;
private static Scanner scanner;
public static void main(String[] args) {
manager = new ContactManager();
scanner = new Scanner(System.in);
System.out.println("========================================");
System.out.println(" CONTACT MANAGEMENT SYSTEM v1.0");
System.out.println("========================================\n");
boolean running = true;
while (running) {
printMenu();
int choice = getIntInput("Enter your choice: ");
System.out.println();
try {
switch (choice) {
case 1 -> addContact();
case 2 -> viewAllContacts();
case 3 -> searchContact();
case 4 -> updateContact();
case 5 -> deleteContact();
case 6 -> exportContacts();
case 7 -> {
System.out.println("Thank you for using Contact Manager!");
running = false;
}
default -> System.out.println("Invalid choice! Try again.");
}
} catch (ContactNotFoundException e) {
System.out.println("Error: " + e.getMessage());
} catch (InvalidContactException e) {
System.out.println("Validation Error: " + e.getMessage());
} catch (FileOperationException e) {
System.out.println("File Error: " + e.getMessage());
System.out.println("Operation: " + e.getOperation());
System.out.println("File: " + e.getFilename());
} catch (Exception e) {
System.out.println("Unexpected error: " + e.getMessage());
e.printStackTrace();
}
System.out.println();
}
scanner.close();
}
private static void printMenu() {
System.out.println("=== MENU ===");
System.out.println("1. Add Contact");
System.out.println("2. View All Contacts");
System.out.println("3. Search Contact");
System.out.println("4. Update Contact");
System.out.println("5. Delete Contact");
System.out.println("6. Export Contacts");
System.out.println("7. Exit");
}
private static void addContact() throws InvalidContactException, FileOperationException {
System.out.println("=== ADD NEW CONTACT ===");
String name = getStringInput("Name: ");
String email = getStringInput("Email: ");
String phone = getStringInput("Phone: ");
String address = getStringInput("Address: ");
manager.addContact(name, email, phone, address);
}
private static void viewAllContacts() {
manager.displayAllContacts();
}
private static void searchContact() {
System.out.println("=== SEARCH CONTACT ===");
String searchTerm = getStringInput("Enter name to search: ");
List<Contact> results = manager.searchByName(searchTerm);
if (results.isEmpty()) {
System.out.println("No contacts found matching: " + searchTerm);
} else {
System.out.println("\nFound " + results.size() + " contact(s):\n");
for (Contact contact : results) {
displayContact(contact);
System.out.println();
}
}
}
private static void updateContact() throws InvalidContactException, FileOperationException {
System.out.println("=== UPDATE CONTACT ===");
String id = getStringInput("Enter contact ID: ");
Contact contact = manager.getContact(id);
displayContact(contact);
System.out.println("\nEnter new values (press Enter to keep current):");
String name = getStringInput("Name [" + contact.getName() + "]: ");
if (name.isEmpty()) name = contact.getName();
String email = getStringInput("Email [" + contact.getEmail() + "]: ");
if (email.isEmpty()) email = contact.getEmail();
String phone = getStringInput("Phone [" + contact.getPhone() + "]: ");
if (phone.isEmpty()) phone = contact.getPhone();
String address = getStringInput("Address [" + contact.getAddress() + "]: ");
if (address.isEmpty()) address = contact.getAddress();
manager.updateContact(id, name, email, phone, address);
}
private static void deleteContact() throws FileOperationException {
System.out.println("=== DELETE CONTACT ===");
String id = getStringInput("Enter contact ID: ");
Contact contact = manager.getContact(id);
displayContact(contact);
String confirm = getStringInput("\nAre you sure you want to delete this contact? (yes/no): ");
if (confirm.equalsIgnoreCase("yes")) {
manager.deleteContact(id);
} else {
System.out.println("Deletion cancelled.");
}
}
private static void exportContacts() throws FileOperationException {
System.out.println("=== EXPORT CONTACTS ===");
String filename = getStringInput("Enter filename (e.g., backup.csv): ");
manager.exportToFile(filename);
}
private static void displayContact(Contact contact) {
System.out.println("ID: " + contact.getId());
System.out.println("Name: " + contact.getName());
System.out.println("Email: " + contact.getEmail());
System.out.println("Phone: " + contact.getPhone());
System.out.println("Address: " + contact.getAddress());
}
private static String getStringInput(String prompt) {
System.out.print(prompt);
return scanner.nextLine().trim();
}
private static int getIntInput(String prompt) {
System.out.print(prompt);
while (!scanner.hasNextInt()) {
scanner.next();
System.out.print("Invalid input. " + prompt);
}
int value = scanner.nextInt();
scanner.nextLine(); // Consume newline
return value;
}
}
Let's test our system with various scenarios including error cases.
1. Normal Operations:
1. Add contacts with valid data 2. View all contacts 3. Search by name 4. Update contact information 5. Delete a contact 6. Export to backup file
2. Validation Errors:
Try adding contacts with:
3. File Errors:
contacts.csv while app is running4. Not Found Errors:
======================================== CONTACT MANAGEMENT SYSTEM v1.0 ======================================== Loaded 0 contacts from file. === MENU === ... Enter your choice: 1 === ADD NEW CONTACT === Name: Alice Johnson Email: alice@email.com Phone: 555-1234-5678 Address: 123 Main St, City Contact added successfully: C0001 === MENU === ... Enter your choice: 1 Name: Bob Email: bob-email.com Phone: 123 Address: Test Validation Error: Invalid email format: bob-email.com === MENU === ... Enter your choice: 2 === ALL CONTACTS === ID Name Email Phone Address ---------------------------------------------------------------------------------------------------- C0001 Alice Johnson alice@email.com 555-1234-5678 123 Main St, City
Let's review best practices for exception handling and file operations.
1. Be Specific:
// Bad - too generic
catch (Exception e) {
e.printStackTrace();
}
// Good - specific handling
catch (FileNotFoundException e) {
System.out.println("File not found: " + e.getMessage());
} catch (IOException e) {
System.out.println("Error reading file: " + e.getMessage());
}
2. Don't Swallow Exceptions:
// Bad - silent failure
try {
riskyOperation();
} catch (Exception e) {
// Do nothing
}
// Good - at least log it
try {
riskyOperation();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
// Or use logging framework
}
3. Clean Up Resources:
// Always use try-with-resources for AutoCloseable
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
// Use reader
} // Automatically closed
4. Provide Context:
// Good - helpful error messages
throw new InvalidContactException(
"Invalid email format: " + email + ". Must contain @ symbol."
);
1. Check File Existence:
File file = new File("data.txt");
if (!file.exists()) {
file.createNewFile();
}
2. Use Absolute Paths When Possible:
File file = new File(System.getProperty("user.home") + "/data/contacts.csv");
3. Handle Large Files Efficiently:
// Read line by line, don't load entire file
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
processLine(line);
}
}
4. Use Proper Character Encoding:
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) {
writer.write("Content with special chars: üñíçödé");
}
Congratulations! 🎉 You've mastered exception handling and file I/O in Java!
Continue building on these skills:
Enhance your Contact Manager: