Lesson Weekend

During the first week of the Java course, we will continue to write applications that run solely in the command line. Remember, the portion of your programs that interact with the user through the command line is known as the command line interface. Focusing exclusively on Java before integrating the complexity that comes along with web frameworks will allow us to develop the strong fundamentals we'll require to tackle such a robust, large language.

So far, the command line applications we've created only prompted the user for information, do something with this information, return a response to the user, then quit. We haven't yet been able to choose from multiple options, or really integrate much interaction into our applications. Thankfully, because we're now able to branch, loop, gather user input, and compare strings, we can easily change this!

Multiple Functionalities in a Command Line Application

Instead of our car dealership application immediately asking the user to provide their price range for a vehicle, what if it gave them multiple options to choose from? Let's change the first prompt in our System.out.println() method to say "Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles or Search Price".

Then, we'll add branching to perform different functions depending on what information the user provides:

App.java
import models.Vehicle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class App {
   public static void main(String[] args) {

       Vehicle hatchback = new Vehicle(1994, "Subaru", "Legacy", 170000, 4000);
       Vehicle suv = new Vehicle(2002, "Ford", "Explorer", 100000, 7000);
       Vehicle sedan = new Vehicle(2015, "Toyota", "Camry", 50000, 30000);
       Vehicle truck = new Vehicle(1999, "Ford", "Ranger", 100000, 4000);
       Vehicle crossover = new Vehicle(1998, "Toyota", "Rav-4", 200000, 3500);

       Vehicle[] allVehicles = {hatchback, suv, sedan, truck, crossover};

       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
       System.out.println("Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles or Search Price");

       try {

           String navigationChoice = bufferedReader.readLine();

           if (navigationChoice.equals("All Vehicles")) {
               for (Vehicle individualVehicle : allVehicles) {
                   System.out.println("----------------------");
                   System.out.println(individualVehicle.year);
                   System.out.println(individualVehicle.brand);
                   System.out.println(individualVehicle.model);
                   System.out.println(individualVehicle.miles);
                   System.out.println(individualVehicle.price);
               }
           } else if (navigationChoice.equals("Search Price")) {
               System.out.println("What is your maximum budget for a vehicle?");
               String stringUserMaxBudget = bufferedReader.readLine();
               int userMaxBudget = Integer.parseInt(stringUserMaxBudget);
               System.out.println("Alright, here's what we have in your price range:");
               for (Vehicle individualVehicle : allVehicles) {
                   if (individualVehicle.worthBuying(userMaxBudget)) {
                       System.out.println("----------------------");
                       System.out.println(individualVehicle.year);
                       System.out.println(individualVehicle.brand);
                       System.out.println(individualVehicle.model);
                       System.out.println(individualVehicle.miles);
                       System.out.println(individualVehicle.price);
                   }
               }
           } else {
               System.out.println("I'm sorry, we don't recognize your input");
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

Dang! This is starting to look like a real program. Don't let the amount curly braces make you sweat. Let's walk through this. In the code above, we do the following:

  • Prompt the user, and gather their input.
  • If their input reads "All Vehicles", we display the details for every vehicle in our system.
  • If it reads "Search Price", a second prompt asks them to provide their max budget.
    • We parse this value and use it as an argument to our existing worthBuying() method.
    • Then, we only return details about vehicles in their price range.
  • If the user provides something other than these two options we display an error.
  • Also, notice we're using equals() to compare strings here.

Now, if we compile and run our program we'll see the application responds differently depending on the user's input. If we say "All Vehicles", we're provided details for each Vehicle object:

Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles or Search Price

All Vehicles

----------------------
1994
Subaru
Legacy
170000
4000
----------------------
2002
Ford
Explorer
100000
7000
----------------------
2015
Toyota
Camry
50000
30000
----------------------
1999
Ford
Ranger
100000
4000
----------------------
1998
Toyota
Rav-4
200000
3500

Or, if we say "Search Price", we receive an additional prompt to ask what our budget for a vehicle is:

Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles or Search Price

Search Price

What is your maximum budget for a vehicle?
4000

Alright, here's what we have in your price range:
----------------------
1994
Subaru
Legacy
170000
4000
----------------------
1999
Ford
Ranger
100000
4000
----------------------
1998
Toyota
Rav-4
200000
3500

Are you beginning to see the possibilities?

User-Created Objects

We recently learned that Constructors are similar to any other type of method. They're only special because they return (or construct) a new instance of their class.

Similar to the manner we call worthBuying() when the user opts to search for vehicles, we could also call our Vehicle constructor method. This would allow users to add their own vehicles to the application. Let's add another option to our first prompt. We'll tell users to enter either All Vehicles, Search Price, or Add Vehicle:

App.java
...
    System.out.println("Welcome to our car dealership. What would you like to do?
                                      Enter one of the following options: All Vehicles, Search Price or Add Vehicle");
...

Next, we'll add an additional else if statement that will be executed when the user enters Add Vehicle into our program:

App.java
import models.Vehicle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class App {
   public static void main(String[] args) {

       Vehicle hatchback = new Vehicle(1994, "Subaru", "Legacy", 170000, 4000);
       Vehicle suv = new Vehicle(2002, "Ford", "Explorer", 100000, 7000);
       Vehicle sedan = new Vehicle(2015, "Toyota", "Camry", 50000, 30000);
       Vehicle truck = new Vehicle(1999, "Ford", "Ranger", 100000, 4000);
       Vehicle crossover = new Vehicle(1998, "Toyota", "Rav-4", 200000, 3500);

       Vehicle[] allVehicles = {hatchback, suv, sedan, truck, crossover};

       BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
       System.out.println("Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price, or Add Vehicle");

       try {

           String navigationChoice = bufferedReader.readLine();

           if (navigationChoice.equals("All Vehicles")) {
               for (Vehicle individualVehicle : allVehicles) {
                   System.out.println("----------------------");
                   System.out.println(individualVehicle.year);
                   System.out.println(individualVehicle.brand);
                   System.out.println(individualVehicle.model);
                   System.out.println(individualVehicle.miles);
                   System.out.println(individualVehicle.price);
               }
           } else if (navigationChoice.equals("Search Price")) {
               System.out.println("What is your maximum budget for a vehicle?");
               String stringUserMaxBudget = bufferedReader.readLine();
               int userMaxBudget = Integer.parseInt(stringUserMaxBudget);
               System.out.println("Alright, here's what we have in your price range:");
               for (Vehicle individualVehicle : allVehicles) {
                   if (individualVehicle.worthBuying(userMaxBudget)) {
                       System.out.println("----------------------");
                       System.out.println(individualVehicle.year);
                       System.out.println(individualVehicle.brand);
                       System.out.println(individualVehicle.model);
                       System.out.println(individualVehicle.miles);
                       System.out.println(individualVehicle.price);
                   }
               }
           } else if (navigationChoice.equals("Add Vehicle")){
                   System.out.println("Alright, let's add a vehicle! What year was this vehicle made?");
                   int userVehicleYear = Integer.parseInt(bufferedReader.readLine());
                   System.out.println("Great! What make or brand is the vehicle?");
                   String userVehicleBrand = bufferedReader.readLine();
                   System.out.println("Got it! What model is it?");
                   String userVehicleModel = bufferedReader.readLine();
                   System.out.println("And how many miles does it have on it?");
                   int userVehicleMiles = Integer.parseInt(bufferedReader.readLine());
                   System.out.println("Finally, what's its price?");
                   int userVehiclePrice = Integer.parseInt(bufferedReader.readLine());
                   Vehicle userVehicle = new Vehicle(userVehicleYear, userVehicleBrand, userVehicleModel, userVehicleMiles, userVehiclePrice);
                   System.out.println("Alright, here's your new vehicle:");
                   System.out.println( "----------------------" );
                   System.out.println( userVehicle.year );
                   System.out.println( userVehicle.brand );
                   System.out.println( userVehicle.model );
                   System.out.println( userVehicle.miles );
                   System.out.println( userVehicle.price );
               }
           else {
               System.out.println("I'm sorry, we don't recognize your input");
           }
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

Let's walk through what we've added in the code above:

  • We've included another else if conditional in our branching. Remember, you can have as many else if statements as you'd like!
  • If the user says they'd like to "Add Vehicle", we have a series of prompts that gather the necessary details about the dealership's new vehicle.
  • Each piece of user input is saved into its own variable. These variables are then passed into the Vehicle constructor in order to create a new Vehicle object:
App.java
...
Vehicle userVehicle = new Vehicle(userVehicleYear, userVehicleBrand, userVehicleModel, userVehicleMiles, userVehiclePrice);
...
  • Then, we display the attributes of the new Vehicle object to our user with System.out.println().

Also, notice the way we're transforming strings into int primitives in these three lines from the code above:

App.java
...
int userVehicleYear = Integer.parseInt(bufferedReader.readLine());
 ...
int userVehicleMiles = Integer.parseInt(bufferedReader.readLine());
...
int userVehiclePrice = Integer.parseInt(bufferedReader.readLine());
...

Instead of declaring a String variable containing the results of bufferedReader.readLine(), then using Integer.parseInt() to transform it into an int on a new line, we handle it all in one place. We do this by providing bufferedReader.readLine() as an argument to Integer.parseInt(). This allows us to declare the variable as int immediately, because after the code right of the = runs, the value will be parsed into an int!

Now, if we compile and run our app, we can create a new Vehicle object directly in the command line:

Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price or Add Vehicle
Add Vehicle

Alright, let's add a vehicle! What year was this vehicle made?
2000

Great! What make or brand is the vehicle?
Chevy

Got it! What model is it?
Malibu

And how many miles does it have on it?
180000

Finally, what's its price?
8000

Alright, here's your new vehicle:
----------------------
2000
Chevy
Malibu
180000
8000

Adding Dynamically-Created Content to ArrayLists

This is great! But if the user is adding a new vehicle to our application, shouldn't this vehicle be included in our list of all available vehicles? Let's tackle this next! Currently, we're storing all Vehicle objects in an Array we've named allVehicles:

App.java
...
    Vehicle[] allVehicles = {hatchback, suv, sedan, truck, crossover};
...

Do you remember the rules of an Array data structure? You cannot alter the length of an Array in Java. So, we may not add a new Vehicle to allVehicles. However, we can add and subtract vehicles from an ArrayList. The ArrayList data type is capable of fluctuating in length, whereas Array is not.

Let's change allVehicles from an Array into an ArrayList. Don't forget to import the necessary classes from the java.util package at the top of your file. After our ArrayList is created, we can use the add() method to add each vehicle object:

App.java
import models.Vehicle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.ArrayList;

public class App {
   public static void main(String[] args) {

       Vehicle hatchback = new Vehicle(1994, "Subaru", "Legacy", 170000, 4000);
       Vehicle suv = new Vehicle(2002, "Ford", "Explorer", 100000, 7000);
       Vehicle sedan = new Vehicle(2015, "Toyota", "Camry", 50000, 30000);
       Vehicle truck = new Vehicle(1999, "Ford", "Ranger", 100000, 4000);
       Vehicle crossover = new Vehicle(1998, "Toyota", "Rav-4", 200000, 3500);

       ArrayList<Vehicle> allVehicles = new ArrayList<Vehicle>();

       allVehicles.add(hatchback);
       allVehicles.add(suv);
       allVehicles.add(sedan);
       allVehicles.add(truck);
       allVehicles.add(crossover);


...

Then, we also use the add() method to include our new vehicle in allVehicles:

App.java
...
  ...
    } else if (navigationChoice.equals("Add Vehicle")){
        ...
Vehicle userVehicle = new Vehicle(userVehicleYear, userVehicleBrand, userVehicleModel, userVehicleMiles, userVehiclePrice);
allVehicles.add(userVehicle); //I'm new!

    ...
....

We can compile and run our application again, and see that everything still works:

Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price or Add Vehicle
Add Vehicle

Alright, let's add a vehicle! What year was this vehicle made?
1908

Great! What make or brand is the vehicle?
Ford

Got it! What model is it?
Model-T

And how many miles does it have on it?
200

Finally, what's its price?
100000

Alright, here's your new vehicle:
----------------------
1908
Ford
Model-T
200
100000

But hey! The program ends immediately after we add our new vehicle! Wouldn't it be preferable to offer our user the option to continue interacting with our application after a new Vehicle is added? It just kicked us out!

Continually Running Programs with While Loops

Thankfully, we can implement a loop to keep our program running continually. That way, after we've successfully added a new vehicle, or completed a price-based search, we can return back the 'original' prompt "Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price or Add Vehicle".

Anatomy of a While Loop

A basic setup for a while loop looks like this:

while(someConditional){
  // code that continually loops while someConditional is true;
}

If we translated this code into 'plain English', it would read: "While the 'number' variable is less than 10, continually loop through these two lines of code."

int number = 1;

while(number < 10){
  System.out.println(number);
  number += 1;
}

If we copy/paste this while loop into the REPL, it results in the following:

int number = 1

while(number < 10){
   System.out.println(number);
   number += 1;
}

1
2
3
4
5
6
7
8
9

The code within the loop kept running, printing number and increasing number by 1 each time, until the conditional in the parenthesis (number < 10) was no longer true. While loops run while their conditional is true. As soon as their conditional is false (like when number is no longer less than 10), the loop stops.

Let's add a while loop to the main() method of our application's command line interface. We'll use it to keep our program continually running until we opt to quit it ourselves. We'll include only the code that needs to run repeatedly within the loop:

App.java
import models.Vehicle;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class App {
   public static void main(String[] args) {

       Vehicle hatchback = new Vehicle(1994, "Subaru", "Legacy", 170000, 4000);
       Vehicle suv = new Vehicle(2002, "Ford", "Explorer", 100000, 7000);
       Vehicle sedan = new Vehicle(2015, "Toyota", "Camry", 50000, 30000);
       Vehicle truck = new Vehicle(1999, "Ford", "Ranger", 100000, 4000);
       Vehicle crossover = new Vehicle(1998, "Toyota", "Rav-4", 200000, 3500);

       ArrayList<Vehicle> allVehicles = new ArrayList<Vehicle>();

       allVehicles.add(hatchback);
       allVehicles.add(suv);
       allVehicles.add(sedan);
       allVehicles.add(truck);
       allVehicles.add(crossover);
       while (true) {
           BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
           System.out.println("Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price, or Add Vehicle");

           try {

               String navigationChoice = bufferedReader.readLine();

               if (navigationChoice.equals("All Vehicles")) {
                   for (Vehicle individualVehicle : allVehicles) {
                       System.out.println("----------------------");
                       System.out.println(individualVehicle.year);
                       System.out.println(individualVehicle.brand);
                       System.out.println(individualVehicle.model);
                       System.out.println(individualVehicle.miles);
                       System.out.println(individualVehicle.price);
                   }
               } else if (navigationChoice.equals("Search Price")) {
                   System.out.println("What is your maximum budget for a vehicle?");
                   String stringUserMaxBudget = bufferedReader.readLine();
                   int userMaxBudget = Integer.parseInt(stringUserMaxBudget);
                   System.out.println("Alright, here's what we have in your price range:");
                   for (Vehicle individualVehicle : allVehicles) {
                       if (individualVehicle.worthBuying(userMaxBudget)) {
                           System.out.println("----------------------");
                           System.out.println(individualVehicle.year);
                           System.out.println(individualVehicle.brand);
                           System.out.println(individualVehicle.model);
                           System.out.println(individualVehicle.miles);
                           System.out.println(individualVehicle.price);
                       }
                   }
               } else if (navigationChoice.equals("Add Vehicle")) {
                   System.out.println("Alright, let's add a vehicle! What year was this vehicle made?");
                   int userVehicleYear = Integer.parseInt(bufferedReader.readLine());
                   System.out.println("Great! What make or brand is the vehicle?");
                   String userVehicleBrand = bufferedReader.readLine();
                   System.out.println("Got it! What model is it?");
                   String userVehicleModel = bufferedReader.readLine();
                   System.out.println("And how many miles does it have on it?");
                   int userVehicleMiles = Integer.parseInt(bufferedReader.readLine());
                   System.out.println("Finally, what's its price?");
                   int userVehiclePrice = Integer.parseInt(bufferedReader.readLine());
                   Vehicle userVehicle = new Vehicle(userVehicleYear, userVehicleBrand, userVehicleModel, userVehicleMiles, userVehiclePrice);
                   allVehicles.add(userVehicle); //I'm new!

                   System.out.println("Alright, here's your new vehicle:");
                   System.out.println("----------------------");
                   System.out.println(userVehicle.year);
                   System.out.println(userVehicle.brand);
                   System.out.println(userVehicle.model);
                   System.out.println(userVehicle.miles);
                   System.out.println(userVehicle.price);
               } else {
                   System.out.println("I'm sorry, we don't recognize your input");
               }
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }
}

Here, we've initialized a new while loop. We pass in true as its parameter. Remember, while loops run for as long as the conditional we provide is true. Because we manually set the conditional to simply true the conditional will always be true. Essentially, this will make our program run forever until we manually quit it (by pressing the red, square stop button near the Run button).

We can compile and run our application yet again, and see the following:

Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price or Add Vehicle
Add Vehicle

Alright, let's add a vehicle! What year was this vehicle made?
1908

Great! What make or brand is the vehicle?
Ford

Got it! What model is it?
Model-T

And how many miles does it have on it?
200

Finally, what's its price?
100000

Alright, here's your new vehicle:
----------------------
1908
Ford
Model-T
200
100000

Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price or Add Vehicle
All Vehicles
----------------------
1994
Subaru
Legacy
170000
4000
----------------------
2002
Ford
Explorer
100000
7000
----------------------
2015
Toyota
Camry
50000
30000
----------------------
1999
Ford
Ranger
100000
4000
----------------------
1998
Toyota
Rav-4
200000
3500
----------------------
1908
Ford
Model-T
200
100000

Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price or Add Vehicle

It doesn't quit after a single interaction with the user! We can add a new vehicle, see our new vehicle object's details, and then receive our navigational prompt again. And, if we select All Vehicles, we can see our newly-created Vehicle has been added to the list.

Refactor

Now, if running an infinite loop and force-quitting our program doesn't seem like a very eloquent solution; you're right. Let's refactor this approach. Instead of running the loop forever, let's only run it until the user tells us they'd like to exit the application.

We'll create a boolean called programRunning, and set it to true. Then, we'll use this boolean in our while loop. We'll also inform users they may enter "Exit" as an option in our prompt:

App.java
...
boolean programRunning = true;

while(programRunning){
System.out.println("Welcome to our car dealership. What would you like to do? Enter one of the following options: All Vehicles, Search Price, Add Vehicle or Exit");
...

Next, let's also add one more else if conditional to our branching:

App.java
...
  ...
} else if (navigationChoice.equals("Add Vehicle")){
        System.out.println("Alright, let's add a vehicle! What year was this vehicle made?");
        ...
      } else if (navigationChoice.equals("Exit")){
        System.out.println("Goodbye!");
        programRunning = false;
      } else {
        System.out.println("I'm sorry, we don't recognize your input");
      }
  ...
...

This conditional will check if the user's input is ever "Exit". If it is, we set our programRunning boolean to false. Since the while loops run only while their conditional is true, this will cause the loop to halt, and our program to end. We can compile and run the application, and see it will allow us to continually interact with it. After completing a single interaction it returns back to the first prompt. However, if we type "Exit", the program quits. Rad!

Now, note that we'll only use this method to keep our applications up and running during these first few days of class. In week 2 we'll learn how to use Spark, a web framework that will allow us to create websites we can visit in our browser. However, during this first week, we can greatly increase the interactivity of our applications with cleverly-placed loops!


Example GitHub Repo for Car Dealership

Overview


While Loops

Basic setup for a while loop looks like this:

while(someConditional){
  // code that continually loops while someConditional is true; 
}

If we translated this code into 'plain English', it would read: "While the 'number' variable is less than 10, continually loop through these two lines of code."

int number = 1;

while(number < 10){
  System.out.println(number);
  number += 1; 
}

If we copy/paste this while loop into the REPL, it results in the following:

int number = 1

while(number < 10){
   System.out.println(number);
   number += 1; 
}

1
2
3
4
5
6
7
8
9

The code within the loop kept running, printing number and increasing number by 1 each time, until the conditional in the parenthesis (number < 10) was no longer true. While loops run while their conditional is true. As soon as their conditional is false (like when number is no longer less than 10), the loop stops.

We may also pass in user-provided information to an object's constructor method, like so:

...
System.out.println("Alright, let's add a vehicle! What year was this vehicle made?");
int userVehicleYear = Integer.parseInt(bufferedReader.readLine());

System.out.println("Great! What make or brand is the vehicle?");
String userVehicleBrand = bufferedReader.readLine();

System.out.println("Got it! What model is it?");
String userVehicleModel = bufferedReader.readLine();

System.out.println("And how many miles does it have on it?");
int userVehicleMiles = Integer.parseInt(bufferedReader.readLine());

System.out.println("Finally, what's its price?");
int userVehiclePrice = Integer.parseInt(bufferedReader.readLine());

Vehicle userVehicle = new Vehicle(userVehicleYear, userVehicleBrand, userVehicleModel, userVehicleMiles, userVehiclePrice);
...

Examples


Example GitHub Repo for Car Dealership