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);
}
}