Now that we’ve explored all of the different ways we can use strings in our programs, let’s walk through a worked example to see how we would go about building a useful program that uses everything we’ve learned so far.
Problem Statement
Consider the following problem statement:
Write a program that will calculate weighted grades for students in a college course. This program should only have a
main
method.
The input will be given in a comma-delimited format. The first line will contain a number of weights as floating-point numbers, separated by commas. The first entry should be ignored.
All input will be via the keyboard.
Each subsequent line of input will contain information for a student. The first entry on that line will contain that student’s name. The rest of the line will contain that student’s scores on each assignment as an integer value, separated by commas. Input will be terminated by the end of the input file, or by a blank line when input is provided via the terminal.
It is guaranteed that at least two lines of input will be provided, the first containing the weights and at least one additional line containing data for a student. In addition, it is guaranteed that each line of input will contain the same number of parts.
The program should output the student’s name, followed by a colon, and a space, and then the student’s score. The score should be formatted to be exactly 5 characters wide, with exactly two characters after the decimal point.
Complete your solution to this example in Example.java
, which is open to the left.
Sample Inputs & Outputs
Here’s an example of the expected input for the program:
Name,0.125,0.125,0.25,0.50
StudentA,75,80,85,90
StudentB,5,15,75,20
StudentC,85,90,70,75
Here is the correct output for that input:
StudentA: 85.63
StudentB: 31.25
StudentC: 76.88
Think and Design Before Coding
Start by sketching the control flow, what kind of loops are appropriate, what variables and arrays will be necessary? What packages will need to be imported?
Handling Input
Next, start with our standard program preamble that we’ve worked with previously in this course:
// Load required classes
import java.util.Scanner;
public class Example{
public static void main(String[] args) throws Exception{
// Scanner variable
Scanner reader;
reader = 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 skeleton above.
Parsing Weights
Next, we’ll need to parse the weights provided on the first line of the input. So, we can begin by reading that line of input:
String weightLine = reader.nextLine();
Then, we can separate that line into its individual parts using the split()
method:
String weightLine = reader.nextLine();
String[] weightParts = weightLine.split(",");
Once we’ve done that, we can populate an array of floating point numbers containing the weights. To do this, we know that the number of weights is one less than the size of the weightParts
array. However, to make things simpler, we’ll simply create an array with the same size and leave the first element blank. This will help us when we perform the second step below.
String weightLine = reader.nextLine();
String[] weightParts = weightLine.split(",");
double[] weights = new double[weightParts.length];
Next, we can iterate through the weightParts
array, and parse each entry to a floating point value and store it in the weights
array. In this case, we’ll use a For loop, but this time we’ll start iterating at 1 instead of 0. In this way, we’ll skip the first entry in weightParts
, which cannot be converted to a floating point value.
String weightLine = reader.nextLine();
String[] weightParts = weightLine.split(",");
double[] weights = new double[weightParts.length];
for(int i = 1; i < weights.length; i++){
weights[i] = Double.parseDouble(weightParts[i].trim());
}
Inside of the For loop, we are simply converting each element of weightParts
to a floating point value, and then storing the result in the corresponding element in weights
.
Also, notice that we’re using weights.length
in the Boolean condition of this For loop. In this case, we know that both arrays are the same size, so we can use either weights.length
or weightParts.length
here.
It is a generally good habit to always .trim()
your inputs before parsing if leading/trailing whitespace is unimportant. In our example
Name, 0.125, 0.125, 0.25, 0.50
would crash the program if .trim()
were not used.
Parsing Each Student
Once we’ve read the weights, we can parse the data for each student, calculate the result, and print the output, all in a single step.
First, since we are reading an unknown number of lines of input, we’ll need to use a While loop. We saw this loop earlier in this chapter, when we learned about how to handle parsing input of an unknown length.
String line = " ";
while(line.length() > 0){
line = reader.nextLine();
if(line.length() > 0){
// parse the input
}
}
Inside of that loop, once we’ve determined that we’ve indeed read a valid line of input, we can use the same split()
method as before to split the input into parts:
String[] parts = line.split(",");
Then, we want to calculate the student’s final grade. So, once again, we’ll create a sum variable and iterate through all of the parts. As before, we’ll start the For loop at 1, just to skip the first element for now:
String[] parts = line.split(",");
double totalScore = 0.0;
for(int j = 1; j < parts.length; j++){
totalScore += weights[j] * Integer.parseInt(parts[j].trim());
}
Inside of the For loop, we’ll multiply the weight of the assignment by the score. Since we don’t need to store the integer value of each score, we can simply convert it to an integer and then directly use it in our expression.
Formatting Output
Finally, we’ll need to provide our output as a formatted string. Since we want to make sure the output of the totalScore
variable is exactly 5 characters wide, with 2 characters after the decimal point, we’ll use the placeholder %5.2f
in the format string:
System.out.println(String.format("%s: %5.2f", parts[0], totalScore));
In the output line, we are providing "%s: %5.2f"
as the first input to the String.format()
method. In this way, we don’t have to create a separate variable to store the format string, simplifying our code. Then, the second input is the first element in the parts
array, which will contain the student’s name. Finally, the last input is the totalScore
variable, giving the student’s total score.