What we'll build
A small report-card program. It reads students and their marks, then prints a report with each student's average and grade, the class topper, and how many students got each grade. It uses almost everything from this course.
Step 1: plan before coding
- A
Studentclass holds a name and a list of marks, and can work out its own average and grade. mainreads the input and creates the students. Bad marks are skipped with try/catch.- Then we print the report: a loop for each student, a stream to find the topper, and a map to count grades.
Tip: Professional programmers plan in plain words first. Splitting a big problem into small steps is the most important programming skill of all.
Step 2: the whole program
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
import java.util.TreeMap;
class Student {
private final String name;
private final List<Integer> marks = new ArrayList<>();
Student(String name) {
this.name = name;
}
String getName() { return name; }
void addMark(int mark) {
if (mark < 0 || mark > 100) {
throw new IllegalArgumentException("mark out of range: " + mark);
}
marks.add(mark);
}
double average() {
return marks.stream().mapToInt(m -> m).average().orElse(0);
}
char grade() {
double avg = average();
if (avg >= 90) return 'A';
if (avg >= 75) return 'B';
if (avg >= 50) return 'C';
return 'F';
}
}
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int count = Integer.parseInt(sc.nextLine().trim());
List<Student> students = new ArrayList<>();
for (int i = 0; i < count; i++) {
String[] parts = sc.nextLine().trim().split(" ");
Student s = new Student(parts[0]);
for (int j = 1; j < parts.length; j++) {
try {
s.addMark(Integer.parseInt(parts[j]));
} catch (IllegalArgumentException e) {
System.out.println("Skipping '" + parts[j] + "' for " + s.getName());
}
}
students.add(s);
}
System.out.println("=== Report Card ===");
TreeMap<Character, Integer> gradeCounts = new TreeMap<>();
for (Student s : students) {
System.out.printf("%-6s %6.1f %c%n", s.getName(), s.average(), s.grade());
gradeCounts.put(s.grade(), gradeCounts.getOrDefault(s.grade(), 0) + 1);
}
Student top = students.stream().max(Comparator.comparingDouble(Student::average)).get();
System.out.println("Topper: " + top.getName());
System.out.println("Grades: " + gradeCounts);
}
}Input (what the user types)
4 Asha 95 88 92 Ravi 70 65 abc 80 Meera 45 52 38 Arjun 88 79 150 91
Output
Skipping 'abc' for Ravi
Skipping '150' for Arjun
=== Report Card ===
Asha 91.7 A
Ravi 71.7 C
Meera 45.0 F
Arjun 86.0 B
Topper: Asha
Grades: {A=1, B=1, C=1, F=1}Step 3: what each part uses
| Feature | Where | Module |
|---|---|---|
| Classes, private fields, constructor | Student | 09 |
| Throwing and catching exceptions | addMark and the inner loop | 12 |
| ArrayList and TreeMap | marks, students, gradeCounts | 13 |
| Streams and a Comparator | average() and the topper | 14, 15 |
| printf formatting | the report lines | 03 |
In %-6s the -6 means “at least 6 characters wide, lined up on the left”, and %6.1f means “6 wide with 1 decimal”. That's what makes the columns line up.
Make it your own
- Add a
highest()method toStudentthat returns their best mark. - Print the students sorted from the best average to the worst.
- Print the class average at the end.