I am writing a program to find and display the student with the highest GPA, as well as the student with the lowest GPA out of a class with 4 attributes (first name, last name, age, GPA).
The output for my code results in "build successful," but the parsing error still shows up and there isn't the proper output information.
public class app
{
public static void main(String args[ ])
{
student st1 = new student("Rebecca", "Collins", 22, 3.3);
student st2 = new student("Alex", "White", 19, 2.8);
student st3 = new student("Jordan", "Anderson", 22, 3.1);
student[ ] studentArray = new student[3];
studentArray[0] = st1;
studentArray[1] = st2;
studentArray[2] = st3;
var maxStudent = studentArray[0];
// Start at 1 because we assumed the first student in the array
// has the current max.
//
for (int i = 1; i < studentArray.length; i++)
{
// If the current student has a GPA higher than the student
// with the current max, make the current student the student
// with the current max.
//
if(studentArray[i].gpa > maxStudent.getGpa())
{
boolean max = false;
boolean min;
min = false;
for (student studentArray1 : studentArray) {
boolean gpa = false;
}
System.out.print("The highest GPA is: "+max);
System.out.println();
System.out.print("The lowest GPA is: "+min);
System.out.println();
System.out.println("Name: "+ studentArray[i].firstName + " "+ studentArray[i].lastName);
System.out.println("Age: "+ studentArray[i].age);
System.out.println("GPA: "+ studentArray[i].gpa);
}
}
public class student
{
//class variables
public String firstName;
public String lastName;
public int age;
public double gpa;
public int max = 0;
public int min = 0;
//constructor method
student(String a, String b, int c, double d)
{
firstName = a;
lastName = b;
age = c;
gpa = d;
}
student(String a, String b, int c, double d, int e, int f)
{
firstName = a;
lastName = b;
age = c;
gpa = d;
min = e;
max = f;
}
//a method that returns the student's complete name
String getInfo()
{
return getFirstName() +" " + getLastName() +" " + getMax();
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(String fn)
{
firstName = fn;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String ln)
{
lastName = ln;
}
public int getAge()
{
return age;
}
public void setAge(int x)
{
age = x;
}
public double getGpa()
{
return gpa;
}
public void getGpa(double g)
{
gpa = g;
}
public int getMax()
{
return max;
}
public void getMax(int e)
{
max = e;
}
public int getMin()
{
return min;
}
public void getMin(int f)
{
min = f;
}
}
I would appreciate any insight that addresses the error and solutions for what I can do to make this code work properly.
There are a number of (possible) issues with your posted code; you appear to be using an inner student class; your braces don't match up and your indentation doesn't seem to be consistent, and the var keyword doesn't exist in versions of Java prior to 10 (and we have no knowledge of your installed JDK or configured project compiler level). Your student(s) shouldn't have individual min and max fields.
There is some debate about the merits of a class with all public fields; but any possible advantage to that is negated when you also implement getters and setters for all of them.
You need two loops; one to find the min and max, one to display the student(s). Java naming conventions should be respected (class names start with a capital letter). And you have a getGpa(double) that should be a setter.
Fixing all of that, it might look something like
public class App {
public static class Student {
private String firstName;
private String lastName;
private int age;
private double gpa;
public Student(String a, String b, int c, double d) {
firstName = a;
lastName = b;
age = c;
gpa = d;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String fn) {
firstName = fn;
}
public String getLastName() {
return lastName;
}
public void setLastName(String ln) {
lastName = ln;
}
public int getAge() {
return age;
}
public void setAge(int x) {
age = x;
}
public double getGpa() {
return gpa;
}
public void setGpa(double g) {
gpa = g;
}
}
public static void main(String[] args) throws Exception {
Student st1 = new Student("Rebecca", "Collins", 22, 3.3);
Student st2 = new Student("Alex", "White", 19, 2.8);
Student st3 = new Student("Jordan", "Anderson", 22, 3.1);
Student[] studentArray = { st1, st2, st3 };
Student maxStudent = studentArray[0];
Student minStudent = studentArray[0];
for (int i = 1; i < studentArray.length; i++) {
if (studentArray[i].getGpa() > maxStudent.getGpa()) {
maxStudent = studentArray[i];
}
if (studentArray[i].getGpa() < minStudent.getGpa()) {
minStudent = studentArray[i];
}
}
System.out.printf("The highest GPA is: %.1f%n", maxStudent.getGpa());
System.out.printf("The lowest GPA is: %.1f%n", minStudent.getGpa());
for (Student s : studentArray) {
System.out.printf("Name: %s %s%n", s.getFirstName(), s.getLastName());
System.out.printf("Age: %d%n", s.getAge());
System.out.printf("GPA: %.1f%n", s.getGpa());
}
}
}
which I ran; producing
The highest GPA is: 3.3
The lowest GPA is: 2.8
Name: Rebecca Collins
Age: 22
GPA: 3.3
Name: Alex White
Age: 19
GPA: 2.8
Name: Jordan Anderson
Age: 22
GPA: 3.1
And, if you're using Java 8+, you could simplify the main code with DoubleSummaryStatistics by streaming the Student(s), mapping to the gpa value and then collecting the statistics. Like,
public static void main(String[] args) throws Exception {
Student st1 = new Student("Rebecca", "Collins", 22, 3.3);
Student st2 = new Student("Alex", "White", 19, 2.8);
Student st3 = new Student("Jordan", "Anderson", 22, 3.1);
Student[] studentArray = { st1, st2, st3 };
DoubleSummaryStatistics dss = Arrays.stream(studentArray).mapToDouble(Student::getGpa).summaryStatistics();
System.out.printf("The highest GPA is: %.1f%n", dss.getMax());
System.out.printf("The lowest GPA is: %.1f%n", dss.getMin());
Arrays.stream(studentArray).map(s -> String.format("Name: %s %s%nAge: %d%nGPA: %.1f", //
s.getFirstName(), s.getLastName(), s.getAge(), s.getGpa())).forEach(System.out::println);
}
Related
How can I break out of a loop when the user enters "done" and print the contents of what the user entered? Also, I would like to be able to find the smallest element of the array and the largest element of the array during the printing.
import java.util.Arrays;
public class array2 {
public static void main(String[] args) {
java.util.Scanner input = new java.util.Scanner(System.in);
input.useDelimiter(System.getProperty("line.separator"));
int numofpeople = 10;
Person[] persons = new Person[numofpeople];
for (int i = 0; i < numofpeople; i++) {
System.out.print("Enter the person's name: ");
String person = input.next();
if(person.equals("done")){break;}
System.out.print("Enter the persons's age: ");
int age = (Integer) input.nextInt();
persons[i] = new Person(person, age);
}
}
}
class Person implements Comparable<Person> {
public String person;
public Integer age;
public Person(String s, Integer g) {
this.person = s;
this.age = g;
}
#Override
public int compareTo(Person o) {
return (this.age>o.age?1:-1);
}
}
The break statement will make the program leave the for loop. You have no code to print the array outside of the for loop. In fact, there is no code outside of the loop. This will make your program exit since it is in the main method. So you need code to print the array.
Complete Solution Given all comments below:
import java.util.ArrayList;
public class Array2 {
public static void main(String[] args) {
java.util.Scanner input = new java.util.Scanner(System.in);
ArrayList<Person> persons = new ArrayList();
int numOfPeople = 10;
for (int i = 0; i < numOfPeople; i++) {
System.out.print("Enter the person's name: ");
String person = input.nextLine();
if (person.trim().equalsIgnoreCase("done")) {
break;
}
System.out.print("Enter the persons's age: ");
int age = Integer.parseInt(input.nextLine());
persons.add(new Person(person, age));
}
//Collections.sort(persons); //not sorting anymore
for (Person person : persons) {
System.out.println(person.name + ": " + person.age);
}
Person youngestPerson = getYoungest(persons);
Person oldestPerson = getOldest(persons);
System.out.println("Youngest: " + youngestPerson.name + ": " + youngestPerson.age);
System.out.println("Oldest: " +oldestPerson.name + ": " + oldestPerson.age);
}
public static Person getYoungest(ArrayList<Person> people) {
Person youngestPerson = null;
for (Person person : people) {
if (youngestPerson == null || person.age < youngestPerson.age) {
youngestPerson = person;
}
}
return youngestPerson;
}
public static Person getOldest(ArrayList<Person> people) {
Person oldestPerson = null;
for (Person person : people) {
if (oldestPerson == null || person.age > oldestPerson.age) {
oldestPerson = person;
}
}
return oldestPerson;
}
protected static class Person implements Comparable<Person> {
protected String name;
protected int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
#Override
public int compareTo(Person o) {
return (this.age > o.age ? 1 : -1);
}
}
}
import java.util.*;
class Distance {
private String name;
private int dist;
public Distance(String name, int dist) {
this.name = name;
this.dist = dist;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDist() {
return dist;
}
public void setDist(int dist) {
this.dist = dist;
}
public String toString() {
return "Distance [name=" + name + ", school street=" + dist + "]";
}
}
class DistanceComp {
public static Distance longdistance(Distance[] dim) {
Distance max = dim[0];
for (int i = 1; i < dim.length; i++) {
if (max.getDist() < dim[i].getDist())
max = dim[i];
}
return max;
}
public static Distance shortdistance(Distance[] dim) {
Distance min = dim[0];
for (int i = 1; i < dim.length; i++) {
if (min.getDist() > dim[i].getDist())
min = dim[i];
}
return min;
}
}
public class week03_01 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Distance[] dist = new Distance[3];
System.out.print(">> how many students? : ");
int num = in.nextInt();
for (int i = 0; i < num; i++) {
System.out.print(">> name and distance : ");
dist[i] = new Distance(in.next(), in.nextInt());
}
System.out.println("\na student with the longest commute to school : " + DistanceComp.longdistance(dist));
System.out.println("a student with the shortest commute to school : " + DistanceComp.shortdistance(dist));
System.out.println("school distance difference is " + );
}
}
I also want to print the "shool distance differecnce".
but it doesn't calculate. i think it has String types.
I think calculate only integer types in an array, but i don't know the code.
Or is s there any other way? Ask for advice.
In your DistanceComp class, create a method to subtract two Distances similar like you did for longdistance and shortdistance:
public static int subtractDistance(Distance dist1, Distance dist2) {
int difference = Math.abs(dist1.getDist() - dist2.getDist());
return difference;
}
Then, use that in your System.out:
System.out.println("school distance difference is " + DistanceComp.subtractDistance(DistanceComp.longdistance(dist), DistanceComp.shortdistance(dist)));
Some notes fyi:
Your code currently only works with 3 students.
Instead of using long names, assign them to a shorter-named variable. This helps with code readability.
I have an assignment that requires me to create a method called getExamRange that looks at an array which includes the exam scores of several students, takes the lowest and highest scores, and subtracts the minimum exam score from the maximum exam score. I also have to create a getMostImprovedStudent which run the getExamRange method on an array of Students and returns the student with the highest exam range. I'm having trouble getting the correct results when the code is run. What is causing this problem?
Here is the code for the Student.java class:
import java.util.*;
public class Student
{
private static final int NUM_EXAMS = 4;
private String firstName;
private String lastName;
private int gradeLevel;
private double gpa;
private int[] exams;
private int numExamsTaken;
/**
* This is a constructor. A constructor is a method
* that creates an object -- it creates an instance
* of the class. What that means is it takes the input
* parameters and sets the instance variables (or fields)
* to the proper values.
*
* Check out StudentTester.java for an example of how to use
* this constructor.
*/
public Student(String fName, String lName, int grade)
{
firstName = fName;
lastName = lName;
gradeLevel = grade;
exams = new int[NUM_EXAMS];
numExamsTaken = 0;
}
public int getExamRange()
{
Arrays.sort(exams);
int examScore1 = exams[0];
int examScore2 = 0;
int lastPos = 0;
for(int i = 0; i < exams.length - 1; i++)
{
lastPos++;
}
examScore2 = exams[lastPos];
return examScore2 - examScore1;
}
public String getName()
{
return firstName + " " + lastName;
}
public void addExamScore(int score)
{
exams[numExamsTaken] = score;
numExamsTaken++;
}
// This is a setter method to set the GPA for the Student.
public void setGPA(double theGPA)
{
gpa = theGPA;
}
/**
* This is a toString for the Student class. It returns a String
* representation of the object, which includes the fields
* in that object.
*/
public String toString()
{
return firstName + " " + lastName + " is in grade: " + gradeLevel;
}
}
and here is the code for the Classroom.java class:
public class Classroom
{
Student[] students;
int numStudentsAdded;
public Classroom(int numStudents)
{
students = new Student[numStudents];
numStudentsAdded = 0;
}
public Student getMostImprovedStudent()
{
int highestScore = 0;
int score = 0;
int location = 0;
int finalLocation = 0;
for(Student s: students)
{
score = s.getExamRange();
location++;
if(score > highestScore)
{
highestScore = score;
finalLocation = location;
}
}
return students[finalLocation - 1];
}
public void addStudent(Student s)
{
students[numStudentsAdded] = s;
numStudentsAdded++;
}
public void printStudents()
{
for(int i = 0; i < numStudentsAdded; i++)
{
System.out.println(students[i]);
}
}
}
Here are the directions for the assignment which state what the methods are supposed to do:
Taking our Student and Classroom example from earlier, you should fill in the method getMostImprovedStudent, as well as the method getExamRange. The most improved student is the one with the largest exam score range.
To compute the exam score range, you must subtract the minimum exam score from the maximum exam score.
For example, if the exam scores were 90, 75, and 84, the range would be 90 - 75 = 15.
Firstly let us look at the getExamRange function
public int getExamRange(){
if(exams == null ||exams.length == 0){
return 0;
}
int min = exams[0];
int max = exams[0];
for (int i : exams
) {
if(i<min){
min=i;
}
if(i>max){
max=i;
}
}
return max - min;
}
and now on getMostImprovedStudent
public Student getMostImprovedStudent()
{
if(students == null ||students[0] == null || students.length=0){
return null;
}
int highestScore = students[0].getExamRange();
int score = 0;
Student mostImprovedStudent = students[0]
for(int i=0;i<students.length;i++)
{
if(students[i]!=null){
score = students[i].getExamRange();
if(score > highestScore)
{
highestScore = score;
mostImprovedStudent = students[i];
}
}
}
return mostImprovedStudent;
}
As part of the curriculum at my school, we are working on some CodeHS Java.
There is one problem that I'm stuck on:
Taking our Student and Classroom example from earlier, you should fill in the method getMostImprovedStudent, as well as the method getExamRange. The most improved student is the one with the largest exam score range.
To compute the exam score range, you must subtract the minimum exam score from the maximum exam score.
For example, if the exam scores were 90, 75, and 84, the range would be 90 - 75 = 15.
This is the Student class which I added my method getExamRange().
import java.util.*;
public class Student
{
private static final int NUM_EXAMS = 4;
private String firstName;
private String lastName;
private int gradeLevel;
private double gpa;
private int[] exams;
private int numExamsTaken;
public static int[] examRange = new int[Classroom.numStudentsAdded];
private int i = 0;
/**
* This is a constructor. A constructor is a method
* that creates an object -- it creates an instance
* of the class. What that means is it takes the input
* parameters and sets the instance variables (or fields)
* to the proper values.
*
* Check out StudentTester.java for an example of how to use
* this constructor.
*/
public Student(String fName, String lName, int grade)
{
firstName = fName;
lastName = lName;
gradeLevel = grade;
exams = new int[NUM_EXAMS];
numExamsTaken = 0;
}
public int getExamRange()
{
Arrays.sort(exams);
examRange[i] = exams[exams.length-1] - exams[0];
i++;
return exams[exams.length-1] - exams[0];
}
public String getName()
{
return firstName + " " + lastName;
}
public void addExamScore(int score)
{
exams[numExamsTaken] = score;
numExamsTaken++;
}
// This is a setter method to set the GPA for the Student.
public void setGPA(double theGPA)
{
gpa = theGPA;
}
/**
* This is a toString for the Student class. It returns a String
* representation of the object, which includes the fields
* in that object.
*/
public String toString()
{
return firstName + " " + lastName + " is in grade: " + gradeLevel;
}
}
And this is the Classroom class in which I added the method getMostImprovedStudent().
import java.util.*;
public class Classroom
{
Student[] students;
static int numStudentsAdded;
public Classroom(int numStudents)
{
students = new Student[numStudents];
numStudentsAdded = 0;
}
public Student getMostImprovedStudent()
{
Arrays.sort(Student.examRange);
//return Student.examRange[0];
}
public void addStudent(Student s)
{
students[numStudentsAdded] = s;
numStudentsAdded++;
}
public void printStudents()
{
for(int i = 0; i < numStudentsAdded; i++)
{
System.out.println(students[i]);
}
}
}
I can get the exam Range by sorting the exams array then subtracting the smallest from the biggest, but once I do this, how do I find the student with the biggest exam range, and return it?
The way you would do this is looping through students, and have a variable to hold the biggest difference in score, and the most improved student:
public Student getMostImprovedStudent()
{
Student mostImproved = students[0];
int biggest = student[i].getExamRange();
for(int i = 1; i < students.length; i++) {
if(students[i].getExamRange() > biggest) {
mostImproved = students[i];
biggest = students[i].getExamRange();
}
}
return mostImproved;
}
However Java 8+ we can do:
public Student getMostImprovedStudent()
{
return Arrays.stream(students)
.max(Comparator.comparing(Student::getExamRange))
.get();
}
Which is assuming that students is not empty
As I explained in the comment above you can do it this way:
public Student getMostImprovedStudent() {
Student maxRangeStudent = null;
int maxRange = 0;
for (Student student: students) {
int curExamRange = student.getExamRange();
if (curExamRange > maxRange){
maxRangeStudent = student;
maxRange = curExamRange;
}
}
return maxRangeStudent;
}
I'm having a hard time trying to solve my problem. I have to sort students in descending order by highest average mark and also to show the average mark of all students. I will include my Main class and declarations from my other classes.
public Main()
{
ArrayList<Student> students = new ArrayList<Student>();
Student A = new Student("John", "Doe", 1000);
students.add(A);
Student B = new Student("Michael", "Hawk", 2000);
students.add(B);
Student C = new Student("Nicholas", "Johnson", 3000);
students.add(C);
HashMap<Integer, ArrayList<PassedExams>> map = new HashMap<Integer, ArrayList<PassedExams>>();
for (Student student : students)
{
map.put(student.getIndeks(), new ArrayList<PassedExams>());
}
for (Entry<Integer,ArrayList<PassedExams>> exam : map.entrySet())
{
if (exam.getKey() == 1000)
{
ArrayList<PassedExams> passedExam = exam.getValue();
passedExam.add(new PassedExams("CS102", 6));
passedExam.add(new PassedExams("CS220", 8));
exam.setValue(passedExam);
}
if (exam.getKey() == 2000)
{
ArrayList<PassedExams> passedExam = exam.getValue();
passedExam.add(new PassedExams("MA101", 10));
passedExam.add(new PassedExams("CS101", 7));
exam.setValue(passedExam);
}
if (exam.getKey() == 3000)
{
ArrayList<PassedExams> passedExam = exam.getValue();
passedExam.add(new PassedExams("CS115", 9));
passedExam.add(new PassedExams("MA102", 7));
exam.setValue(passedExam);
}
}
for (Student student : students)
{
System.out.println(student.toString() + " " + map.get(student.getIndex()));
}
}
`
public class PassedExams
{
private String code;
private Integer mark;
// get and set methods
// aswell as toString();
}
`
public class Student
{
private String name, surname;
private Integer index;
// get and set methods
// aswell as toString();
}
EDIT: Adding input and output
What is seen by default:
Student Name: John Surname: Doe Index: 1000 [Predmet: Code: CS102 Mark: 6, Predmet: Code: CS220 Mark: 8]
Student Name: Michael Surname: Hawk Index: 2000 [Predmet: Code: MA101 Mark: 10, Predmet: Code: CS101 Mark: 7]
Student Name: Nicholas Surname: Johnson Index: 3000 [Predmet: Code: CS115 Mark: 9, Predmet: Code: MA102 Mark: 7]
What should be seen after sort:
Student Name: Michael Surname: Hawk Index: 2000 [Predmet: Code: MA101 Mark: 10, Predmet: Code: CS101 Mark: 7]
Student Name: Nicholas Surname: Johnson Index: 3000 [Predmet: Code: CS115 Mark: 9, Predmet: Code: MA102 Mark: 7]
Student Name: John Surname: Doe Index: 1000 [Predmet: Code: CS102 Mark: 6, Predmet: Code: CS220 Mark: 8]
And total average mark:
Total average mark from students is: 7.83
Also I guess I should change from Integer to Double because of the line above.
Draken is right, it's more elegant to model the passed exams list as property of a student. However, you can sort your students with the way things are.
When you want to define an order on a list in Java you can write a special Comparator:
//sorting starts here
Collections.sort(students, new Comparator<Student>() {
#Override
public int compare(Student o1, Student o2) {
double sum1 = 0, sum2 = 0;
for (PassedExams pe : map.get(o1.getIndex())) sum1+=pe.mark;
for (PassedExams pe : map.get(o2.getIndex())) sum2+=pe.mark;
sum1 /= map.get(o1.getIndex()).size();
sum2 /= map.get(o2.getIndex()).size();
return Double.compare(sum2, sum1);
}
});
Here's the elegant way to do it (I'm using Java 1.7, so please ignore the lack of predicates!)
Main
public class App {
public static void main(String[] args) {
new App();
}
public App()
{
ArrayList<Student> students = new ArrayList<Student>();
Student A = new Student("John", "Doe", 1000);
students.add(A);
Student B = new Student("Michael", "Hawk", 2000);
students.add(B);
Student C = new Student("Nicholas", "Johnson", 3000);
students.add(C);
for (Student student : students)
{
if (student.getIndex() == 1000)
{
student.getPassedExamList().add(new PassedExam("CS102", 6));
student.getPassedExamList().add(new PassedExam("CS220", 8));
}
if (student.getIndex() == 2000)
{
student.getPassedExamList().add(new PassedExam("MA101", 10));
student.getPassedExamList().add(new PassedExam("CS101", 7));
}
if (student.getIndex() == 3000)
{
student.getPassedExamList().add(new PassedExam("CS115", 9));
student.getPassedExamList().add(new PassedExam("MA102", 7));
}
}
for (Student student : students)
{
System.out.println(student.toString() + " " + student.getPassedExamList());
}
Collections.sort(students);
System.out.println("\nSorted\n");
for (Student student : students)
{
System.out.println(student.toString() + " " + student.getPassedExamList());
}
System.out.println("\nCalculating average\n");
double total = 0;
double count = 0;
for (Student student : students)
{
count += student.getPassedExamList().size();
total += student.getTotalMarks();
}
DecimalFormat df = new DecimalFormat("0.##");
System.out.println("Average is " + df.format(total / count));
}
}
Passed exam
public class PassedExam {
private String code;
private Integer mark;
public PassedExam(String code, int mark){
this.code = code;
this.mark = mark;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Integer getMark() {
return mark;
}
public void setMark(Integer mark) {
this.mark = mark;
}
#Override
public String toString() {
return "PassedExams{" +
"code='" + code + '\'' +
", mark=" + mark +
'}';
}
}
Student
public class Student implements Comparator<Student>, Comparable<Student> {
private String name, surname;
private Integer index;
private List<PassedExam> passedExamList = new ArrayList<PassedExam>();
public Student(String name, String surname, int index){
this.name = name;
this.surname = surname;
this.index = index;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Integer getIndex() {
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public List<PassedExam> getPassedExamList() {
return passedExamList;
}
public int getTotalMarks(){
int total = 0;
for(PassedExam exam : passedExamList)
total += exam.getMark();
return total;
}
#Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", surname='" + surname + '\'' +
'}';
}
#Override
public int compare(Student o1, Student o2) {
return Integer.compare(o2.getTotalMarks(), o1.getTotalMarks());
}
#Override
public int compareTo(Student o) {
return Integer.compare(o.getTotalMarks(), this.getTotalMarks());
}
}
The thing that allows me to call Collections.sort() is the fact that I implement Comparable<Student> on the Student class. I then add the method compareTo() and state how I want it sorting. Since you wanted descending order, I've reverse the normal order of comparison. You can read more on Comparable here
I don't think you need a hashMap
First add all students in the list.
Implement a Comparator, the comparator would probably have a method: getExamsForStudent()
Then sort the list using Collections.sort(list, comparator).