patternjavaMinor
Multiple similar methods to compute the average student grade
Viewed 0 times
thestudentcomputegradeaveragemethodsmultiplesimilar
Problem
I have bunch of similar methods in different classes to average student grades.
In the
In the
This one is in the
```
private static void calculateSubjectAvgGrade() {
ArrayList allSubjects = Main.getSubjectsInAllCourses();
for(int index = 0; index < allSubjects.size(); index++) {
System.out.println(index + ". " + allSubjects.get(index).getTitle());
}
System.out.print("Izvelieties prieksmetu ievodot ta numuru: ");
int number = Input.consoleIntIn();
double sum = 0;
int subjectsWithGrade = 0;
for (Course course : Main.courses) {
try {
sum += course.getAverageGradeInSubject(allSubjects.get(number));
subjectsW
In the
Student class:public double getAverageGrade() throws NoGradesForStudentException {
double sum = 0;
int totalGrades = 0;
ArrayList studentSubjects = getStudentSubjects();
for(Subject subject : studentSubjects) {
try {
sum += getAverageGradeInSubject(subject);
totalGrades++;
}
catch(NoGradesInSubjectException e) {
//everything is okey
}
}
if (totalGrades == 0) {
throw new NoGradesForStudentException("Student does not have any grades yet");
} else {
return sum/totalGrades;
}
}In the
GroupOfCourses class:public double getAverageGrade() throws NoGradesInCourseException {
double gradeSum = 0;
double studentsWithGrades = 0;
for(Student student : getStudents()) {
try {
gradeSum += student.getAverageGrade();
studentsWithGrades++;
}
catch (NoGradesForStudentException e) {
//viss kartiba, ja izmet so iznemumu
}
}
if (studentsWithGrades != 0) {
return gradeSum/studentsWithGrades;
} else {
throw new NoGradesInCourseException("There are no grades in course.");
}
}This one is in the
main and user input is mingled with the logic. But the logic is the same as in previous examples.```
private static void calculateSubjectAvgGrade() {
ArrayList allSubjects = Main.getSubjectsInAllCourses();
for(int index = 0; index < allSubjects.size(); index++) {
System.out.println(index + ". " + allSubjects.get(index).getTitle());
}
System.out.print("Izvelieties prieksmetu ievodot ta numuru: ");
int number = Input.consoleIntIn();
double sum = 0;
int subjectsWithGrade = 0;
for (Course course : Main.courses) {
try {
sum += course.getAverageGradeInSubject(allSubjects.get(number));
subjectsW
Solution
Since you are writing for Java 8, what you want to use is
This code is compact enough that near-duplication of code would not be a problem.
However, the
Note that taking the average of the average of grades in each subject is not necessarily the same as taking the average of grades. It may be appropriate to rename the method to make it clear that there is batching by subject. Similarly, your
DoubleStream.average(). Java 8 streams are a new and powerful technique that drastically changes how code can be written in Java.public class Student {
...
public double getAverageGrade() throws NoGradesForStudentException {
return getStudentSubjects().stream()
.mapToDouble(Subject::getAverageGradeInSubject)
.average()
.orElseThrow(() -> new NoGradesForStudentException("Student does not have any grades yet"));
}
}This code is compact enough that near-duplication of code would not be a problem.
However, the
NoGradesForStudentException would cause a bit of a problem. In particular, with a stream-based solution, ignoring cases where a student has no grade in a particular subject would be a tricky exercise in exception handling. A better approach is to embrace Java's convention for DoubleStream.average(), and change all of these getAverageGrade…() methods to return an OptionalDouble instead of a double. Then, the code would look like this:public class Student {
...
public OptionalDouble getAverageGrade() {
return getStudentSubjects().stream()
.mapToObj(Subject::getAverageGradeInSubject)
.filter(OptionalDouble::isPresent)
.mapToDouble(OptionalDouble::getAsDouble)
.average();
}
}Note that taking the average of the average of grades in each subject is not necessarily the same as taking the average of grades. It may be appropriate to rename the method to make it clear that there is batching by subject. Similarly, your
GroupOfCourses.getAverageGrade() needs to make it clear that it calculates the average of each student's grade.Code Snippets
public class Student {
...
public double getAverageGrade() throws NoGradesForStudentException {
return getStudentSubjects().stream()
.mapToDouble(Subject::getAverageGradeInSubject)
.average()
.orElseThrow(() -> new NoGradesForStudentException("Student does not have any grades yet"));
}
}public class Student {
...
public OptionalDouble getAverageGrade() {
return getStudentSubjects().stream()
.mapToObj(Subject::getAverageGradeInSubject)
.filter(OptionalDouble::isPresent)
.mapToDouble(OptionalDouble::getAsDouble)
.average();
}
}Context
StackExchange Code Review Q#85214, answer score: 5
Revisions (0)
No revisions yet.