THE SYLLABUS TASK
What you need to build
Write a Java program to compute total, average & grade of students.
Full syllabus requirements: classes, fields and methods
Exactly ten students. For each: roll number, name, subject count (1–10), then one mark per line. Marks 0–100; roll numbers unique. Average grades: A≥90, B≥80, C≥70, D≥60, E≥40, otherwise F.
UNDERSTAND THE IDEA
Explanation
The driver creates an array containing exactly ten Student objects. Each student accepts a dynamically sized marks array, so the number of subjects need not match between students.
The constructor clones the supplied array to protect its marks from later caller changes. computeTotal resets its accumulator each time; computeAverage calculates total/subject count, and grade uses the published demonstration thresholds.
TURN THE IDEA INTO STEPS
Step-by-step algorithm
- Read ten unique student records and their subject counts.
- Validate and clone each marks list.
- Reset and sum marks in computeTotal.
- Divide by the positive subject count.
- Choose the grade from highest threshold downward and print all results.
SEE THE CORE OPERATION
Flowchart
This chart focuses on the named operation or core OOP decision. Diamonds show conditions; labeled branches show outcomes. Read it with the complete algorithm and source for input handling and other operations. Scroll within the diagram on a phone.
Validate and compute student result
Main.java
import java.util.*;
public class Main {
private static final Scanner IN = new Scanner(System.in).useLocale(Locale.ROOT);
static String text() {
if (!IN.hasNextLine()) throw new IllegalArgumentException("Incomplete input.");
String value = IN.nextLine().trim();
if (value.isEmpty() || value.length() > 200) throw new IllegalArgumentException("Text must have 1–200 characters.");
return value;
}
static int integer(int low, int high) {
int value = Integer.parseInt(text());
if (value < low || value > high) throw new IllegalArgumentException("Integer out of range.");
return value;
}
static double number(double low, double high) {
double value = Double.parseDouble(text());
if (!Double.isFinite(value) || value < low || value > high) throw new IllegalArgumentException("Number out of range.");
return value;
}
static void money(String label, double value) { System.out.printf(Locale.ROOT, "%s: %.2f%n", label, value); }
static class Student {
private final String name, rollNo;
private final double[] marks;
private double total, average;
Student(String rollNo, String name, double[] marks) {
if (marks.length == 0) throw new IllegalArgumentException("At least one subject required.");
for (double mark : marks) if (!Double.isFinite(mark) || mark < 0 || mark > 100) throw new IllegalArgumentException("Invalid mark.");
this.rollNo = rollNo; this.name = name; this.marks = marks.clone();
}
double computeTotal() { total = 0; for (double mark : marks) total += mark; return total; }
double computeAverage() { computeTotal(); average = total / marks.length; return average; }
String grade() { computeAverage(); return average >= 90 ? "A" : average >= 80 ? "B" : average >= 70 ? "C" : average >= 60 ? "D" : average >= 40 ? "E" : "F"; }
void displayResult() { String letter = grade(); System.out.printf(Locale.ROOT,"%s | %s | total %.2f | average %.2f | grade %s%n",rollNo,name,total,average,letter); }
}
// Exactly 10 students: roll/name/subject-count, then one mark per line for each.
public static void main(String[] args) {
try {
Student[] students = new Student[10]; Set<String> rolls = new HashSet<>();
for (int i = 0; i < students.length; i++) {
String roll = text(), name = text(); int subjects = integer(1, 10); double[] marks = new double[subjects];
for (int j = 0; j < subjects; j++) marks[j] = number(0,100);
if (!rolls.add(roll)) throw new IllegalArgumentException("Duplicate roll number.");
students[i] = new Student(roll,name,marks);
}
for (Student student : students) student.displayResult();
} catch (IllegalArgumentException e) { System.out.println("Invalid input: " + e.getMessage()); }
}
}
Copy a source file or download the project to preserve its file names.
USE THE RIGHT ENVIRONMENT
How to compile and run
Install a JDK (Java 11 or newer; JDK 17 is suitable), extract this project’s ZIP into its own folder, then open a terminal in that folder.
javac -encoding UTF-8 Main.java
java MainThe standalone source is named Main.java and its entry class is Main. You may also paste it into an online Java compiler and supply the sample input there. Choose Java explicitly; these pages do not change the site compiler or import code automatically.
Each experiment has its own folder because many use the public class Main. Compile and run one experiment at a time.
UNDERSTAND THE JAVA CODE
Line-by-line explanation
These steps follow the exact Java source above. Related statements are grouped; line numbers count blank lines and restart for each file. Start with main to follow execution, then open the constructors, methods or event handlers it uses.
Main.java
Lines 1–4Import utilities and create the shared input reader
import java.util.*;
public class Main {
private static final Scanner IN = new Scanner(System.in).useLocale(Locale.ROOT);java.util.* imports utility type names such as Scanner, Locale and collections. Main is the public class matching Main.java. The private static final IN field holds one shared Scanner for System.in; final prevents replacing that reference. The scanner uses Locale.ROOT.
Lines 5–10Read one nonempty trimmed input line
static String text() {
if (!IN.hasNextLine()) throw new IllegalArgumentException("Incomplete input.");
String value = IN.nextLine().trim();
if (value.isEmpty() || value.length() > 200) throw new IllegalArgumentException("Text must have 1–200 characters.");
return value;
}text checks whether a line exists, reads it and removes leading/trailing whitespace. Reject empty text and lengths above 200 by throwing IllegalArgumentException. Otherwise return the string. One field is read per line, so these helpers do not mix nextInt with leftover newlines.
Lines 11–15Parse and range-check an integer field
static int integer(int low, int high) {
int value = Integer.parseInt(text());
if (value < low || value > high) throw new IllegalArgumentException("Integer out of range.");
return value;
}Integer.parseInt converts the returned string to int or throws NumberFormatException, a subtype of IllegalArgumentException. Reject values outside the caller’s inclusive low/high limits, then return the accepted integer.
Lines 16–20Parse and range-check a finite decimal field
static double number(double low, double high) {
double value = Double.parseDouble(text());
if (!Double.isFinite(value) || value < low || value > high) throw new IllegalArgumentException("Number out of range.");
return value;
}Double.parseDouble reads the string as a double. Double.isFinite rejects NaN and infinities as well as the explicit low/high range check. Return only a finite accepted value; exceptions transfer control to a matching catch block.
Line 21Format a labelled numeric result consistently
static void money(String label, double value) { System.out.printf(Locale.ROOT, "%s: %.2f%n", label, value); }money is a formatting helper: %s prints the label, %.2f prints two decimal places, and %n ends the line. Locale.ROOT fixes locale-sensitive formatting. The helper can also display non-currency quantities; it does not change the stored value.
Lines 22–25Store each student’s identity, marks and calculated results
static class Student {
private final String name, rollNo;
private final double[] marks;
private double total, average;The final marks field is an array reference; final prevents reassigning the field, not changing array elements. total and average hold calculated values.
Lines 26–30Validate marks and copy the input array
Student(String rollNo, String name, double[] marks) {
if (marks.length == 0) throw new IllegalArgumentException("At least one subject required.");
for (double mark : marks) if (!Double.isFinite(mark) || mark < 0 || mark > 100) throw new IllegalArgumentException("Invalid mark.");
this.rollNo = rollNo; this.name = name; this.marks = marks.clone();
}Require at least one mark, check each finite value lies from 0 to 100, and assign marks.clone(). The clone gives the Student its own array so later changes to the caller’s array do not alter its recorded marks.
Lines 31–32Recompute total before average
double computeTotal() { total = 0; for (double mark : marks) total += mark; return total; }
double computeAverage() { computeTotal(); average = total / marks.length; return average; }computeTotal resets total before summing, so repeated calls do not double-count. computeAverage calls it and divides by the nonzero mark count using double arithmetic.
Lines 33–35Choose a grade from the highest threshold downward
String grade() { computeAverage(); return average >= 90 ? "A" : average >= 80 ? "B" : average >= 70 ? "C" : average >= 60 ? "D" : average >= 40 ? "E" : "F"; }
void displayResult() { String letter = grade(); System.out.printf(Locale.ROOT,"%s | %s | total %.2f | average %.2f | grade %s%n",rollNo,name,total,average,letter); }
}The conditional chain tests 90, 80, 70, 60 and 40 in descending order. displayResult calls grade first so total and average are ready before formatting. A computed average below 40 gets F.
Lines 36–40Prepare exactly ten student objects and unique rolls
// Exactly 10 students: roll/name/subject-count, then one mark per line for each.
public static void main(String[] args) {
try {
Student[] students = new Student[10]; Set<String> rolls = new HashSet<>();
for (int i = 0; i < students.length; i++) {The driver reserves ten Student reference slots and a HashSet of roll strings. Its loop must fill every slot; it does not accept an arbitrary student count.
Lines 41–44Read one student and protect against duplicate roll numbers
String roll = text(), name = text(); int subjects = integer(1, 10); double[] marks = new double[subjects];
for (int j = 0; j < subjects; j++) marks[j] = number(0,100);
if (!rolls.add(roll)) throw new IllegalArgumentException("Duplicate roll number.");
students[i] = new Student(roll,name,marks);Read identity, 1–10 subjects and each checked mark. Set.add returns false if that roll was already present. Construct the Student only after those reads and the uniqueness check succeed.
Lines 45–46Display all completed results
}
for (Student student : students) student.displayResult();After input for all ten students succeeds, call displayResult for each object. The enhanced for loop visits references already stored in the array.
Lines 47–49Report invalid input and close the enclosing scopes
} catch (IllegalArgumentException e) { System.out.println("Invalid input: " + e.getMessage()); }
}
}The catch handles IllegalArgumentException, including invalid numeric strings from the helpers, and prints its message. The final braces close main and Main. Java objects become eligible for garbage collection when no live reference needs them; this program does not manually free them.
FOLLOW THE STATE
Dry run
- A student receives marks 80 and 90.
- Total is 170, average is 85 and grade is B.
- Calling computeTotal a second time still returns 170 because total resets.
- Changing the caller’s original marks array does not change the stored clone.
CHECK THE BEHAVIOUR
Sample input & output
These outputs were captured by running the exact delivered Java project.
Sample 1
R01
Student 1
2
80
90
R02
Student 2
2
80
90
R03
Student 3
2
80
90
R04
Student 4
2
80
90
R05
Student 5
2
80
90
R06
Student 6
2
80
90
R07
Student 7
2
80
90
R08
Student 8
2
80
90
R09
Student 9
2
80
90
R10
Student 10
2
80
90
R01 | Student 1 | total 170.00 | average 85.00 | grade B
R02 | Student 2 | total 170.00 | average 85.00 | grade B
R03 | Student 3 | total 170.00 | average 85.00 | grade B
R04 | Student 4 | total 170.00 | average 85.00 | grade B
R05 | Student 5 | total 170.00 | average 85.00 | grade B
R06 | Student 6 | total 170.00 | average 85.00 | grade B
R07 | Student 7 | total 170.00 | average 85.00 | grade B
R08 | Student 8 | total 170.00 | average 85.00 | grade B
R09 | Student 9 | total 170.00 | average 85.00 | grade B
R10 | Student 10 | total 170.00 | average 85.00 | grade B
Sample 2
R01
Student 1
1
39
R02
Student 2
1
39
R03
Student 3
1
39
R04
Student 4
1
39
R05
Student 5
1
39
R06
Student 6
1
39
R07
Student 7
1
39
R08
Student 8
1
39
R09
Student 9
1
39
R10
Student 10
1
39
R01 | Student 1 | total 39.00 | average 39.00 | grade F
R02 | Student 2 | total 39.00 | average 39.00 | grade F
R03 | Student 3 | total 39.00 | average 39.00 | grade F
R04 | Student 4 | total 39.00 | average 39.00 | grade F
R05 | Student 5 | total 39.00 | average 39.00 | grade F
R06 | Student 6 | total 39.00 | average 39.00 | grade F
R07 | Student 7 | total 39.00 | average 39.00 | grade F
R08 | Student 8 | total 39.00 | average 39.00 | grade F
R09 | Student 9 | total 39.00 | average 39.00 | grade F
R10 | Student 10 | total 39.00 | average 39.00 | grade F
Common mistakes
- Reset total before summing again.
- Do not divide by zero subjects.
- Check grade thresholds in descending order.
WHY THIS GROWTH RATE?
Time and space complexity
O(Σsᵢ) marks processing for all students; O(Σsᵢ) stored marks.
Computing one total scans s marks. Average and grade may invoke that scan again, but a fixed number of scans is still O(s).
For ten students the work is proportional to the sum of their subject counts. Generalizing the student count gives O(ns) when every student has s subjects.
Cloning marks uses O(s) memory per student. Text output and roll-uniqueness tracking are additional work/storage.
These bounds describe the implemented data processing. Input/output text length, scheduling, framework rendering and runtime/library internals are identified separately where they matter. Educational limits bound the actual examples.
PREPARE FOR YOUR LAB VIVA
Related viva questions & answers
Try answering aloud, then expand to check your reasoning. Questions focus on this program’s classes, state and behavior.
Why does the constructor clone the marks array?
An array is mutable. Cloning prevents later changes through the caller’s original array reference from silently altering the student’s recorded marks.
Why must computeTotal set total back to zero?
The method can be called more than once by average and grade calculations. Without resetting, each call would add the same marks again and inflate the result.
Why can different students have different marks-array lengths?
Each Student holds its own dynamically allocated array. The driver reads that student’s subject count before allocating the corresponding marks list.
Why are grade conditions evaluated from 90 downward?
A high average also satisfies lower thresholds. Testing lower conditions first could assign a lower grade before reaching the correct higher one.
What exactly does Student[] students = new Student[10] allocate?
It allocates ten reference slots, not ten fully initialized Student instances. The driver constructs and assigns each student separately.
Are the published grade thresholds an official grading policy?
They are explicit assumptions for this lab because the syllabus does not give thresholds. A college-specific rule can replace grade() without changing the object-array design.