Program: The Guest List
Let’s look at how the ArrayList
benefits us when writing a simple guest list program. In this program, the user will be able to add, edit, and remove guests.
The first thing we’ll do is create a Scanner
for input as well as create an ArrayList
to hold the names of the guests.
import java.util.ArrayList; import java.util.Scanner; public class GuestList { public static void main(String[] args) { Scanner sc = new Scanner(System.in); ArrayList<String> guestlist = new ArrayList<>(); } }
Line 6 creates a Scanner
. Line 7 creates an ArrayList
of String
to hold all the names of the guests. The ArrayList
is aptly named guestlist
.
Currently, guestlist
is empty, so let’s add a few names for testing purposes and print them out.
public static void main(String[] args) { Scanner sc = new Scanner(System.in); ArrayList<String> guestlist = new ArrayList<>(); guestlist.add("Michael Orwell"); guestlist.add("Veronika O'Neill"); guestlist.add("Lester Wilcox"); guestlist.add("Justine Oakley"); guestlist.add("Rylan Tempest"); System.out.println("\n=== GUEST LIST ==="); for (int i = 0; i < guestlist.size(); i++) { System.out.printf("%d | %s\n", (i + 1), guestlist.get(i)); } }
[Run] === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest
Lines 4-8 each add a name to the list using the add
method and passing in a String
. In general, the add
method places the value it receives at the end of the list, so the names will be in the same order as they were added. Line 10 prints out a heading for the guest list. Lines 11-13 is a typical for loop that prints out each element in the list. On line 12, the %d
gets replaced with (i + 1)
. This gives us the numbering to the left of the names. The reason it’s i + 1
is because i
goes from 0-4, so adding 1 each time gives us 1-5, which looks more natural. The %s
gets replaced with guestlist.get(i)
. The get
method returns the element at the specified index. For example, when i
is 3, we can break it down by first replacing all the i
’s with 3:
System.out.printf("%d | %s\n", (3 + 1), guestlist.get(3));
3 + 1 is 4 and guestlist.get(3)
returns “Justine Oakley”, therefore:
System.out.printf("%d | %s\n", 4, "Justine Oakley");
Replacing the %d with 4 and the %s with “Justine Oakley” results in:
System.out.printf("4 | Justine Oakley\n");
The resulting string:
4 | Justine Oakley
Adding a Guest
Now let’s give the user some control over the guest list. First, we’ll construct a menu and write a switch statement to handle the various options. We’ll only implement one option in this example, the option to add a guest to the list. We’ll also surround the relevant sections of code in a do-while loop so the program doesn’t immediately end.
public static void main(String[] args) { Scanner sc = new Scanner(System.in); ArrayList<String> guestlist = new ArrayList<>(); guestlist.add("Michael Orwell"); guestlist.add("Veronika O'Neill"); guestlist.add("Lester Wilcox"); guestlist.add("Justine Oakley"); guestlist.add("Rylan Tempest"); do { System.out.println("\n=== GUEST LIST ==="); for (int i = 0; i < guestlist.size(); i++) { System.out.printf("%d | %s\n", (i + 1), guestlist.get(i)); } System.out.println("\n--- MENU ---"); System.out.println("1: Add Guest\n2: Insert Guest\n3: Rename Guest\n4: Remove Guest\n5: Exit"); System.out.print("Option: "); int option = sc.nextInt(); sc.nextLine(); switch (option) { case 1: System.out.print("Guest name: "); guestlist.add(sc.nextLine()); break; } } while (true); }
[Run] === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest --- MENU --- 1: Add Guest 2: Insert Guest 3: Rename Guest 4: Remove Guest 5: Exit Option: 1 Guest name: Anabella Irvin === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest 6 | Anabella Irvin --- MENU --- 1: Add Guest 2: Insert Guest
After the guests have been printed, line 16 prints the menu heading. Line 17 then prints the options that the user can choose from such as adding a guest, removing a guest, etc. Line 18 asks the user to enter an option. Line 19 obtains the user’s input into variable option
. Line 20 calls sc.nextLine
to consume the \n
that’s waiting in the input stream. This ensures that any call to sc.nextLine
that immediately follows blocks for more input. Lines 22-27 is a switch statement. It switches on the option
variable. In the case that option
is 1, evidently the user wants to add a guest, so line 24 asks for the name of the guest. Line 25 both obtains the name and adds it to the guest list. Usually we’d use two lines for this with an intermediate variable like so:
String name = sc.nextLine(); guestlist.add(name);
Line 25 just shows that you can omit the name
variable and put the call to sc.nextLine
straight in the parentheses. Whatever sc.nextLine
returns becomes the argument to the add
method and thus is added to the list. Line 26 breaks out of the switch statement like usual. The relevant code has been surrounded in a do-while loop (lines 10-28) so that the guest list is reprinted with any changes and the user is able to choose another option. We can see from the sample run that the user chose to add a guest called Anabella Irvin. We can see her name in position 6 when the list is printed again. Really, all that’s left now is to implement the other options.
Inserting a Guest
This option allows the user to insert a guest at a position of their choosing.
case 2: System.out.print("Insert at Number: "); int index = sc.nextInt() - 1; sc.nextLine(); System.out.print("Guest name: "); String name = sc.nextLine(); guestlist.add(index, name); break;
[Run] === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest --- MENU --- 1: Add Guest 2: Insert Guest 3: Rename Guest 4: Remove Guest 5: Exit Option: 2 Insert at Number: 3 Guest name: Frank Berry === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Frank Berry 4 | Lester Wilcox 5 | Justine Oakley 6 | Rylan Tempest
Line 2 asks the user for a number to insert the guest at. Line 3 obtains this number and takes 1 away because, again, visually the guests are numbered starting at 1 but the ArrayList
indexing starts at 0, so taking 1 away gives the equivalent array index to what the user sees. This value is stored in variable index
. Line 4 consumes the \n
that the call to sc.nextInt
didn’t read. Lines 5-6 prompt for the name of the guest, which gets stored in variable name
. Line 7 adds the name to the specified index. We can see from the sample run that “Frank Berry” is inserted at number 3 (index 2). In the ArrayList
, the element that was already at index 2 and every element after it get shifted 1 to the right to make room for this new element.
What if the user tries to insert a guest but enters a number that is out of range, like -1 or 18? This would give an out-of-bounds error. We could do a simple greater-than/less-than check to ensure that the index is valid, and if it’s not, we inform the user and ask for another number. Alternatively, we could handle it in more discreet way. We could simply constrain or clamp the index to the appropriate range. This means if the index is valid, we leave it as is. If the index is too low, we push it up to the minimum. If the index is too high, we pull it down to the maximum. As an example, imagine the guest list has 5 names, which occupy indexes 0, 1, 2, 3, 4 as usual. If the user tries to enter a guest at index 1, we simply add the guest at index 1 without any interference. If the user tries to enter a guest at index -3, we can assume they want to add it at the beginning of the list and so we add it at index 0 instead. On the flip side, if the user tries to enter a guest at index 9, we can assume they want to add it at the end of the list and so we add it at index 5 instead. Many languages have a clamp function built in but Java doesn’t at this time. Fortunately, it’s not a difficult thing to write; you can simply use an if statement:
if (index < 0) { index = 0; } else if (index > guestlist.size()) { index = guestlist.size(); }
This simply says: if the index is less than 0, then set the index to 0, else if the index is greater than the size of the list, then set the index to the size of the list. If neither condition is true, the index is unaffected.
Another way is to use the ternary operator (though I don’t recommend doing it this way as it’s not easy to decipher, especially at a glance):
index = index < 0 ? 0 : index > guestlist.size() ? guestlist.size() : index;
The ternary operator is actually used twice here. We can see that it first checks index < 0
. If true (meaning the index is too low), the result is the value before the :
, which is 0. If false, the result is the value after the :
, which is another ternary operation! This also needs to be worked out. It’s condition is index > guestlist.size()
. If true (meaning the index is too high), the result is the value before the :
, which is guestlist.size()
. If false, the result is the value after the :
, which is simply the original index, unchanged.
A third, slightly cleverer way is to use a combination of the Math.max
and Math.min
functions. They are quite simple. Math.max
takes two arguments and returns the larger one. Math.min
takes two arguments and returns the smaller one. For example:
int num = Math.min(14, 6);
Math.min
is passed 14 and 6. It returns 6 because it is the smaller number. The order of the arguments doesn’t matter either; the smaller of the two is always returned. As you’d expect, if Math.max
were used instead, it would return 14. Here is case 2 updated to clamp the index using these two functions:
case 2: System.out.print("Insert at Number: "); int index = sc.nextInt() - 1; index = Math.max(0, Math.min(index, guestlist.size())); sc.nextLine(); System.out.print("Guest name: "); String name = sc.nextLine(); guestlist.add(index, name); break;
The only change is that a line of code has been inserted into line 4. Here, Math.max
is called with the value 0 as the first argument. However, the second argument isn’t a straight value, but a call to Math.min
. When this happens, the value that Math.min
returns will be the second argument to Math.max
. It is therefore necessary for Math.min
to be worked out first. We can see it is passed two arguments (index
and guestlist.size()
). Again, if we imagine that the size of the guest list is 5, and the user enters an invalid index, like 21, then that results in:
index = Math.max(0, Math.min(21, 5));
Math.min returns 5 (the smaller of the two), resulting in:
index = Math.max(0, 5);
Math.max returns 5 (the larger of the two), resulting in:
index = 5;
So, even though the user enters 21, the index will actually be 5 (which is the last index in the list plus 1).
Let’s now imagine the user enters something crazy -3500:
index = Math.max(0, Math.min(-3500, 5));
Math.min returns -3500:
index = Math.max(0, -3500);
Math.max returns 0:
index = 0;
So, even though the user enters -3500, the index is set to 0 (the first index in the list).
Now let’s imagine the user enters a valid index of 2:
index = Math.max(0, Math.min(2, 5));
Math.min returns 2:
index = Math.max(0, 2);
Math.max returns 2:
index = 2;
The index is unchanged.
Renaming a Guest
When renaming a guest, the program first asks the user for the guest’s number. It then checks if the number is valid. If it is, the program prompts for a new name and updates the relevant guest.
case 3: { System.out.print("Guest Number: "); int index = sc.nextInt() - 1; sc.nextLine(); if (index < 0 || index > guestlist.size() - 1) { System.out.println("Error: There is no guest with that number."); break; } System.out.print("New Name: "); String name = sc.nextLine(); guestlist.set(index, name); break; }
[Run] === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest --- MENU --- 1: Add Guest 2: Insert Guest 3: Rename Guest 4: Remove Guest 5: Exit Option: 3 Guest Number: 1 New Name: Michael Larrie === GUEST LIST === 1 | Michael Larrie 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest --- MENU --- 1: Add Guest 2: Insert Guest 3: Rename Guest 4: Remove Guest 5: Exit Option: 3 Guest Number: 7 Error: There is no guest with that number.
Line 2 prompts the user for the guest number and line 3 obtains it and takes 1 away for the correct index. Line 4 reads the \n
that is left. Line 5 checks that the index is invalid i.e. if the index is less than 0 OR greater than the last index, then it is out of range. In that case, line 6 informs the user that there is no guest with that number and line 7 breaks. This ends the case right there and the program continues after the switch statement and loops back around to the menu again. On the other hand, if the index is valid, the if statement doesn’t run and line 9 asks what the new name should be. Line 10 obtains the input. Line 11 calls the ArrayList
’s set
method. This method simply sets an index to a value, overwriting any previous value that was there. Thus, the specified index is set to the new name.
Note that each case doesn’t define a separate scope as far as variables are concerned, therefore we get an error when trying to declare a variable with the same name in two different cases. For instance, variables index
and name
are declared in both case 2 and case 3. This causes an error under normal circumstances. An easy solution is to encapsulate the code for each case in curly brackets, so that the variables are not in the same scope, as can be seen in case 3 above on lines 1 and 13.
Removing a Guest
To remove a guest, we simply ask for a number and, if it’s valid, remove the guest.
case 4: { System.out.print("Guest Number: "); int index = sc.nextInt() - 1; if (index < 0 || index > guestlist.size() - 1) { System.out.println("Error: There is no guest with that number."); break; } guestlist.remove(index); break; }
[Run] === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest --- MENU --- 1: Add Guest 2: Insert Guest 3: Rename Guest 4: Remove Guest 5: Exit Option: 4 Guest Number: 3 === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Justine Oakley 4 | Rylan Tempest
Line 2 asks for the guest’s number. Line 3 obtains it and converts it to the index. Line 4 checks if the index is out of range. If true, line 5 informs that user that that number is invalid and line 6 breaks, causing the program to loop back around to the menu again. If false, line 8 calls the remove
method with the supplied index and the corresponding value is removed from the list. All subsequent values shift down to fill the gap.
Program Exit and Invalid Option
case 5: { System.out.println("Exiting..."); System.exit(0); break; } default: { System.out.println("Option invalid."); break; }
[Run] --- MENU --- 1: Add Guest 2: Insert Guest 3: Rename Guest 4: Remove Guest 5: Exit Option: 22 Option invalid. === GUEST LIST === 1 | Michael Orwell 2 | Veronika O'Neill 3 | Lester Wilcox 4 | Justine Oakley 5 | Rylan Tempest --- MENU --- 1: Add Guest 2: Insert Guest 3: Rename Guest 4: Remove Guest 5: Exit Option: 5 Exiting… Process finished with exit code 0
On exit, line 2 informs the user that the program is exiting. Line 3 calls System.exit(0)
. This ends the program right there and then. You pass in a number as a status code that shows up in the console when the program ends. You decide on what value is passed and what it means. Zero is traditionally used to indicate that the program exited normally, and other numbers indicate the program exited abnormally. The break
statement on line 4 will never execute but it’s left for the sake of consistency.
In the default case, line 7 simply informs the user that the option they entered is invalid and the loop repeats. As we can see from the sample run, entering 22 is invalid and the menu is displayed again. Entering 5 causes the program to exit and the final line reads “Process finished with exit code 0”, where the 0 is the value that was passed to System.exit
.