I've moved my main()
to the bottom of the code block in order to fit it all in one class for this submission. Is there a better way to do it?
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by Travis on 2/2/2015.
*/
public class CompanyEmployee {
//Strings
private String firstName;
private String lastName;
private String eMail;
private String birthDay;
private String phoneNumber;
//arraylist for CompanyEmployee objects
static ArrayList<CompanyEmployee> employees = new ArrayList<CompanyEmployee>();
static Scanner keyboard = new Scanner(System.in);
//email format
String regex = "^(.+)@(.+).(.+)$";
//Phone #
String regex1 = "^\\(?([0-9]{3})\\)?[-.\\s]?([0-9]{3})[-.\\s]?([0-9]{4})$";
//Uppercase/Lowercase
String regex2 = "^[a-zA-Z]+$";
//date format
String regex3 = "^(?:[0-9]{2})?[0-9]{2}/[0-3]?[0-9]/[0-3]?[0-9]$";
//Patterns using specific regex's.
Pattern pattern = Pattern.compile(regex);
Pattern pattern1 = Pattern.compile(regex1);
Pattern pattern2 = Pattern.compile(regex2);
Pattern pattern3 = Pattern.compile(regex3);
//default constructor, currently unused
public CompanyEmployee() throws InvalidEmployeeBirthday, InvalidEmployeeEmail, InvalidEmployeeName, InvalidEmployeePhoneNumber {
this.firstName = "";
this.lastName = "";
this.eMail = "";
this.birthDay = "1901/01/01";
this.phoneNumber = "000-000-0000";
}
/**
* constructor to create employees using firstname, lastname, birthday, email, and phonenumber
* Also throws several custom errors in based on regex values
*/
public CompanyEmployee(String firstName, String lastName, String eMail, String birthDay, String phoneNumber) throws InvalidEmployeeName,
InvalidEmployeeEmail, InvalidEmployeeBirthday, InvalidEmployeePhoneNumber {
//Matcher for first name
Matcher matcher = pattern2.matcher(firstName);
//Matcher for last name
Matcher matcher1 = pattern2.matcher(lastName);
//Matcher for email
Matcher matcher2 = pattern.matcher(eMail);
//Matcher for birthday
Matcher matcher3 = pattern3.matcher(birthDay);
//Matcher for phone number
Matcher matcher4 = pattern1.matcher(phoneNumber);
//if input passes regex, sets string firstName to string fn
if (matcher.matches()) {
this.firstName = firstName;
} else {
throw new InvalidEmployeeName("Please only use upper and lowercase letters a-Z.");
}
//if input passes regex, sets string lastName to string ln
if (matcher1.matches()) {
this.lastName = lastName;
} else {
throw new InvalidEmployeeName("Please only use upper and lowercase letters a-Z.");
}
//if input passes regex, sets string eMail to string em
if (matcher2.matches()) {
this.eMail = eMail;
} else {
throw new InvalidEmployeeEmail("Please use only a valid email addresses");
}
//if input passes regex, sets string birthDay to string b
if (matcher3.matches()) {
this.birthDay = birthDay;
} else {
throw new InvalidEmployeeBirthday("Please only use dates in the format of 'yyyy/dd/mm'");
}
//if input passes regex, sets string phoneNumber to string pn
if (matcher4.matches()) {
this.phoneNumber = phoneNumber;
} else {
throw new InvalidEmployeePhoneNumber("Please use only use phone #'s in the format of " +
"American phone numbers: 123-456-7890");
}
}
//creates a toString for the employee object.
public String toString() {
return "\nName: " + firstName + " " + lastName + "\nEmail: " + eMail + "\nBirthday: " +
"" + birthDay + "\nPhone #: " + phoneNumber + "\n";
}
//Create employees array
public static void createArray() {
CompanyEmployee e1 = null, e2 = null, e3 = null, e4 = null, e5 = null, e6 = null;
try {
e1 = new CompanyEmployee("Dave", "Smith", "[email protected]", "1969/04/20", "253-555-7894");
e2 = new CompanyEmployee("Lucy", "Carmon", "[email protected]", "1998/06/05", "253-555-1579");
e3 = new CompanyEmployee("George", "Jackson", "[email protected]", "1979/07/13", "253-555-1264");
e4 = new CompanyEmployee("Joy", "Vargas", "[email protected]", "1984/01/26", "253-555-3645");
e5 = new CompanyEmployee("Bob", "Velma", "[email protected]", "1993/04/15", "253-555-1256");
e6 = new CompanyEmployee("Sally", "Diego", "[email protected]", "1956/09/02", "253-555-5796");
} catch (Exception e) {
System.out.println(e.getMessage());
}
employees.add(e1);
employees.add(e2);
employees.add(e3);
employees.add(e4);
employees.add(e5);
employees.add(e6);
}
//Get Methods
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return eMail;
}
public String getBirthday() {
return birthDay;
}
public String getPhoneNumber() {
return phoneNumber;
}
//Set Methods
public void setFirstName(String firstName) throws InvalidEmployeeName {
Matcher matcher = pattern2.matcher(firstName);
if (matcher.matches()) {
this.firstName = firstName;
} else {
throw new InvalidEmployeeName("Please only use upper and lowercase letters a-Z.");
}
}
public void setLastName(String lastName) throws InvalidEmployeeName {
Matcher matcher1 = pattern2.matcher(lastName);
if (matcher1.matches()) {
this.lastName = lastName;
} else {
throw new InvalidEmployeeName("Please only use upper and lowercase letters a-Z.");
}
}
public void setEmail(String eMail) throws InvalidEmployeeEmail {
Matcher matcher2 = pattern.matcher(eMail);
if (matcher2.matches()) {
this.eMail = eMail;
} else {
throw new InvalidEmployeeEmail("Please use only a valid email addresses");
}
}
public void setBirthday(String birthDay) throws InvalidEmployeeBirthday {
Matcher matcher3 = pattern3.matcher(birthDay);
if (matcher3.matches()) {
this.birthDay = birthDay;
} else {
throw new InvalidEmployeeBirthday("Please only use dates in the format of 'dd/mm/yyyy'");
}
}
public void setPhoneNumber(String phoneNumber) throws InvalidEmployeePhoneNumber {
Matcher matcher4 = pattern1.matcher(phoneNumber);
if (matcher4.matches()) {
this.phoneNumber = phoneNumber;
} else {
throw new InvalidEmployeePhoneNumber("Please use only use phone #'s in the format of " +
"American phone numbers: 123-456-7890");
}
}
//Methods to provide menu operation and search/sort functions
public static boolean greetingMessage() throws InvalidGreetingChoice, InvalidSortChoice {
//menu options
int choice;
System.out.println("Greetings! Welcome to the company directory.\nWould you like to " +
"view a sorted list of existing employees or search for an existing employee?\nPlease" +
" choose from the following list:\n1. To print a sorted list.\n2. To do an employee search.\n" +
"3. To create a new employee.\n4. To exit completely.");
//menu option based on user input.
try {
choice = keyboard.nextInt();
keyboard.nextLine();
} catch (Exception e) {
throw new InvalidGreetingChoice("Please choose only numbers, 1-4. Try again.");
}
//calls each method which handles operations for menu items. Exit choice turns boolean to false
//to exit the program.
if (choice == 1) {
sortMessage();
} else if (choice == 2) {
searchMessage();
} else if (choice == 3) {
createMessage();
} else if (choice == 4) {
exitMessage();
return false;
}
return true;
}
public static void sortMessage() throws InvalidSortChoice, InvalidGreetingChoice {
//menu choice
int choice1;
System.out.println("Great, you have chosen to view a sorted list. To proceed, please choose from" +
" the following list:\n\n1: First name, ascending\n2: First name, descending\n3: Last " +
"name, ascending\n4: Last name, descending\n5: Email, ascending\n6: Email, descending\n" +
"7: Birthday, ascending\n8: Birthday, descending\n9: Phone number, ascending\n10: Phone " +
"number, descending\n11: If you want to exit to the main menu.");
//menu choice
try {
choice1 = keyboard.nextInt();
keyboard.nextLine();
} catch (Exception e) {
throw new InvalidSortChoice("Please only enter 1 number, 1-11. Try again.");
}
//exit option calls greetingMessage() to return to main menu.
if (choice1 == 11) {
greetingMessage();
}
//sort objects by indicated option
try {
bubbleSort(employees, choice1);
} catch (Exception e) {
e.getMessage();
}
//print sorted list
int i = 0;
for (CompanyEmployee temp : employees) {
System.out.println("Employee " + ++i + ": " + temp.toString() + "\n");
}
//returning to main menu
System.out.println("Returning you to the main menu.\n");
}
public static void searchMessage() throws InvalidSortChoice, InvalidGreetingChoice {
//Strings for type test and answer
String type = null, answer;
//menu int
int choice2 = 0;
System.out.println("Great, you have chosen to do a search.\nWhat category do you want to search by?\n1. " +
"First name.\n2. Last Name.\n3. Email.\n4. Birthday.\n5. Phone number.\n6. Exit Search");
try {
choice2 = keyboard.nextInt();
keyboard.nextLine();
} catch (Exception e) {
e.getMessage();
}
//exit option to return to main menu
if (choice2 == 6) {
greetingMessage();
}
try {
type = typeTest(choice2);
} catch (Exception e) {
e.getMessage();
}
//Since search isn't specific, I have a method to indicate what type of search is being performed.
System.out.println("What " + type + " would you like to search for?\n");
//take answer, plug it into search method, return the object.toString for the answer, or return
//message indicating that object doesn't exist.
try {
answer = keyboard.nextLine();
answer = CompanyEmployee.arraySearch(employees, answer, choice2);
System.out.println(answer);
} catch (Exception e) {
e.getMessage();
}
}
public static void createMessage() throws InvalidGreetingChoice, InvalidSortChoice {
//temp Strings to create employee
String tempFirst, tempLast, tempEmail, tempBirthday, tempPhone;
//temp object
CompanyEmployee newEmployee;
//int to provide the option to create employee or exit
int tempChoice;
System.out.println("Great, you have chosen to create a new employee.\nTo begin, what is the " +
"employee's first name?");
tempFirst = keyboard.nextLine();
System.out.println("\nWhat is the employee's Last name?");
tempLast = keyboard.nextLine();
System.out.println("\nWhat is the employee's Email?");
tempEmail = keyboard.nextLine();
System.out.println("\nWhat is the employee's Birthday?");
tempBirthday = keyboard.nextLine();
System.out.println("\nWhat is the employee's Phone Number?");
tempPhone = keyboard.nextLine();
System.out.println("\nOk, You have entered the following information for this employee:\n" +
"First name: " + tempFirst + "\nLast name: " + tempLast + "\nEmail: " + tempEmail + "\nBirthday:" +
" " + tempBirthday + "\nPhone number: " + tempPhone + "\n\nIf you would like to continue, press " +
"1, to try again, press 2");
tempChoice = keyboard.nextInt();
keyboard.nextLine();
if (tempChoice == 1) {
try {
newEmployee = new CompanyEmployee(tempFirst, tempLast, tempEmail, tempBirthday, tempPhone);
employees.add(newEmployee);
} catch (Exception e) {
e.getMessage();
}
System.out.println("The employee has been created, returning to main menu.\n\n");
} else if (tempChoice == 2) {
System.out.println("You have chosen to not create this employee, returning to the main menu.");
} else {
if ((tempChoice != 1) && (tempChoice != 2)) {
System.out.println("Please only use 1 or 2, try again:");
createMessage();
}
}
}
public static void exitMessage() {
System.out.println("You have chosen to exit, thanks for using the Employee Database.");
System.exit(0);
}
//Algorithm for sorting
public static void bubbleSort(ArrayList<CompanyEmployee> array, int sortType) throws InvalidSortChoice,
InvalidGreetingChoice {
// Marks the last element to compare
int lastPos;
// Index of an element to compare
int i;
// Used to swap to elements
CompanyEmployee temp;
//based on the sort chosen, determines output order of method
int test;
test = sortType;
//Firstname Ascending
if (test == 1) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getFirstName().compareTo(array.get(i + 1).getFirstName()) > 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//FirstName Descending
else if (test == 2) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getFirstName().compareTo(array.get(i + 1).getFirstName()) < 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//LastName Ascending
else if (test == 3) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getLastName().compareTo(array.get(i + 1).getLastName()) > 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//LastName Descending
else if (test == 4) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getLastName().compareTo(array.get(i + 1).getLastName()) < 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//Email Ascending
else if (test == 5) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getEmail().compareTo(array.get(i + 1).getEmail()) > 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//Email Descending
else if (test == 6) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getEmail().compareTo(array.get(i + 1).getEmail()) < 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//Birthday Ascending
else if (test == 7) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getBirthday().compareTo(array.get(i + 1).getBirthday()) > 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//Birthday Descending
else if (test == 8) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getBirthday().compareTo(array.get(i + 1).getBirthday()) < 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//PhoneNumber Ascending
else if (test == 9) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getPhoneNumber().compareTo(array.get(i + 1).getPhoneNumber()) > 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
}
//PhoneNumber Descending
else if (test == 10) {
for (lastPos = array.size() - 1; lastPos >= 0; lastPos--) {
for (i = 0; i <= lastPos - 1; i++) {
// Compare an element with its neighbor.
if (array.get(i).getPhoneNumber().compareTo(array.get(i + 1).getPhoneNumber()) < 0) {
// Swap the two elements.
temp = array.get(i);
array.set(i, array.get(i + 1));
array.set(i + 1, temp);
}
}
}
} else {
System.out.println("That's and incorrect choice, please choose a number from 1-11. Try again.");
sortMessage();
}
}
//Sequential Search algorithm
public static String arraySearch(ArrayList<CompanyEmployee> array, String searchValue, int searchType) throws
InvalidGreetingChoice {
//String used to indicate type of search performed, and return string.
String type, answer1;
//typetest returns string matching type of sort requested.
type = typeTest(searchType);
for (int i = 0; i < array.size(); i++) {
//turn object into string for contains check
answer1 = array.get(i).toString();
//check if the string contains passed string value of x
if (answer1.contains(searchValue)) {
return array.get(i).toString();
}
}
answer1 = ("The search found no employees with the following " + type + ": " + searchValue + "\n");
return answer1;
}
//Method to make sure my output matches user input
public static String typeTest(int typeTest) {
//look at value and return string of indicated type
String typeReturn;
if (typeTest == 1) {
typeReturn = "first name";
} else if (typeTest == 2) {
typeReturn = "last name";
} else if (typeTest == 3) {
typeReturn = "email";
} else if (typeTest == 4) {
typeReturn = "birthday";
} else if (typeTest == 5) {
typeReturn = "phone Number";
} else {
typeReturn = null;
}
return typeReturn;
}
//custom Exceptions
public class InvalidEmployeeBirthday extends Exception {
public InvalidEmployeeBirthday(String message) {
super(message);
}
}
public class InvalidEmployeeName extends Exception {
public InvalidEmployeeName(String message) {
super(message);
}
}
public class InvalidEmployeeEmail extends Exception {
public InvalidEmployeeEmail(String message) {
super(message);
}
}
public class InvalidEmployeePhoneNumber extends Exception {
public InvalidEmployeePhoneNumber(String message) {
super(message);
}
}
public static class ObjectEqualsNull extends Exception {
public ObjectEqualsNull(String message) {
super(message);
}
}
public static class InvalidSortChoice extends Exception {
public InvalidSortChoice(String message) {
super(message);
}
}
public static class InvalidGreetingChoice extends Exception {
public InvalidGreetingChoice(String message) {
super(message);
}
}
//MAIN
public static void main(String[] args) throws ObjectEqualsNull, InvalidSortChoice,
InvalidGreetingChoice, InvalidEmployeeName {
//Employee objects
createArray();
//sentinel while loop to keep the program going till user indicated exit.
while (greetingMessage());
}
}
1 Answer 1
Single responsibility principle
A class should have a single responsibility. This one does too many things:
- Represents an employee
- Contains a static list of employees
- Handles user input
- Handles various operations (create, search, print)
Strange input validation
This constructor is wrong, and pointless:
//default constructor, currently unused public CompanyEmployee() throws InvalidEmployeeBirthday, InvalidEmployeeEmail, InvalidEmployeeName, InvalidEmployeePhoneNumber { this.firstName = ""; this.lastName = ""; this.eMail = ""; this.birthDay = "1901/01/01"; this.phoneNumber = "000-000-0000"; }
It's wrong because:
- It declares exceptions to be thrown that it will never throw
- It creates an invalid employee
Poor naming and commenting
This kind of code makes two mistakes at once:
//Matcher for first name Matcher matcher = pattern2.matcher(firstName);
The variable name pattern2
is awful,
because it doesn't describe the purpose of the variable.
If you renamed the variable to firstNameMatcher
,
the comment would become pointless.
In fact, whenever you feel like writing a comment,
consider improving the code in a way to make the comment unnecessary.
It could be renaming a variable,
or moving a block of code to a helper function with a descriptive name.
Pointless variables
The regex
, regex1
, ..., regex3
variables are pointless.
They are used only once,
by the corresponding Pattern
variables.
It would be better to inline these strings in the Pattern
definitions,
because these variables pollute the namespace of the class.
More pointless variables
The constructor creates multiple Matcher
instances up-front,
even if some of them might never get used,
for example if the first validator fails.
It's best to create a variable right before you need it, not sooner.
In this particular example, the Matcher
instances seem completely unnecessary, as you could just as well do this:
if (firstNameMatcher.matcher(firstName).matches()) {
this.firstName = firstName;
} else {
throw new InvalidEmployeeName("Please only use upper and lowercase letters a-Z.");
}
Even better, no need to assign member fields until everything was validated. So you could write the constructor like this:
if (!firstNameMatcher.matcher(firstName).matches()) {
throw new InvalidEmployeeName("Please only use upper and lowercase letters a-Z.");
}
if (!lastNameMatcher.matcher(lastName).matches()) {
throw new InvalidEmployeeName("Please only use upper and lowercase letters a-Z.");
}
// ...
this.firstName = firstName;
this.lastName = lastName;
// ...
Too relaxed visibility
The Pattern
variables are declared with default visibility.
It's a good policy to make everything private
first,
and relax later when you find a good reason to do that.
Code duplication
The validation logic is duplicated in the constructor and the setters. It would be better to extract that logic to a helper method, for example:
private void validatePhoneNumber(String phoneNumber) throws InvalidEmployeePhoneNumber {
if (!phoneNumberPattern.matcher(phoneNumber).matches()) {
throw new InvalidEmployeePhoneNumber("Please use only use phone #'s in the format of " +
"American phone numbers: 123-456-7890");
}
}
You could call this from both the constructor and the setter.