Application Building
AAHC

Click on A to make all fonts on the page smaller.

Click on A to make all fonts on the page larger.

Click on HC to toggle high contrast mode. When you move your mouse over some bold words in high contrast mode, related words are automatically highlighted. Text is shown in black and white.


Welcome to the Java Application Building series of Java courses. This series will focus on developing applications using the many tools available in Java. As in all OST courses, the emphasis will be on interactive instruction.

Course Objectives

When you complete this course, you will be able to:

In this course, you will achieve an understanding of the structure and purposes for many of the classes in the Java API. In-depth experience with user-interfaces, event and exception handling, database connectivity, multiple threads and synchronization will provide you with a toolkit for both implementing applications as well as understanding source code of others. Programs designed in the course using Java Threads, Client/Server Sockets and Database Connectivity provide a solid basis for application building.

From beginning to end, you will learn by doing your own Java projects, within our Eclipse Learning Sandbox we affectionately call "Ellipse". These projects will add to your portfolio and provide needed experience. Besides a browser and internet connection, all software is provided online by the O'Reilly School of Technology.

Review

In this series, we assume that you have a general foundation of Java and object-oriented programming knowledge, so basic programming skills won't be covered in this course. We'll work now to grow and refine your existing Java programming skills. If you are unable to follow the code that we use for illustrations and examples in this course, we recommend that you take OST's first Java series of courses to gain those basic programming skills; then you'll be able to reap the full benefits of the materials presented here.

If you are new to OST courses, read this overview before you go further.

In the previous course, we went over these concepts:

We'll apply these ideas and more as we improve our Sales Report application.

Preview

In the first new version of our application, we'll bring in LayoutManagers to provide a better user interface. Except for the various LayoutManagers and Panels, we'll also be using familiar code and techniques. In upcoming lessons, we will learn additional techniques that will enable us to:

Ready? Alright then!

Improving Your Code

Let's get to work using the same application we developed in the previous series. The application prompts users for the number of salespeople and their sales performance figures, and then displays the top performer. (If you took the earlier course, type the code in and run it.)

Create a new java4_Lesson1 project (it may help to take a look at the overview). Now, create a new main class in this project as shown:

Type main as shown in blue:

CODE TO TYPE: Main

// ****************************************************************
// Main.java
//
// Instantiates and starts the SalesReport class
//
// ****************************************************************
package sales1;
                
public class Main { 

    public static void main(String[] args){
        if (args.length > 0)
        {
            int argIn = Integer.parseInt(args[0]);
            SalesReport mySalesInfo = new SalesReport(argIn);
            mySalesInfo.testMe();
        }
        else
        {  
            SalesReport mySalesInfo = new SalesReport();  // instantiate the class
            mySalesInfo.testMe();                        // start the application
        }
    }
}               

This class instantiates and starts our application. There will be errors in Main, because we still haven't created the class that it instantiates.

In java4_Lesson1, create the SalesReport class as shown:

Type SalesReport as shown in blue below:

CODE TO TYPE: SalesReport
package sales1;

import java.util.Scanner;
                
public class SalesReport{
    int SALESPEOPLE;
    int sum;
    int sales[];
    Scanner scan = new Scanner(System.in);  
           
    public SalesReport(){
        System.out.print("Enter the number of salespersons: ");
        this.SALESPEOPLE = scan.nextInt();
        this.sales = new int[SALESPEOPLE];
    }  

    public SalesReport(int howMany){
        this.SALESPEOPLE = howMany;
        this.sales = new int[SALESPEOPLE];
    }

    public void testMe(){
        getSalesInput();
        provideSalesOutput();
        findMax();
    }
                
    public void getSalesInput(){
        Scanner scan = new Scanner(System.in);
                
        for (int i=0; i < sales.length;  i++)
        {
            System.out.print("Enter sales for salesperson " + (i+1) + ": ");
            sales[i] = scan.nextInt();
        }
    }
                
    public void provideSalesOutput(){
         System.out.println("\nSalesperson   Sales");
         System.out.println("--------------------");
         sum = 0;
         for (int i=0; i < sales.length;  i++)
         {
             System.out.println("     " + (i+1) + "         " + sales[i]);
             sum = sum + sales[i];
         }
         System.out.println("\nTotal sales: " + sum);
    }

    public void findMax(){
        int max = sales[0];  // this way we are assured that value for the initial max is in the collection
        int who = 0;         // and the initial index is the first so we visit all
        for (int i=0; i < sales.length;  i++)
        {
            if (max < sales[i])
            {
                max = sales[i];
                who = i;
            }
        }
        System.out.println("\nSalesPerson " + (who+1) + " had the highest sale with $" + max );
    }
} 

Save and Run it.

Since SalesReport does not extend Applet, it is not an Applet, and since SalesReport does not have a main() method, Java is not sure what to do. We created the Main class to instantiate and start this application, so we should go to that class to run it.

NoteIn Eclipse, if you choose Run As, but neither Java Applet nor Java Application appear as options, click in the Editor Window. This lets Eclipse know that you are running the .java file.

Click on the Main.java class. (SalesReport is no longer unknown, because we have defined it now.)

Save and Run it. The Console opens and is ready for you to provide input:

Click in the console window, type 2, and press Enter. You're asked for sales numbers for salespersons 1 and 2--enter any number for each and press Enter. Trace the code from the instantiation in Main().

The code works fine, but we can improve it. Previously, we wrote code to find the average and minimum sales, and to allow the user to set a number as a goal and determine which salespeople reached this goal. The new versions of the SalesReport application we'll write in this course will call upon many of the added potentials we learned earlier.


Design Pattern: Model/View/Controller

A common and well-known design pattern in object-oriented programming involves separating the various components of an application based on function. In keeping with object-oriented principles of modularity and the MVC design pattern, we'll separate the components in our construction. First, we will make the application, or Model class. The model class holds the code that defines a particular application. The application functionality required for SalesReport was the ability to determine the average sales, the minimum and maximum sales, and which salespeople surpassed a goal set by the user.

Separating Application from User Interface

Let's put our new version of the application in a different package.

In the java4_Lesson1 project, add a new class as shown:

Type SalesApp as shown in blue:

CODE TO TYPE: SalesApp
package salesGUI;

public class SalesApp {

    //array to hold sales of each salesperson
    private int[] sales;
    //variable for sales goal (to be established by user)
    private int salesBar; 
    private int totalSales;
    //why not average = totalSales/sales.length; here?
    private double average; 
    private int minIndex = 0;
    private int maxIndex = 0;
    SalesUserInterface myUserInterface;
}

Save it.

OBSERVE:
private int[] sales;
private int salesBar; 
private int totalSales;
private double average; 
private int minIndex = 0;
private int maxIndex = 0;
SalesUserInterface myUserInterface;

Here we set up variables for the model of our Sales Report Application. We created the sales array sales to hold each salesperson's sales figures. The salesBar variable will hold our sales goal. The totalSales and average variables will keep the totals and average sales. The minIndex and maxIndex will hold the locations in the sales array for the minimum sales and maximum sales.

SalesUserInterface myUserInterface is a reference to the GUI for the SalesUserInterface application that we'll be making in Lesson 3. We'll use it to send information to and from the GUI.

Now add the rest of the setters for the private variables. Add the blue code as shown:

CODE TO EDIT: SalesApp
package salesGUI;

public class SalesApp {

    //array to hold sales of each salesperson
    private int[] sales;
    //variable for sales goal (to be established by user)
    private int salesBar; 
    //sales of all sales people together
    private int totalSales;
    //why not average = totalSales/sales.length; here?
    private double average; 
    private int minIndex = 0;
    private int maxIndex = 0;
    SalesUserInterface myUserInterface;
    
    public void setMyUserInterface(SalesUserInterface myGUI){
        myUserInterface = myGUI;
    }
    
    public void setSales(int[] sales) {
        this.sales = sales;
        for (int i = 0; i < sales.length; i++)
            // checking to see if it's working
            System.out.println(sales[i]); 
        // data consistency
        setTotalSales(); 
    }

    public void setTotalSales() {
        totalSales = 0;
        for (int x = 0; x < sales.length; x++)
            totalSales += sales[x];
        setAverage(); // data consistency
    }
    
    public void setAverage() {
        if (sales.length != 0)
            average = (double) (totalSales / sales.length);
        System.out.println("totalSales is " + totalSales + " and sales.length is "
            + sales.length + " making average "
            + ((double) totalSales / sales.length));
    }
    
    public void setSalesBar(int goal){
        salesBar = goal;
    }
}

Save it.

OBSERVE: Setters
public void setMyUserInterface(SalesUserInterface myGUI)){
    myUserInterface = myGUI;
}
  
public void setSales(int[] sales) {
    this.sales = sales;
    for (int i = 0; i < sales.length; i++)
        // just checking to see if working
        System.out.println(sales[i]); 
    // data consistency
    setTotalSales(); 
}

public void setTotalSales() {
    totalSales = 0;
    for (int x = 0; x < sales.length; x++)
        totalSales += sales[x];
    setAverage(); // data consistency
}

public void setAverage() {
    if (sales.length != 0)
        average = (double) (totalSales / sales.length);
    System.out.println("totalSales is " + totalSales + " and sales.length is "
        + sales.length + " making average "
        + ((double) totalSales / sales.length));
} 
  
public void setSalesBar(int goal){
    salesBar = goal;
}     

The five methods above are setters for the variables sales, totalSales, and average. They are chained together; if we call setSales(), it calls setTotalSales(), which in turn calls setAverage(). This ensures that when we set the sales, the totalSales and average are up to date and consistent with the current sales array data. Finally, we set the salesBar variable with setSaleBar(int goal). The goal will be an integer that is set by the end user when we build our User Interface in a future lesson.

Now, add the getters. Add the code shown in blue:

CODE TO EDIT: SalesApp
package salesGUI;

public class SalesApp {

    //array to hold sales of each salesperson
    private int[] sales;
    //variable for sales goal (to be established by user)
    private int salesBar; 
    private int totalSales;
    //why not average = totalSales/sales.length; here?
    private double average; 
    private int minIndex = 0;
    private int maxIndex = 0;
    SalesUserInterface myUserInterface; 
    
    public void setMyUserInterface(SalesUserInterface myGUI){
        myUserInterface = myGUI;
    }
    
    public void setSales(int[] sales) {
        this.sales = sales;
        for (int i = 0; i < sales.length; i++)
            // just checking to see if working
            System.out.println(sales[i]); 
        // data consistency
        setTotalSales(); 
    }
    
    public void setTotalSales() {
        totalSales = 0;
        for (int x = 0; x < sales.length; x++)
            totalSales += sales[x];
        setAverage(); // data consistency
    }
    
    public void setAverage() {
        if (sales.length != 0)
            average = (double) (totalSales / sales.length);
        System.out.println("totalSales is " + totalSales + " and sales.length is "
            + sales.length + " making average "
            + ((double) totalSales / sales.length));
    }
    
    public void setSalesBar(int goal){
        salesBar = goal;
    }
    
    public int[] getSales() {
        return sales;
    }
    
    public double getAverage() {
        if (sales.length != 0)
            // cast so does not truncate int division
            return ((double) totalSales / sales.length); 
        else
            return average;
    }
    
    public int getBar() {
        return salesBar;
    }
    
    public int getTotalSales() {
        return totalSales;
    }
    
    public int getMin() {
        return minIndex;
    }
    
    public int getMax() {
        return maxIndex;
    }
}

Save it.

Let's take a closer look at the getAverage() getter:

OBSERVE
public double getAverage() {
    if (sales.length != 0)
        return ((double) totalSales / sales.length); 
    else
        return average;
}

If the sales array length (the user-entered number of salespersons) is not 0, getAverage() calculates the average before returning its value; otherwise, it returns the value of the average variable.

Now create a method that calculates the minimum and maximum sales, using comparisons. Add the code shown in blue:

CODE TO EDIT: SalesApp
package salesGUI;

public class SalesApp {

    //array to hold sales of each salesperson
    private int[] sales;
    //variable for sales goal (to be established by user)
    private int salesBar; 
    private int totalSales;
    //why not average = totalSales/sales.length; here?
    private double average; 
    private int minIndex = 0;
    private int maxIndex = 0;
    SalesUserInterface myUserInterface; 
    
    public void setMyUserInterface(SalesUserInterface myGUI){
        myUserInterface = myGUI;
    }
    
    public void setSales(int[] sales) {
        this.sales = sales;
        for (int i = 0; i < sales.length; i++)
            // just checking to see if working
            System.out.println(sales[i]); 
        // data consistency
        setTotalSales(); 
    }
    
    public void setTotalSales() {
        totalSales = 0;
        for (int x = 0; x < sales.length; x++)
            totalSales += sales[x];
        setAverage(); // data consistency
    }
    
    public void setAverage() {
        if (sales.length != 0)
            average = (double) (totalSales / sales.length);
        System.out.println("totalSales is " + totalSales + " and sales.length is "
            + sales.length + " making average "
            + ((double) totalSales / sales.length));
    }
    
    public void setSalesBar(int goal){
        salesBar = goal;
    }
    
    public int[] getSales() {
        return sales;
    }
    
    public double getAverage() {
        if (sales.length != 0)
            // cast so does not truncate int division
            return ((double) totalSales / sales.length); 
        else
            return average;
    }
    
    public int getBar() {
        return salesBar;
    }
    
    public int getTotalSales() {
        return totalSales;
    }
    
    public int getMin() {
        return minIndex;
    }
    
    public int getMax() {
        return maxIndex;
    }

    public void calculateMinMax() {
        int minimum = sales[0];
        int maximum = sales[0];
        // loop through the sales array to see each sales amount
        for (int x = 0; x < sales.length; x++) {
            //Check for max sale
            if (sales[x] > maximum) {
                maximum = sales[x];
                maxIndex = x;
            }
            else if (sales[x] < minimum) //Check for min sale
            {
                minimum = sales[x];
                minIndex = x;
            }
        }
        System.out.println("Maximum value is at index " + maxIndex
            + " (Salesperson " + (maxIndex + 1) + ") with value " + maximum);
        System.out.println("Minimum value is at index " + minIndex
            + " (Salesperson " + (minIndex + 1) + ") with value " + minimum);
        setAverage();
    }
}

Save it.

The calculateMinMax() method
public void calculateMinMax() {
    int minimum = sales[0];
    int maximum = sales[0];
    // loop through the sales array to see each sales amount
    for (int x = 0; x < sales.length; x++) {
        //Check for max sale
        if (sales[x] > maximum) {
            maximum = sales[x];
            maxIndex = x;
        }
        else if (sales[x] < minimum) //Check for min sale
        {
            minimum = sales[x];
            minIndex = x;
        }
    }
    System.out.println("Maximum value is at index " + maxIndex
        + " (Salesperson " + (maxIndex + 1) + ") with value " + maximum);
    System.out.println("Minimum value is at index " + minIndex
        + " (Salesperson " + (minIndex + 1) + ") with value " + minimum);
    setAverage();
}

The calculateMaxMin() sets the index of the maximum (maxIndex) and minimum (minIndex) values in the sales array. We set local variables minimum and maximum to the value in the sales[0] element as a starting point, then loop through the array. If the value in a particular index is greater than the previous maximum, we set maximum to that value. If the value in a particular index is not greater than the previous maximum, we check to see if the value is less than the previous minimum, and if so, we set minimum to the new value. We also keep track of the location of the indexes that contain the current minimum (minIndex) and maximum (maxIndex) values in the array.

Okay, now we'll add a method to determine who the top sales people are, so we can praise them and then give them even more work! Edit your code as shown in blue:

CODE TO EDIT: SalesApp
package salesGUI;

public class SalesApp {
 
    //array to hold sales of each salesperson
    private int[] sales;
    //variable for sales goal (to be established by user)
    private int salesBar; 
    private int totalSales;
    //why not average = totalSales/sales.length; here?
    private double average; 
    private int minIndex = 0;
    private int maxIndex = 0;
    SalesUserInterface myUserInterface;
    
    public void setMyUserInterface(SalesUserInterface myGUI){
        myUserInterface = myGUI;
    }
    
    public void setSales(int[] sales) {
        this.sales = sales;
        for (int i = 0; i < sales.length; i++)
            // just checking to see if working
            System.out.println(sales[i]); 
        // data consistency
        setTotalSales(); 
    }
    
    public void setTotalSales() {
        totalSales = 0;
        for (int x = 0; x < sales.length; x++)
            totalSales += sales[x];
        setAverage(); // data consistency
    }
    
    public void setAverage() {
        if (sales.length != 0)
            average = (double) (totalSales / sales.length);
        System.out.println("totalSales is " + totalSales + " and sales.length is "
            + sales.length + " making average "
            + ((double) totalSales / sales.length));
    }
    
    public void setSalesBar(int goal){
        salesBar = goal;
    }
    
    public int[] getSales() {
        return sales;
    }
    
    public double getAverage() {
        if (sales.length != 0)
            // cast so does not truncate int division
            return ((double) totalSales / sales.length); 
        else
            return average;
    }
    
    public int getBar() {
        return salesBar;
    }
    
    public int getTotalSales() {
        return totalSales;
    }
    
    public int getMin() {
        return minIndex;
    }
    
    public int getMax() {
        return maxIndex;
    }
    
    public void calculateMinMax() {
        int minimum = sales[0];
        int maximum = sales[0];
        // loop through the sales array to see each sales amount
        for (int x = 0; x < sales.length; x++) {
            //Check for max sale
            if (sales[x] > maximum) {
                maximum = sales[x];
                maxIndex = x;
            }
            else if (sales[x] < minimum) //Check for min sale
            {
                minimum = sales[x];
                minIndex = x;
            }
        }
        System.out.println("Maximum value is at index " + maxIndex
            + " (Salesperson " + (maxIndex + 1) + ") with value " + maximum);
        System.out.println("Minimum value is at index " + minIndex
            + " (Salesperson " + (minIndex + 1) + ") with value " + minimum);
        setAverage();
    }
    
    //method returns performance array to indicate success at reaching goal
    public int[] determineTopSalesPeople() {                      
        // System.out prints to console to be sure we got here--debugging tool
        System.out.println("I'm here and salesBar is " + salesBar);
    
        // an array with values of -1, 0, 1 to indicate success at reaching goal
        int[] performance = new int[sales.length]; 

        // Loop through the sales array and see who sold more than the sales bar
        for (int x = 0; x < sales.length; x++)
        {
            if (sales[x] > salesBar) {
                performance[x] = 1;
            }
            else if (sales[x] == salesBar) {
                performance[x] = 0;
            }
            else {
                performance[x] = -1;
            }
        }
        return performance;
    }
}

Save it.

The method determineTopSalesPeople() will return the top-performing salespeople in the sales array. It returns an integer array, associated with the sales array. If a salesperson's performance is below the salesBar, then we place a -1 in the corresponding slot of the integer array. If performance is equal to the salesBar, then we place a 0 in that slot. And if a salesperson's performance is above the salesBar, then we place a +1 in that slot.

Coming Attractions: The View

The "View" is exactly that: the View or GUI used to interact with the Model.

Eventually we'll create the Graphical User Interface (GUI) using Swing components, so in the next lesson we'll cover some Swing basics. Using javax.swing package is similar to using java.awt components. In fact, Swing components usually inherit from the awt components:

Duke will help you work out the design.