Programming Assignment 2
A Simple Address Book
Example Implementation
/** * Implementation of Assignment 2: A simple address book. * * @author Cheng, Jade * @assignment CSCI 2912 Assignment 2 * @date Feb, 26, 2012 */ import java.util.ArrayList; import java.util.NoSuchElementException; import java.util.Scanner; /** * Implementation of Assignment 2: A simple address book. */ public final class ChengJade2 { /** * Adds a contact to the specified {@link AddressBook}. * * @param book The {@link AddressBook} to which the contact is added. * @param scanner The scanner reading from standard input. * @throws NoSuchElementException Thrown if standard input is closed. */ private static void add(final AddressBook book, final Scanner scanner) { assert null != book; assert null != scanner; // Prompt for the name and phone number; then create a contact // and add it to the address book. final String name = prompt(scanner, " NAME ---> "); final String phone = prompt(scanner, " PHONE --> "); final Contact contact = new Contact(name, phone); book.add(contact); // Print some information about what was added. System.out.println(); System.out.print("Added "); System.out.println(contact); System.out.println(); } /** * Finds contacts in the specified {@link AddressBook}. * * @param book The {@link AddressBook} through which contacts are searched. * @param scanner The scanner reading from standard input. * @throws NoSuchElementException Thrown if standard input is closed. */ private static void find(final AddressBook book, final Scanner scanner) { assert null != book; assert null != scanner; // Prompt for what to find; then find the contacts. final String needle = prompt(scanner, " WHAT --> "); final ArrayList<Contact> contacts = book.find(needle); // Print some information about what was found. if (!contacts.isEmpty()) System.out.println(); for (final Contact contact : contacts) System.out.println(contact); System.out.println(); System.out.print("Number of contacts found: "); System.out.println(contacts.size()); System.out.println(); } /** * The main entry point of the program. * * @param args The command-line arguments. */ public static void main(final String[] args) { assert null != args; // Create a new address book. final AddressBook book = new AddressBook(); // Read commands from standard input. final Scanner scanner = new Scanner(System.in); // Logic within this loop will determine the end case. while (true) { // Print a menu of available commands. System.out.println(" ~ Address Book Menu ~"); System.out.println("+-------------------------+"); System.out.println(" ADD Adds a contact"); System.out.println(" FIND Finds contacts"); System.out.println(" PRINT Prints contacts"); System.out.println(" QUIT Quits"); System.out.println("+-------------------------+"); System.out.println(); // Check if standard input is closed. try { // Get a command from the user. final String command = prompt(scanner, "--> "); // Add, find, print, quit, or process an invalid command. if ("add".equalsIgnoreCase(command)) add(book, scanner); else if ("find".equalsIgnoreCase(command)) find(book, scanner); else if ("print".equalsIgnoreCase(command)) print(book); else if ("quit".equalsIgnoreCase(command)) return; else System.out.println("\nInvalid command.\n"); } catch (NoSuchElementException e) { // If the user closes standard input, terminate without // displaying an error. break; } } } /** * Prints the {@link AddressBook} instance. * * @param book The {@link AddressBook} to print. */ private static void print(final AddressBook book) { assert null != book; System.out.println(); System.out.println(book); } /** * Prompts the user for a string. * * @param scanner The scanner reading standard input. * @param message The message to display before the prompt. * @return The string entered by the user. * @throws NoSuchElementException Thrown if standard input is closed. */ private static String prompt(final Scanner scanner, final String message) { assert null != scanner; assert null != message; // Logic within this loop will determine the end case. while (true) { // Print the message and flush standard output. System.out.print(message); System.out.flush(); // If the next line from the scanner has some length, return it; // otherwise, iterate. final String line = scanner.nextLine().trim(); if (!line.isEmpty()) return line; } } } /** * A simple address book that manages a collection of {@link Contact} instances. */ final class AddressBook { /** The list of {@link Contact} instances. */ private final ArrayList<Contact> contacts = new ArrayList<>(); /** * Adds an {@link Contact} to this instance. * * @param contact The {@link Contact} to add to this instance. */ public void add(final Contact contact) { assert null != contact; this.contacts.add(contact); } /** * Finds a list of {@link Contact} instances that match the specified text. * * @param needle The text to find. * @return A list of {@link Contact} instances that match the specified * text. */ public ArrayList<Contact> find(final String needle) { assert null != needle; assert !needle.isEmpty(); // Put the text in lower case; the match method expects this. final String needleLowerCase = needle.toLowerCase(); // Create a new list of contacts. final ArrayList<Contact> list = new ArrayList<>(); // Loop over every item in this instance; if the item matches the text, // then add it to the list. for (final Contact item : this.contacts) if (item.match(needleLowerCase)) list.add(item); // Return the list of contacts that match the specified text. return list; } @Override public String toString() { // Build a string into this instance. final StringBuilder builder = new StringBuilder(); // Add every contact in this instance. for (final Contact contact : this.contacts) builder.append(String.format("%s\n", contact)); // Also write the number of contacts. if (!this.contacts.isEmpty()) builder.append('\n'); builder.append("Number of contacts: "); builder.append(this.contacts.size()); builder.append('\n'); // Return the string. return builder.toString(); } } /** * An immutable class that contains information about a contact in an * {@link AddressBook} instance. */ final class Contact { /** The name associated with this instance. */ public final String name; /** The phone number associated with this instance. */ public final String phone; /** * Initializes a new instance of the {@link Contact} class. * * @param name The name associated with this instance. * @param phone The phone number associated with this instance. */ public Contact(final String name, final String phone) { assert null != name; assert !name.isEmpty(); assert null != phone; assert !phone.isEmpty(); this.name = name; this.phone = phone; } /** * Returns <code>true</code> if this instance should be included in the * search results for the specified text; otherwise, <code>false</code>. * * @param needle The text for which the user is searching. The text should * be in all lower-case letters. * @return The value <code>true</code> if this instance should be included * in the search results for the specified text; otherwise, * <code>false</code>. */ public boolean match(final String needle) { assert null != needle; assert !needle.isEmpty(); assert needle.toLowerCase().equals(needle); // Return true if either name or phone match the specified value. Note it // is assumed the specified value is lower case. Also note it would be // more efficient to cache the lower-case versions of name and phone as // fields. return false || this.name.toLowerCase().contains(needle) || this.phone.toLowerCase().contains(needle); } @Override public String toString() { // Note it would be more efficient to cache this description as a field. return String.format("[%s; %s]", this.name, this.phone); } }