(See the previous and initial iteration.)
I have refactored the API based on excellent review by cbojar. Also, a honorary mention goes to janos for pruning some unnecessary code out of the transcript reading method.
Now, I have this:
Course.java
package net.coderodde.gpa;
/**
* This class implements a record for storing the grade of a course, and the
* amount of credits awarded for completing it.
*
* @author Rodion "rodde" Efremov
* @version 1.61 (Mar 21, 2016)
*/
public class Course {
private final int credits;
private final int grade;
public Course(int credits, int grade) {
this.credits = credits;
this.grade = grade;
}
public int getCredits() { return credits; }
public int getGrade() { return grade; }
}
Transcript.java
package net.coderodde.gpa;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* This class implements a transcript record that stores the course descriptors
* ({@link net.coderodde.gpa.Course}) for a student.
*
* @author Rodion "rodde" Efremov
* @version 1.61 (Mar 21, 2016)
*/
public class Transcript implements Iterable<Course> {
private final List<Course> courseList = new ArrayList<>();
public void addCourse(Course course) {
courseList.add(course);
}
@Override
public Iterator<Course> iterator() {
return courseList.iterator();
}
public double getGradePointAverage() {
int totalCredits = getTotalCredits();
int totalCreditWeightedGrades = 0;
for (Course course : this) {
totalCreditWeightedGrades += course.getCredits() *
course.getGrade();
}
return (1.0 * totalCreditWeightedGrades) / totalCredits;
}
public int getTotalCredits() {
int sum = 0;
for (Course course : this) {
sum += course.getCredits();
}
return sum;
}
}
TranscriptReader.java
package net.coderodde.gpa;
import java.io.InputStream;
import java.util.Scanner;
/**
* This class is responsible for loading a transcript from an input stream.
*
* @author Rodion "rodde" Efremov
* @version 1.61 (Mar 21, 2016)
*/
public class TranscriptReader {
private final Scanner scanner;
public TranscriptReader(InputStream in) {
this.scanner = new Scanner(in);
}
public Transcript readTranscript() {
Transcript transcript = new Transcript();
int lineNumber = 1;
while (scanner.hasNextLine()) {
String line = scanner.nextLine().trim();
if (line.equals("end")) {
// Used to end the command line session.
break;
}
if (line.isEmpty()) {
lineNumber++;
continue;
}
// Since 'line' was 'trimmed', there should not be any whitespace
// before the first token, and after the last one.
String[] parts = line.split("\\s*,\\s*");
if (parts.length != 2) {
System.err.println(
"Line " + lineNumber + " contains invalid number of " +
"tokens (" + parts.length + "). Should have exactly " +
"two: number of credits and the grade.");
lineNumber++;
continue;
}
String creditsString = parts[0];
String gradeString = parts[1];
int credits;
int grade;
try {
credits = Integer.parseInt(creditsString);
} catch (NumberFormatException ex) {
System.err.println(
"Invalid credit token on line " + lineNumber +
": " + creditsString);
++lineNumber;
continue;
}
try {
grade = Integer.parseInt(gradeString);
} catch (NumberFormatException ex) {
System.err.println(
"Invalid grade token on line " + lineNumber +
": "+ gradeString);
++lineNumber;
continue;
}
transcript.addCourse(new Course(credits, grade));
lineNumber++;
}
scanner.close();
return transcript;
}
}
App.java
package net.coderodde.gpa;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
/**
* This class implements a command line application for computing GPA (grade
* point average).
*
* @author Rodion "rodde" Efremov
* @version 1.61 (Mar 21, 2016)
*/
public class App {
public static void main(String[] args) {
if (args.length > 1) {
printHelp();
return;
}
InputStream in = null;
try {
in = args.length == 0 ? System.in : new FileInputStream(args[0]);
} catch (FileNotFoundException ex) {
// I catch FileNotFoundException in order to be able to print
// an easy to read error message.
System.err.println("ERROR: The file \"" + args[0] +
"\" does not exist.");
System.exit(1);
}
TranscriptReader transcriptReader = new TranscriptReader(in);
Transcript transcript = transcriptReader.readTranscript();
System.out.println(transcript.getGradePointAverage());
}
private static void printHelp() {
System.out.println("Usage: java -jar FILE.jar [grades.csv]");
System.out.println("Omit the only argument in order to input " +
"data from command line.");
}
}
Please, tell me anything that comes to mind.