Chapter 7.J

Java Loops

Loops in Java

Subsections of Java Loops

While Loop

Now that we’ve added terminal entry to our tool set, let’s look at how we can use each of these looping constructs in Java. First, here is the general syntax for a While loop in Java:

while(<Loop Condition>){
  <loop code block>
}

As expected, Java will first evaluate the <Loop Condition> to a single Boolean value. If that value is true, it will execute the instructions in the <loop code block>, which can be one or more lines of code, or even additional constructs. Once the <loop code block> execution is complete, the program will return to the top of the loop and evaluate the <Loop Condition> again. It will repeat this process until the expression evaluates to false. Of course, if the expression is false initially, the code in the <loop code block> will not be executed at all.

It is very important to remember that the Loop Condition is enclosed by parentheses ( ), while the block of code that should be executed if that expression is true is enclosed by curly braces { }, just like in an If statement, class body or method body

Let’s take a look at a quick example, just to see how this construct works in practice. First, let’s consider the program represented by this flowchart from earlier in the chapter:

Looping Program Flowchart Looping Program Flowchart

This flowchart corresponds to the following code in Java. In this case, we’ll assume x is hard-coded for now:

int x = 8;
int i = 1;
while(x >= i){
  System.out.println(i);
  i = i + 1;
}

By walking through the execution of this program, we see that it will output all integers from $ 1 $ through $ 8 $. If the user inputs a number less than $ 1 $, the program will not produce any output at all.

Do-While Loop

Java also includes another form of a While loop, known as a Do-While loop . Here is the general syntax for a Do-While loop in Java:

do{
  <loop code block>
}while(<Loop Condition>);

In this code, Java will first execute all of the code in the <loop code block> without evaluating any Boolean expressions. The main use of a Do-While loop is to guarantee that the code inside the loop is executed at least once. Then, it will evaluate the <Loop Condition> to a Boolean value. If that value is true, then the program will repeat the code in the <loop code block> once again. If it is false at any time it is evaluated, then the program will continue running the code directly below the Do-While loop.

It is very important to remember that the Loop Condition is enclosed by parentheses ( ), while the block of code that should be executed if that expression is true is enclosed by curly braces { }, just like in an If statement, class body or method body. In addition, notice that Java also requires a semicolon ; after the Boolean expression.

Let’s take a look at a quick example, just to see how this construct works in practice. First, let’s consider the program represented by this flowchart from earlier in the chapter:

Do While Loop Flowchart Do While Loop Flowchart

This flowchart corresponds to the following code in Java. In this case, we’ll assume x is hard-coded for now:

int x = 8;
int i = 1;
do{
  System.out.println(i);
  i = i + 1;
}while(x >= i);

By walking through the execution of this program, we see that it will output all integers from $1$ through $8$.

However, this program will perform differently than a While loop if the user inputs a number less than $1$. Since this program is built using a Do-While loop, it will always execute the code inside the loop first, so the program will always print at least 1 to the terminal. After that, the program will evaluate x >= i, which will be false if x is less than $1$, so it will terminate. Notice that this is different than the While loop on the previous page, which will not produce any output at all in this instance.

Therefore, it is very important to understand how each loop functions and choose the appropriate loop for each task. In practice, Do-While loops are used very rarely, but they can be useful in some instances.

Uncommonly Used

In practice, Do-While loops are not commonly used in Java. We’re including them here just in case you see them in other code you find, but we generally don’t recommend using them in your own code unless the situation calls for this loop structure.

For Loop

The syntax for a For loop in Java is a bit complex, and has many different parts. Here’s the general format:

for(<initializers>; <loop condition>; <updaters>){
  <loop code block>
}

Let’s break this syntax down into each individual part to understand how it works.

First, the <initializers> section is used to create and initialize any variables that we’d like to use as loop counters inside of the loop. For example, we could use int i = 0 in that section to create a single integer variable i and set its initial value to 0. We may also declare multiple variables of the same type, separating each with a comma or ,. In that instance, we could say int i = 0, j = 1, which would declare two new integer variables, i and j, and set their values to 0 and 1, respectively. Finally, we can choose to leave that section blank, as it is not required at all. In either case, we must end that section with a semicolon ; before moving on to the next section. This section is executed just once, before the first iteration of the loop itself. We’ll explore a full example below.

The <loop condition> section is the same as in a While loop. It must evaluate to a single Boolean value, either true or false, which is used to determine if the loop continues executing or not. This section must also end with a semicolon ;, and is generally required in a For loop.

Finally, the <updaters> section can include one or more statements used to increment (update) the values of the loop counter variables. This section is executed at the end of each iteration of the loop, before the Boolean expression is evaluated again. Generally, we would include code such as i++ or i = i + 2 in this section. Similar to the <initializers> section, multiple update statements can be included in this section, separated by a comma ,. So, we could use i++, j++ to increment the values of both i and j in the same loop.

Let’s look at an example. Here’s a flowchart from earlier in this chapter containing a For loop:

For Loop Flowchart For Loop Flowchart

This flowchart corresponds to the following code in Java. Once again, we’ll assume x is hard-coded for now:

int x = 8;
for(int i = 1; i <= x; i++){
  System.out.println(i);
}

In this For loop, we can clearly see the three parts. First, we have int i = 0 as the initializer. It creates a new variable and gives it an initial value. Then, we see i <= 8 is our loop’s Boolean condition. Finally, we have i++ as the lone updater, since it updates the value of the loop counter i by incrementing it by $ 1 $.

To understand how this For loop functions in practice, let’s look at an equivalent While loop:

int x = 8;

//initializers
int i = 1;

while(i <= x){
  System.out.println(i)
  
  //updaters
  i++;
}

These loops are exactly identical in terms of how the code is executed. In a For loop, the initializers are performed once at the beginning, before the loop really starts. Then, we evaluate the Boolean expression and determine if we should enter the loop and perform those operations. At the end of each loop iteration, the updaters are executed to update the values of any loop counters, before the loop repeats back to the Boolean expression.

For Loops and Variable Scope

For loops in Java have one important caveat when it comes to variable scope. As expected, any variables declared in the initializers section of a For loop may be accessed from within the For loop itself, but they may also be accessed in the Boolean expression or the updaters section as well. They cannot, however, be accessed outside of the For loop.

However, any variables declared inside the For loop cannot be accessed in either the Boolean expression or the updaters. In effect, a For loop in Java has two levels of scope, one containing the variables declared in the initializers, and another for just the code inside the loop. Generally this doesn’t pose a problem, but it is an important distinction to be aware of.

Here’s one more example of a For loop in Java, using three loop counters instead of just one:

int sum = 0;
for(int i = 0, j = 1, k = 20; i + j < k; i++, j++, k--){
  sum += i + j + k;
}

Notice that there are three variables initialized in the initializer, which is int i = 0, j = 1, k = 20. In addition, there are three variables updated in the updater, which is i++, j++, k--. While it is uncommon for most programmers to use multiple loop counters in a single For loop, it is important to understand how it can be done.

Missing Curly Braces?

In Java, it is possible to have loop constructs without curly braces, just like we saw for conditional constructs in an earlier. In that case, the next line of code immediately following the while or for will be the only line repeated inside of the loop.

Consider this code for example:

int x = 0;
while(x < 5)
  x++;

This code is valid, and will compile and run properly. However, just like with conditional constructs, if we want to add a second line to the inside of the loop, we’ll need to remember to add curly braces for our code to work properly.

In addition, we can omit parts of a For loop, as in this example:

int x = 0;
for( ; x < 5 ; )
  x++;

Here, we’ve omitted both the initializers and updaters of the For loop. Those parts are considered optional, and either one can be left out. However, in this case, it may make more sense to convert this to a While loop instead.

Loop Control

Java also includes both the break and continue keywords. They are pretty straightforward and easy to follow.

Break

Here’s the flowchart showing a program with a break statement from earlier in this chapter:

Break Flowchart Break Flowchart

This flowchart corresponds to the following code in Java. Once again, we’ll assume x is hard-coded for now:

int x = 8;
int i = 1;
while(true){
  if(x % i != 0){
    System.out.println(i);
    break;
  }
  i = i + 1;
}

This code shows us an example of an infinite While loop, sometimes referred to as a While-True loop. In this case, we are simply using the keyword true as our Boolean expression, so the loop will always continue to run unless we use the break keyword to leave it. So, in this code, once x % i != 0 evaluates to true, we reach the break keyword and then exit the loop.

Continue

Here’s the flowchart showing a program with a continue statement from earlier in this chapter:

Continue Flowchart Continue Flowchart

This flowchart corresponds to the following code in Java. Once again, we’ll assume x is hard-coded for now:

int x = 8;
for(int i = 1, i <= x; i++){
  if(x % i != 0){
    continue;
  }
  System.out.println(i);
}

In this example, we see a For loop that contains a continue statement inside of it. Here, it is important to remember that, even though the continue statement tells the program to go back to the beginning of the loop, the updater i++ will still be executed before evaluating the Boolean expression i <= x. This is one of the unique features of a For loop compared to a similar While loop. If we rewrote this program using a While loop, we’d have to remember to update the value of i manually before the continue keyword, as in this example:

int x = 8;
int i = 1;
while(i <= x){
  if(x % i != 0){
    i++;
    continue;
  }
  System.out.println(i);
  i++;
}

Notice that we had to include an extra i++ before the continue keyword. Otherwise, the loop would repeat without updating the value of i, causing it to become infinitely stuck.

Try It!

Try the preceding code and see what happens when you remove the i++ statement directly above the continue keyword. Does it cause any problems?

Hint: When using a program via the terminal, you can press CTRL + C to stop a running program if it locks up or starts infinitely looping.

Loop Subgoals

Of course, we can identify some subgoals for working with loops in Java as well. Let’s take a look at them and see how we can use them to help understand loops a little bit better.

Evaluating Loops

Here are the subgoals for evaluating a loop in Java:

1. Identify Loop Parts

The first and most important part of evaluating a loop is to identify each part of the loop structure. Here is a list of things to look for:

  1. Start Condition - variables that are initialized when the loop is first reached (For loops only)
  2. Update Condition - variables that are updated after each loop iteration (For loops only)
  3. Loop (termination) Condition - the Boolean expression that will terminate the loop when it becomes false
  4. Loop Body - the lines of code which will be repeated on each loop iteration

Depending on which type of loop we are looking at, we may not find all of the parts listed above.

2. Trace the Loop

Once we’ve identified all of the parts of the loop, we can then trace the loop to see how it updates values on each iteration. The easiest way to do this is to write down the values of each variable before the loop starts, and then update those values as the loop iterates. We’ve already seen a few examples for how to trace a loop in this chapter, and we’ll do one more on the next page.

Writing Loops

We can also use subgoals to help write loops. Here are the subgoals we’ll use:

1. Determine Purpose of the Loop

Before writing a loop, we must decide what we’re using it for. Once we know that, then we can determine which type of loop would be best. For example, if we are using the loop to repeat steps until a particular Boolean condition is false, we’ll probably want to use a While loop. If we want to make sure the loop executes at least once, we may want to use a Do-While loop instead. Finally, if we are iterating a specific number of times, or across a particular data structure (as we’ll see in a later chapter), we should probably use a For loop.

2. Define and Initialize Variables

Once we’ve determined which loop structure we’re going to use, we’ll need to define and initialize any variables needed by the loop. Specifically, we may want to define the initial value of our iterator variable to some value if we are using one.

3. Determine Termination Condition

Next, we’ll need to determine the Boolean condition that should cause the loop to terminate. For example, we may want the loop to repeat until our iterator variable i becomes 5. So, we’ll want to invert that Boolean statement to find the statement that can be used inside the loop to determine whether it should continue.

Therefore, the termination condition i == 5 should become the continuation condition i < 5. We could also use i != 5, however we could run into an issue where the value of i skips over 5 for some reason in our code, creating an infinite loop. By using i < 5 instead, the loop will terminate as soon as i becomes 5 or greater, which is safer overall.

4. Write Loop Body

Once we’ve set up the loop itself, we can write the code we’d like repeated inside of the loop body. One thing we must be very careful about is making sure we are properly updating our loop’s iteration variable toward the termination condition. If we forget to do that, we may run into a condition where the loop will not terminate at all, causing our programs to lock up. In a later chapter, we’ll discuss concepts such as loop invariants that will help us with this step.

Input Loops

Now that we know how to use loops, let’s discuss a common structure for reading and parsing user input from the terminal using a loop.

Reading Terminal Input

In many of our prior projects, we’ve seen the Scanner class used to read input from the keyboard’s input stream, which is System.in in Java. Typically we use code similar to this:

import java.util.Scanner;

public class ReadInput {

    public static void main(String[] args){
        // Create the Scanner object to read from the terminal
        Scanner scanner = new Scanner(System.in);

        int x = scanner.nextInt();
        double d = scanner.nextDouble();

        System.out.println(x + " + " + d + " = " + (x + d));
    }
}

Let’s look at some of the important lines of code in this short example:

  • import java.util.Scanner; - this line at the very top of our program is an import statement. It tells Java that we’d like to import, or use, the Scanner class from the java.util library, which is part of the standard Java Development Kit (JDK). These lines must be at the top of our file, before any class declarations. We’ll learn more about importing and using library classes a bit later in this course.
  • Scanner scanner = new Scanner(System.in) - this line serves two purposes. First, it creates a new instance of a Scanner object, which is stored in the variable scanner. Notice that these names are case-sensitive! The capitalized Scanner is the name of the class, which in this case is used like a data type similar to int or double. The lowercase scanner is the variable name where the object created from that class is stored. We’ll learn about objects and classes a bit later in this course. The last part new Scanner(System.in) creates a new Scanner object and tells it to read input from the System.in stream, which is the connected to the keyboard in the terminal.
  • scanner.nextInt() - this method will read the next piece of input from the keyboard and try to convert it to an integer. If it can, it will store it in the variable x. However, if the next piece of input is not an integer, this will cause an error and crash the program. We’ll learn how to catch and handle these errors a bit later in this course, but for now we’ll have to assume that our users are providing input that matches the expected structure.
  • scanner.nextDouble() - similar to the previous line, this will read the next piece of input and try to convert it to a floating-point value. If it can, it will store it in the variable d.

Of course, there are much more advanced ways to use a Scanner in Java. We’ll learn more in a later chapter, or we can always refer to the Java Documentation for the Scanner class.

Reading Multiple Lines

Many times, we want our programs to be able to read multiple lines of input, and to continue to read input until the end of the stream is reached. In that case, we can use a While loop and a few different methods in the Scanner class to accomplish this.

Consider this code example:

import java.util.Scanner;

public class ReadManyLines {

    public static void main(String[] args){
        // Create the Scanner object to read from the terminal
        Scanner scanner = new Scanner(System.in);

        int countLetters = 0;
        int countLines = 0;

        // Repeat while the Scanner thinks there is another line to be read
        while(scanner.hasNextLine()){
            // Read the next line of input
            String input = scanner.nextLine();
            
            // Check to see if the line is empty after removing all leading and trailing whitespace
            if (input.trim().length() == 0){
            
                // If the line is empty, break out of the while loop
                break;
            }
            
            // parse the line of input and perform the calculations needed
            countLetters += input.length();
            countLines++;
        }

        // all input has been read at this point
        System.out.println("I read " + countLetters + " characters of input across " + countLines + " lines");
    }
}

This program will read input from the terminal until no more input is provided, and it will count the total number of lines and characters read from the terminal’s input stream. To do this, it uses a few new methods of the Scanner class:

  • scanner.hasNextLine() - this method will return true if there is more input to be read from the input stream. So, we use this in the While loop to repeat until there is no more input to be read.
  • scanner.nextLine() - this method reads an entire line of input from the input stream. It will keep reading characters until it reaches a newline character \n. Remember that when the user presses the ENTER key on a keyboard, that will add a newline character \n to the keyboard’s input stream, signalling the end of a line of input.

This works well in many situations, but there is one important thing we must remember - the keyboard input stream System.in is an infinite stream! This means that is never ends, and the scanner.hasNextLine() method will always return true when reading input from the terminal.

So, how do we get our program to end? In most cases, we will simply add an If statement inside of the loop to check and see if the line of input is empty, and then break out of the loop if it is. In this code, we use the Boolean expression input.trim().length() == 0 to check and see if the String input is empty. We’ll learn more about these string methods in a later part of this course.

Avoiding Dangling Newlines

This new method of reading input, which uses scanner.nextLine() to read an entire line of input instead of scanner.nextInt() or scanner.nextDouble() to just read a single element from the input, comes with one major caveat that developers must be aware of - the dangling newline.

Consider this code:

import java.util.Scanner;

public class DanglingNewline {

    public static void main(String[] args){
        // Create the Scanner object to read from the terminal
        Scanner scanner = new Scanner(System.in);

        // Repeat while the Scanner thinks there is another line to be read
        while(scanner.hasNextLine()){
            // Read the next line of input
            String name = scanner.nextLine();

            // Check to see if the line is empty after removing all leading and trailing whitespace
            if (name.trim().length() == 0){
            
                // If the line is empty, break out of the while loop
                break;
            }

            // Read an integer from input
            int age = scanner.nextInt();
            System.out.println("Greetings " + name + "! Your age is " + age);
        }
    }
}

This program will read the name and age of a user from input, one per line. So, let’s assume that we are providing the following input:

Willie
42
Wildcat
37

When we run this program, however, we see that an error occurs:

Dangling Newline Dangling Newline

Why did this happen? Let’s look at the stream that would be read by the program, complete with the newline characters:

Willie\n42\nWildcat\n37\n

Now, let’s step through the program and check all the Scanner methods that read the input to see where the error occurs! First, the scanner.hasNextLine() method will return true since the stream still has input to be read. Next, the scanner.nextLine() method will read the next line of input, up to and including the newline \n characater. So, it will read "Willie" from the stream and store it in name, and then remove it and the following newline. Now we have this in the stream:

42\nWildcat\n37\n

Good so far! After that, the scanner.nextInt() method will try to read the next item in the stream and convert it to an integer. It sees the characters "42" followed by a newline, and it knows that it can convert "42" to an integer, so it will read those characters and store the value 42 in the age variable. However, the nextInt() method does not remove the newline character from the stream. So, we’ll be left with this content in the stream:

\nWildcat\n37\n

Here’s where things go wrong. The scanner.hasNextLine() method will still return true since there is input to be read. So, the scanner.nextLine() method will read input until it reaches a newline character \n. In this case, it sees that immediately, so it will store the empty string "" in the name variable and then remove the newline from the stream. So, we are left with this content in the stream.

Wildcat\n37\n

This means that, when the scanner.nextInt() method is called, the first thing it reads is not a number, so it throws an InputMismatchException and crashes the program!

This happens because had a dangling newline that was left in the input stream. To fix this, the easiest way is to always read an entire line of input, and then use other methods to parse and convert that line as needed. In general, we want to avoid mixing the Scanner methods that read entire lines and the methods that just read individual elements of input. In most cases, we should use one or the other.

In this case, we can change the scanner.nextInt() to Integer.parseInt(scanner.nextLine()) to read the entire next line of input and then convert it to an integer:

import java.util.Scanner;

public class DanglingNewline {

    public static void main(String[] args){
        // Create the Scanner object to read from the terminal
        Scanner scanner = new Scanner(System.in);

        // Repeat while the Scanner thinks there is another line to be read
        while(scanner.hasNextLine()){
            // Read the next line of input
            String name = scanner.nextLine();

            // Check to see if the line is empty after removing all leading and trailing whitespace
            if (name.trim().length() == 0){
            
                // If the line is empty, break out of the while loop
                break;
            }

            // Read an integer from input
            int age = Integer.parseInt(scanner.nextLine());
            System.out.println("Greetings " + name + "! Your age is " + age);
        }
    }
}

With that change in place, the program will run correctly!

Dangling Newline Dangling Newline

Prompting for Input

Lastly, it is usually considered good practice to include prompts that tell the user what kind of input is expected. For example, we can update the previous code to include some prompts, using the System.out.print() method:

import java.util.Scanner;

public class DanglingNewline {

    public static void main(String[] args){
        // Create the Scanner object to read from the terminal
        Scanner scanner = new Scanner(System.in);

        System.out.print("Enter a name: ");

        // Repeat while the Scanner thinks there is another line to be read
        while(scanner.hasNextLine()){

            // Read the next line of input
            String name = scanner.nextLine();

            // Check to see if the line is empty after removing all leading and trailing whitespace
            if (name.trim().length() == 0){
            
                // If the line is empty, break out of the while loop
                break;
            }

            System.out.print("Enter an age as an integer: ");
            // Read an integer from input
            int age = Integer.parseInt(scanner.nextLine());
            System.out.println("Greetings " + name + "! Your age is " + age);

            System.out.print("Enter a name: ");
        }
    }
}

Notice that the first prompt has to be printed before the while loop - this is because the scanner.hasNextLine() method will wait until a line of input has been provided before it allows the program to continue, even if we haven’t actually read that line of input yet. So, we have to print our prompt before checking for a line of input to be read from the terminal.

While this is considered best practice in the real world, we typically will not include these prompts for input in our programs in this course. The major reason for removing the input prompts is to ensure that the automated grader is just reading the output produced by your program and not the prompts for input.

Without this change, we’d have to be very careful to make sure that our input prompts also perfectly matched what the automated grader was expecting. Since we really want the focus to be on the output produced and not the input prompts, we’ve made the decision to simply not include input prompts in our programs in this course.

My Program is Stuck

There are some instances where it may look like your program has stopped working, especially when dealing with loops and user input. If that happens, try these steps:

  1. Try typing on the keyboard. If text appears in the terminal, that means your program is just waiting for you to provide input.
  2. If no text appears when you type on the keyboard, try the keyboard shortcut CTRL + C (or CMD + C on a Mac) to interrupt the program.
  3. If that does not work, close the terminal window or tab where the program is running. That should stop any programs running in that terminal.
  4. If Codio or your system appears to still be running slow, as a last resort try restarting the computer where the program was running. In Codio, click the Project menu and choose Restart Box… to restart the underlying Linux system where your program is running.

Subsections of Input Loops

Accumulator Pattern

One common use for loops is the accumulator pattern. An accumulator simply computes some values based on a large amount of data, such as the sum, maximum, minimum, average, or count. In programming, a pattern is simply a common structure that is used to solve a recurring problem in code. Since many programs end up needing a loop that acts an accumulator, we’ve developed a common pattern that can be used in our code to solve this problem.

The simplest example of the accumulator pattern is a program that will sum up a set of values. Consider this code:

import java.util.Scanner;

public class Accumulator {

    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);

        // Initialize accumulator variables
        int sum = 0;

        // Read and parse input
        while(scanner.hasNextLine()){
            String input = scanner.nextLine();
            if (input.trim().length() == 0){
                break;
            }
            int x = Integer.parseInt(input);

            // Update accumulator variables
            sum += x;
        }

        // Display results
        System.out.println("The sum of these values is " + sum);
    }
}

In this example, we see the general structure for the accumulator pattern:

  • Before the loop, we initialize any accumulator variables to their default values. Since we are computing the sum, we should start at 0. However, when computing other values, such as the product, we may need to initialize these values to 1, -1, or some other value. It doesn’t always make sense to start at 0.
  • Inside of the loop, we read the input and parse it. Then, we will update the accumulator variables before repeating the loop.
    • Many times we also include a conditional statement here and only update the variables if the Boolean condition is true. For example, we could easily modify this program to only sum up the even values using a conditional statement.
  • After the loop ends, we can then display the accumulated results. In some cases, such as when we are computing the average of a list of values, we may have to perform some final calculations here before displaying the result.

We’ll see this pattern appear many times in our programs from this point onward, so it is helpful to make note of it and observe when it is used in practice.

A Worked Example

YouTube Video

Video Materials

Updated Code

The code in this example video contains a slightly older version of the input code that also includes the ability to read from a file, which can be ignored. We recommend using the code shown below instead. The rest of the video is still applicable to this example.

Now that we’ve learned some of the different looping constructs in Java, let’s work through a completed example to see how we can use loops to build more advanced programs.

Problem Statement

For this example, we’d like to build a program that matches the following problem statement:

Write a program that will accept a series of integers from the keyboard, one per line. It will continue to accept integers from the user until the user inputs 0. If the user inputs a negative number, the program should print "Error! Positive Integers Only" and continue to receive input. Once the user inputs 0, the program should print the sum and average of the positive integers input by the user.

Flowchart

Before we start coding, let’s try to draw a flowchart for this program, just to make sure we understand the control flow it will use. We know that we need to get keyboard input, convert it to an integer then take some actions based on its value.

Initial Flow Chart Initial Flow Chart

We also know we will have to repeat this an indeterminate number of times, and a While loop is the preferred construct to use for this. So lets add a While loop. While we are at it, make sure that if 0 is input for x, we do nothing and let the program flow back to the start of the while loop. So, our final flowchart may look like this.

Revised Flow Chart Revised Flow Chart

There are a few important items to note in this flowchart:

  1. We added a conditional statement inside of the loop to check if x > 0. If this is false, we’ll print the error and loop back to the top. This is keeps us from adding 0 or values less than 0 to our sum.
  2. The x < 0 and x > 0 paths are mutually exclusive. We should probably consider using If-Else If-Else statements to communicate this intentional exclusivity when we write our code.
  3. The flowchart is a “complete” example that shows the overall control flow of the program, but it skips many details:
    1. How can we check if x != 0 that first time if we don’t get a value for x until we are in the loop?
    2. How do we calculate the average?
    3. Where does the Scanner code to handle input go?

Keep in mind that a flowchart is an abstraction of the code we need to write; it is just a model containing some important subset of the details. This one is sufficient to ensure we use the right loop and if statements.

Code the Boiler Plate

Lets start by adding the boiler plate code for setting up the class, the main() method and input. Let’s store this program in Example.java

import java.util.Scanner;

public class Example{
  
    public static void main(String[] args){
        // Create the Scanner object to read from the terminal
        Scanner scanner = new Scanner(System.in);
          
        /* -=-=-=-=- MORE CODE GOES HERE -=-=-=-=- */
      
    }
  
}

For the rest of this example, we’ll look at a smaller portion of the code. That code can be placed where the MORE CODE GOES HERE comment is in the working copy above.

Handling Input

Next, we want to build a program that can accept a series of integers from the user. Since we don’t know how many we’ll get, we’ll probably want to use some sort of a While loop. So, let’s add in a While loop and start building from there:

while(){
  
}

Inside of that loop, we know we need to read an integer from the user, so we can add the code for that as well:

while(){
  int x = Integer.parseInt(scanner.nextLine());
}

Next, we need to determine when the loop should terminate. In this case, we can go back to the problem statement above, where we see the line:

It will continue to accept integers from the user until the user inputs 0.

So, we might be tempted to do something like this:

while(x != 0){
  int x = Integer.parseInt(scanner.nextLine());
}

However, that code has a very important error in it. We haven’t declared x outside of the While loop, so when we try to compile this code we’ll get a compiler error. So, let’s resolve that error:

int x = 0;
while(x != 0){
  x = Integer.parseInt(scanner.nextLine());
}

When we compile and run this fragment, we should see that it never prompts for input. We need to initialize x to some value, so we quickly chose to initialize it to $ 0 $. However, by doing so, we should hopefully see that it will never enter the loop, since x != 0 will immediately be false. So, let’s set x = 1 instead for now:

Sentinel Values

In the above loop, “zero” may be referred to as a sentinel value , which is a value to watch for and alter the program’s behavior when it occurs. It is important to ensure we don’t inadvertently initialize our variable to a sentinel value.

int x = 1;
while(x != 0){
   x = Integer.parseInt(scanner.nextLine());
}

That’s a good start! As we continue to work on this program, we’ll revisit the structure of this code and see that there might be a better way to do it. For now, let’s press on ahead.

Invalid Inputs

Next, we can handle the error messages for any invalid inputs. From the problem statement:

If the user inputs a negative number, the program should print “Error! Positive Integers Only” and continue to receive input.

This case is pretty simple. We want to check if the user has entered a number less than $ 0 $. If so, we should just print out an error message, but continue to receive input. The word “continue” gives us an important clue toward how we can accomplish this task. Here’s one way to build this test into our program:

int x = 1;
while(x != 0){
  x = Integer.parseInt(scanner.nextLine());
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
    continue;
  }
  //logic here
}

In this code, if the user enters a negative number, we simply use an If statement to find that error, print out the error message, and then the continue keyword will cause the program to loop back to the beginning and read another input. Of course, we can do this without the continue keyword as well, using an If-Else statement instead:

int x = 1;
while(x != 0){
  x = Integer.parseInt(scanner.nextLine());
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
  }else{
    //logic here
  }
}

Either approach works equally well. Some developers prefer to avoid the use of continue and break keywords because they make it more difficult to understand loops, while other developers prefer to avoid having the logic of the loop nested several layers deep in many If-Else statements. It is really up to developer preference and the overall style guide that is in effect.

For this example, we’ll use the code with the continue keyword, just to get a better understanding of how it works.

Program Logic

Once we’ve handled our user inputs, we can include our program’s logic. In this case, we need to calculate both the sum and average of all of the numbers entered by the user. Calculating the sum is pretty simple! We can just include a sum variable and add each input to that variable:

int x = 1;
int sum = 0;
while(x != 0){
  x = Integer.parseInt(scanner.nextLine());
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
    continue;
  }
  sum += x;
}
System.out.println("Sum: " + sum);

To calculate the average of a set of numbers, we must remember the formula $ \text{Average} = \frac{\text{Sum}}{\text{Count}} $. Since we already are tracking the sum, we can just add another variable to keep track of the count of inputs:

int x = 1;
int sum = 0;
int count = 0;
while(x != 0){
  x = Integer.parseInt(scanner.nextLine());
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
    continue;
  }
  sum += x;
  count++;
}
System.out.println("Sum: " + sum);
System.out.println("Average: " + (double)sum / count);

Notice in the code above we are casting sum as a double when we calculate the average. Otherwise, the program will perform floored integer division, which isn’t what we want in this case.

Now, let’s see if this works.

Try It!

See if you can complete the program using the example code above in a file name Example.java. Does it work correctly?

There is a very important logic bug in the code above. See if you can figure out what it is before continuing!

Logic Bug

The code above contains a very important logic error. To find that error, let’s run the program by entering the numbers 1 and 3, followed by 0 to end the program. Here’s the output we should receive:

Logic Error Output Logic Error Output

Notice that the sum of 4 is correct, but the average is 1.333333 instead of 2. Why is that?

If we look closely at our program above, we notice that the program will still increment count when we input 0 to stop the program. So, it believes that we’ve entered three numbers, when we actually only entered two. Therefore, we need to figure out some way to prevent the program from incrementing count when we input 0.

There are several ways we can accomplish this. One way is to simply wrap the program logic in another If-Then statement, as in this example:

int x = 1;
int sum = 0;
int count = 0;
while(x != 0){
  x = Integer.parseInt(scanner.nextLine());
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
    continue;
  }
  if(x != 0){
    sum += x;
    count++;
  }
}
System.out.println("Sum: " + sum);
System.out.println("Average: " + (double)sum / count);

We could also use a break keyword to exit the loop as soon as we realize that the user’s input is 0:

int x = 1;
int sum = 0;
int count = 0;
while(x != 0){
  x = Integer.parseInt(scanner.nextLine());
  if(x == 0){
    break;
  }
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
    continue;
  }
  sum += x;
  count++;
}
System.out.println("Sum: " + sum);
System.out.println("Average: " + (double)sum / count);

Either approach works. Again, it just depends on how we’d like to style our code so that it is clear and easy to understand.

In addition, we could rearrange the code just a bit to make the While loop’s Boolean expression a bit clearer:

int sum = 0;
int count = 0;
int x = Integer.parseInt(scanner.nextLine());
while(x != 0){
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
  }else{
    sum += x;
    count++;
  }
  x = Integer.parseInt(scanner.nextLine());
}
System.out.println("Sum: " + sum);
System.out.println("Average: " + (double)sum / count);

In this example, we read an input from the user before entering the loop. So, if the user initially inputs 0, it skips the loop entirely, which is fine. If the input is not 0, then it will enter the loop and check to see if it is negative. If it is, it will print the error message, but if not, it will update the sum and count accordingly. Finally, at the end of the loop, it will read another input from the user, then immediately loop back to the beginning and make sure that the user has not input 0 before starting the next iteration. Also, notice that this code does not include any break or continue keywords.

However, this code does include two lines that read input from the user. This violates one principle of writing good code, which is DRY, or Don’t Repeat Yourself. If at all possible, we want to avoid writing two lines of code that perform the same action. So, while this code may be a bit simpler to read, it may also be a bit more difficult to update later. For example, what if a future developer needs to change this program to read floating point numbers instead of integers? If that developer does not update both lines that read input from the file, it could make the program unusable!

Finally, it may be best to simply include several If-Else If-Else statements to make everything clear in the code, as in this example:

int x = -1;
int sum = 0;
int count = 0;
while(x!= 0){
  x = Integer.parseInt(scanner.nextLine());
  if(x < 0){
    System.out.println("Error! Positive Integers Only");
  }else if (x > 0) {
    sum += x;
    count++;
  }
}
System.out.println("Sum: " + sum);
System.out.println("Average: " + (double)sum / count);

This code is probably one of the best ways to accomplish this task. We use a clear string of If-Else If-Else statements to show that there are two possible operations inside of the While loop. Either the input is negative, in which case we print an error message and restart the loop; or the input is positive and accepted for our calculations. IF the input is 0, we allow the program to flow up to while loop condition–which will terminate the loop.

Subsections of A Worked Example