Multiple similar methods to compute the average student grade
Since you are writing for Java 8, what you want to use is 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(() -&gt; 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.