Õppetund 20/140

Õppetunnile juurdepääsu kontrollimine...

Video ja kirjalik õppetund · 26 min

Project: Build a Console-Based Grade Calculator

Build a menu-driven grade calculator that reads and validates marks, tracks totals, highs and lows, and calculates a final grade.

EelvaadeSubtiitridVarsti

Vaatad tasuta eelvaate õppetundi.

Project Overview

So far, we have learned Java's fundamental building blocks separately. In this project, we combine them into one complete interactive console application: a Grade Calculator. It reads a student's name and the mark for each subject, checks every input, and reports the total, average, highest and lowest marks, the passed and failed subjects, a grade and a final result. It is menu-driven, so it keeps running until the user chooses to exit.

The project uses almost everything from this module: constants, String values, operators and casting, Scanner input with normalization, if-else, switch, for, while, do-while, break, continue, range validation and a text block.

Learning Objectives

After completing this project, you will be able to:

  • Build a complete console application
  • Collect user input
  • Validate required text and numeric ranges
  • Read multiple marks using loops
  • Calculate a total using an accumulator
  • Track highest and lowest values
  • Count passed and failed subjects
  • Calculate a grade based on the average
  • Build a menu-driven program
  • Use switch, break, and continue practically
  • Combine multiple programming concepts together

Build It Yourself First

Before reading any of our code, build the program yourself from the requirements below. You decide how to structure it; everything fits in one main method.

Requirements

  1. Menu. Show the menu below, read an option, act on it, and show the menu again until the user chooses Exit.
  2. Student name. Option 1 first asks for the student's name. A name that is empty or only spaces is rejected and asked for again.
  3. Subject count. Next it asks for the number of subjects, which must be 1 to 10. A value outside that range is asked for again.
  4. Marks. Then it asks for one mark per subject, 0 to 100. An invalid mark is asked for again for the same subject.
  5. Pass rule. A subject is passed with a mark of 40 or more. If any subject is below 40, the grade is F and the result is Failed, whatever the average.
  6. Grade rules. If every subject is passed, the grade comes from the average in the table below, and the result is Passed.
  7. Result. Print the student, the subject count, the total out of the maximum possible (subjects × 100), the average, the highest and lowest mark, the passed and failed subject counts, the grade, the result and a performance message: Excellent performance (A), Very good performance (B), Good performance (C), Satisfactory performance (D), Passed, but improvement is needed (E) or One or more subjects were failed (F).
  8. Rules and exit. Option 2 prints the grade rules. Option 3 prints Grade calculator closed. and ends the program. Any other number prints Invalid option. Choose 1, 2, or 3.

The menu:

text
=== Grade Calculator ===

1. Calculate student result
2. View grade rules
3. Exit

Choose an option:

The grade rules for a student who passed every subject:

Average MarkGrade
80 to 100A
70 to under 80B
60 to under 70C
50 to under 60D
40 to under 50E

The average is a double, so it can fall between whole numbers: an average of 79.67 is still a B. You may assume the user types a whole number at every numeric prompt; text such as eighty needs exception handling, which comes later (see Current Input Limitation).

Acceptance Criteria

Each item is behaviour you can check by running your program. The messages are the ones the reference solution uses.

  • Option 2 prints the grade rules and shows the menu again
  • Option 4 prints Invalid option. Choose 1, 2, or 3. and shows the menu again
  • Option 3 prints Grade calculator closed. and the program ends
  • An empty or spaces-only name prints Student name is required. and asks again
  • Subject counts 0 and 11 print Subject count must be between 1 and 10. and ask again; 1 and 10 are accepted
  • Marks -1 and 101 print Mark must be between 0 and 100. and ask again for the same subject; 0 and 100 are accepted
  • Marks 90, 85 and 80 give Total marks: 255 out of 300, Average mark: 85.0, grade A and result Passed
  • A single subject with mark 80 gives grade A, with 70 grade B, and with 40 grade E and result Passed: a mark or average exactly on a boundary belongs to the higher band
  • A single subject with mark 75 gives highest and lowest mark 75 and grade B
  • Marks 100, 100 and 39 give grade F and result Failed, although the average is about 79.7
  • Marks 0, 0 and 0 give total 0, average 0.0, grade F and result Failed
  • After every result, the menu is shown again

Sample Run

With the inputs 1, an empty name, Nur, 0, 2, 101, 75, 39, 4 and 3, the session looks like this:

text
=== Grade Calculator ===

1. Calculate student result
2. View grade rules
3. Exit

Choose an option: 1

--- Student Information ---
Enter student name:
Student name is required.
Enter student name: Nur
Enter number of subjects (1-10): 0
Subject count must be between 1 and 10.
Enter number of subjects (1-10): 2

--- Enter Subject Marks ---
Enter mark for subject 1 (0-100): 101
Mark must be between 0 and 100.
Enter mark for subject 1 (0-100): 75
Enter mark for subject 2 (0-100): 39

=== Student Result ===
Student: Nur
Subjects: 2
Total marks: 114 out of 200
Average mark: 57.0
Highest mark: 75
Lowest mark: 39
Passed subjects: 1
Failed subjects: 1
Grade: F
Result: Failed
Performance: One or more subjects were failed

=== Grade Calculator ===

1. Calculate student result
2. View grade rules
3. Exit

Choose an option: 4
Invalid option. Choose 1, 2, or 3.

=== Grade Calculator ===

1. Calculate student result
2. View grade rules
3. Exit

Choose an option: 3
Grade calculator closed.

The average 57.0 is in the D band, but the failed subject makes the grade F.

Try it before reading on. The rest of this lesson builds a reference solution step by step; compare it with yours.

Program Flow

From here on, we build the reference solution. Its overall flow:

Diagrammi joonistamine…

Step 1: Define Constants

We will store the program's fixed rules as constants. This reduces unexplained magic numbers in the code.

java
static final int CALCULATE_RESULT_OPTION = 1;
static final int VIEW_RULES_OPTION = 2;
static final int EXIT_OPTION = 3;

static final int MINIMUM_SUBJECT_COUNT = 1;
static final int MAXIMUM_SUBJECT_COUNT = 10;

static final int MINIMUM_MARK = 0;
static final int MAXIMUM_MARK = 100;
static final int PASSING_MARK = 40;

Step 2: Create the Scanner

java
Scanner scanner = new Scanner(System.in);

In this project, following our previous convention, we will generally read input using scanner.nextLine(). When a numeric value is required, we will parse it with Integer.parseInt(...).

Step 3: Create the Menu Loop

The menu must be displayed at least once. Therefore, do-while is suitable:

java
int menuOption;
do {
    // Display menu
    // Read option
    // Process option
} while (menuOption != EXIT_OPTION);

Step 4: Validate Student Name

The student name cannot be blank:

java
String studentName;
while (true) {
    System.out.print("Enter student name: ");
    studentName = scanner.nextLine().strip();
    if (studentName.isBlank()) {
        System.out.println("Student name is required.");
        continue;
    }
    break;
}

We do not know in advance how many attempts the user will need, so a while (true) loop keeps asking: an invalid name leads to continue (try again), a valid one to break (leave the validation loop). Steps 5 and 8 use the same pattern for the subject count and each mark.

Step 5: Validate Subject Count

java
int subjectCount;
while (true) {
    System.out.print(
            "Enter number of subjects ("
            + MINIMUM_SUBJECT_COUNT + "-" + MAXIMUM_SUBJECT_COUNT + "): ");
    subjectCount = Integer.parseInt(scanner.nextLine().strip());
    if (subjectCount < MINIMUM_SUBJECT_COUNT
            || subjectCount > MAXIMUM_SUBJECT_COUNT) {
        System.out.println(
                "Subject count must be between "
                + MINIMUM_SUBJECT_COUNT + " and " + MAXIMUM_SUBJECT_COUNT + ".");
        continue;
    }
    break;
}

The loop continues until the subject count is valid.

Step 6: Prepare Result Variables

Before processing marks, create the required accumulators and counters:

java
int totalMarks = 0;
int highestMark = MINIMUM_MARK;
int lowestMark = MAXIMUM_MARK;
int passedSubjectCount = 0;
int failedSubjectCount = 0;

totalMarks works as an accumulator. The highest and lowest marks will be compared with every valid mark.

Step 7: Read Subject Marks

The subject count is already known. Therefore, a for loop is suitable:

java
for (int subjectNumber = 1; subjectNumber <= subjectCount; subjectNumber++) {
    // Read one valid mark
}

Step 8: Validate Each Mark

The prompt for the same subject must repeat until a valid mark is provided:

java
int mark;
while (true) {
    System.out.print(
            "Enter mark for subject "
            + subjectNumber + " (" + MINIMUM_MARK + "-" + MAXIMUM_MARK + "): ");
    mark = Integer.parseInt(scanner.nextLine().strip());
    if (mark < MINIMUM_MARK || mark > MAXIMUM_MARK) {
        System.out.println(
                "Mark must be between "
                + MINIMUM_MARK + " and " + MAXIMUM_MARK + ".");
        continue;
    }
    break;
}

Step 9: Process Each Valid Mark

After receiving a valid mark, we add it to the total, update the highest and lowest marks, and count the subject as passed or failed:

java
totalMarks += mark;
if (mark > highestMark) {
    highestMark = mark;
}
if (mark < lowestMark) {
    lowestMark = mark;
}
if (mark >= PASSING_MARK) {
    passedSubjectCount++;
} else {
    failedSubjectCount++;
}

Step 10: Calculate the Average

java
double averageMark = totalMarks / (double) subjectCount;

The cast is needed because totalMarks / subjectCount would perform integer division, since both operands are int.

Step 11: Determine the Final Result

The student has passed all subjects if failedSubjectCount == 0:

java
boolean passedAllSubjects = failedSubjectCount == 0;

Final result:

java
String finalResult;
if (passedAllSubjects) {
    finalResult = "Passed";
} else {
    finalResult = "Failed";
}

Step 12: Determine the Grade

Subject failure takes priority over the average:

java
String grade;
if (!passedAllSubjects) {
    grade = "F";
} else if (averageMark >= 80) {
    grade = "A";
} else if (averageMark >= 70) {
    grade = "B";
} else if (averageMark >= 60) {
    grade = "C";
} else if (averageMark >= 50) {
    grade = "D";
} else {
    grade = "E";
}

Even if the student's average is very high, a failed subject makes the grade F.

Step 13: Create a Performance Message

The grade is a fixed exact category: A, B, C, D, E, or F. Therefore, a switch expression is suitable:

java
String performanceMessage = switch (grade) {
    case "A" -> "Excellent performance";
    case "B" -> "Very good performance";
    case "C" -> "Good performance";
    case "D" -> "Satisfactory performance";
    case "E" -> "Passed, but improvement is needed";
    case "F" -> "One or more subjects were failed";
    default -> "Result unavailable";
};

Complete Java Program

java
import java.util.Scanner;

public class Main {

    static final int CALCULATE_RESULT_OPTION = 1;
    static final int VIEW_RULES_OPTION = 2;
    static final int EXIT_OPTION = 3;

    static final int MINIMUM_SUBJECT_COUNT = 1;
    static final int MAXIMUM_SUBJECT_COUNT = 10;

    static final int MINIMUM_MARK = 0;
    static final int MAXIMUM_MARK = 100;
    static final int PASSING_MARK = 40;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        int menuOption;

        do {
            System.out.println();
            System.out.println("=== Grade Calculator ===");
            System.out.println();
            System.out.println("1. Calculate student result");
            System.out.println("2. View grade rules");
            System.out.println("3. Exit");
            System.out.println();
            System.out.print("Choose an option: ");
            menuOption = Integer.parseInt(scanner.nextLine().strip());

            switch (menuOption) {
                case CALCULATE_RESULT_OPTION -> {
                    System.out.println();
                    System.out.println("--- Student Information ---");

                    String studentName;

                    while (true) {
                        System.out.print("Enter student name: ");
                        studentName = scanner.nextLine().strip();
                        if (studentName.isBlank()) {
                            System.out.println("Student name is required.");
                            continue;
                        }
                        break;
                    }

                    int subjectCount;

                    while (true) {
                        System.out.print(
                                "Enter number of subjects ("
                                + MINIMUM_SUBJECT_COUNT + "-" + MAXIMUM_SUBJECT_COUNT + "): ");
                        subjectCount = Integer.parseInt(scanner.nextLine().strip());
                        if (subjectCount < MINIMUM_SUBJECT_COUNT
                                || subjectCount > MAXIMUM_SUBJECT_COUNT) {
                            System.out.println(
                                    "Subject count must be between "
                                    + MINIMUM_SUBJECT_COUNT + " and " + MAXIMUM_SUBJECT_COUNT + ".");
                            continue;
                        }
                        break;
                    }

                    int totalMarks = 0;
                    int highestMark = MINIMUM_MARK;
                    int lowestMark = MAXIMUM_MARK;
                    int passedSubjectCount = 0;
                    int failedSubjectCount = 0;

                    System.out.println();
                    System.out.println("--- Enter Subject Marks ---");

                    for (int subjectNumber = 1; subjectNumber <= subjectCount; subjectNumber++) {
                        int mark;

                        while (true) {
                            System.out.print(
                                    "Enter mark for subject "
                                    + subjectNumber + " (" + MINIMUM_MARK + "-" + MAXIMUM_MARK + "): ");
                            mark = Integer.parseInt(scanner.nextLine().strip());
                            if (mark < MINIMUM_MARK || mark > MAXIMUM_MARK) {
                                System.out.println(
                                        "Mark must be between "
                                        + MINIMUM_MARK + " and " + MAXIMUM_MARK + ".");
                                continue;
                            }
                            break;
                        }

                        totalMarks += mark;

                        if (mark > highestMark) {
                            highestMark = mark;
                        }

                        if (mark < lowestMark) {
                            lowestMark = mark;
                        }

                        if (mark >= PASSING_MARK) {
                            passedSubjectCount++;
                        } else {
                            failedSubjectCount++;
                        }
                    }

                    double averageMark = totalMarks / (double) subjectCount;

                    boolean passedAllSubjects = failedSubjectCount == 0;

                    String finalResult;

                    if (passedAllSubjects) {
                        finalResult = "Passed";
                    } else {
                        finalResult = "Failed";
                    }

                    String grade;

                    if (!passedAllSubjects) {
                        grade = "F";
                    } else if (averageMark >= 80) {
                        grade = "A";
                    } else if (averageMark >= 70) {
                        grade = "B";
                    } else if (averageMark >= 60) {
                        grade = "C";
                    } else if (averageMark >= 50) {
                        grade = "D";
                    } else {
                        grade = "E";
                    }

                    String performanceMessage = switch (grade) {
                        case "A" -> "Excellent performance";
                        case "B" -> "Very good performance";
                        case "C" -> "Good performance";
                        case "D" -> "Satisfactory performance";
                        case "E" -> "Passed, but improvement is needed";
                        case "F" -> "One or more subjects were failed";
                        default -> "Result unavailable";
                    };

                    int maximumPossibleMarks = subjectCount * MAXIMUM_MARK;

                    System.out.println();
                    System.out.println("=== Student Result ===");
                    System.out.println("Student: " + studentName);
                    System.out.println("Subjects: " + subjectCount);
                    System.out.println(
                            "Total marks: " + totalMarks + " out of " + maximumPossibleMarks);
                    System.out.println("Average mark: " + averageMark);
                    System.out.println("Highest mark: " + highestMark);
                    System.out.println("Lowest mark: " + lowestMark);
                    System.out.println("Passed subjects: " + passedSubjectCount);
                    System.out.println("Failed subjects: " + failedSubjectCount);
                    System.out.println("Grade: " + grade);
                    System.out.println("Result: " + finalResult);
                    System.out.println("Performance: " + performanceMessage);
                }

                case VIEW_RULES_OPTION -> {
                    String gradeRules = """
                            === Grade Rules ===

                            Passing mark per subject: 40

                            Average 80 to 100      → Grade A
                            Average 70 to under 80 → Grade B
                            Average 60 to under 70 → Grade C
                            Average 50 to under 60 → Grade D
                            Average 40 to under 50 → Grade E

                            If any subject mark is below 40:
                            Grade F and final result Failed
                            """;

                    System.out.println();
                    System.out.println(gradeRules);
                }

                case EXIT_OPTION -> System.out.println("Grade calculator closed.");
                default -> System.out.println("Invalid option. Choose 1, 2, or 3.");
            }
        } while (menuOption != EXIT_OPTION);

        scanner.close();
    }
}

Sample Run: Passed Student

With the inputs 1, Sakib, 3, 90, 85, 80 and 3, the reference solution prints:

text
=== Grade Calculator ===

1. Calculate student result
2. View grade rules
3. Exit

Choose an option: 1

--- Student Information ---
Enter student name: Sakib
Enter number of subjects (1-10): 3

--- Enter Subject Marks ---
Enter mark for subject 1 (0-100): 90
Enter mark for subject 2 (0-100): 85
Enter mark for subject 3 (0-100): 80

=== Student Result ===
Student: Sakib
Subjects: 3
Total marks: 255 out of 300
Average mark: 85.0
Highest mark: 90
Lowest mark: 80
Passed subjects: 3
Failed subjects: 0
Grade: A
Result: Passed
Performance: Excellent performance

=== Grade Calculator ===

1. Calculate student result
2. View grade rules
3. Exit

Choose an option: 3
Grade calculator closed.

Testing Checklist

The acceptance criteria in Build It Yourself First are your test plan. Run them against your version (or the reference solution), using at least the following values:

Menu

text
1
2
3
4

Subject Count

text
0
1
10
11

Marks

text
-1
0
39
40
79
80
100
101

Result Scenarios

  • All subjects passed
  • One subject failed
  • All subjects failed
  • One subject
  • Highest and lowest are the same

Current Input Limitation

In this project, we validate the range of numeric input, such as -10 or 150. However, if the user enters non-numeric text such as eighty, then Integer.parseInt(...) can produce a NumberFormatException.

Malformed input can be recovered from more cleanly after learning exception handling. For this project, we assume valid numeric text is provided at numeric prompts.

Common Mistakes

Integer Division

double averageMark = totalMarks / subjectCount; compiles, but for the marks 90, 85 and 79 it gives 84.0 instead of 84.66666666666667, because the division happens with int values (see Step 10).

Calculating the Grade Before Checking Failure

Wrong:

java
if (averageMark >= 80) {
    grade = "A";
}

This can ignore a failed subject: the marks 100, 100 and 39 would get an A-range average and no F. Correct:

java
if (!passedAllSubjects) {
    grade = "F";
} else if (averageMark >= 80) {
    grade = "A";
}

Processing an Invalid Mark

Wrong order:

java
totalMarks += mark;
if (mark < MINIMUM_MARK || mark > MAXIMUM_MARK) {
    continue;
}

The invalid mark has already been added to the total. Validate first, process later.

Project Improvement Exercises

Solutions: lesson 1.25.

Exercise 1: Percentage

Calculate:

text
percentage =
    total marks
    ÷ maximum possible marks
    × 100

Exercise 2: Distinction Count

Count subjects where the mark is 80 or above.

Exercise 3: Highest Subject

Track the subject number where the highest mark was received. Example:

text
Highest mark: 95
Highest subject: 3

Exercise 4: Lowest Subject

Track the subject number with the lowest mark.

Exercise 5: Grade Point

Create a grade point based on the grade:

GradePoint
A5.0
B4.0
C3.0
D2.0
E1.0
F0.0

Use a switch expression.

Exercise 6: Calculate Another Student

After completing one result, ask Calculate another student? yes/no. If the answer is yes, calculate another student's result.

Exercise 7: Text Menu

Instead of numeric options, use:

text
calculate
rules
exit

Normalize the input with .strip().toLowerCase().

Knowledge Check

Question 1

Why is do-while suitable for the menu?

Question 2

Why is for suitable for subject marks?

Question 3

Why is while suitable for mark validation?

Question 4

What does continue do when a mark is invalid?

Question 5

What does break do when a mark is valid?

Question 6

Why is a cast used in the average calculation?

Question 7

What kind of variable is totalMarks?

Question 8

How is the highest mark updated?

Question 9

How is the lowest mark updated?

Question 10

Why is the grade F if one subject is failed?

Question 11

Why is switch suitable for the performance message?

Question 12

When does the menu loop end?

Knowledge Check Answers

Answer 1

The menu must be displayed at least once and should repeat until exit is selected.

Answer 2

The subject count is known before the marks are read.

Answer 3

We do not know in advance how many attempts will be needed to obtain a valid mark.

Answer 4

It ends the current validation iteration and returns to the prompt.

Answer 5

It terminates the nearest validation loop.

Answer 6

To avoid integer division and produce a decimal average.

Answer 7

An accumulator.

Answer 8

The highest mark is updated when the current mark is greater than the existing highest mark.

java
if (mark > highestMark) {
    highestMark = mark;
}

Answer 9

The lowest mark is updated when the current mark is lower than the existing lowest mark.

java
if (mark < lowestMark) {
    lowestMark = mark;
}

Answer 10

According to the project rule, every subject must be passed individually.

Answer 11

The grade is a fixed exact category: A, B, C, D, E, or F.

Answer 12

When the user selects option 3.

Lesson Summary

  • The project combined the module's building blocks: constants, variables, String values, operators, casting, Scanner input, if-else, switch, loops, break, continue, and a text block.
  • A do-while loop shows the menu at least once and repeats it until the user chooses exit.
  • while (true) loops with continue and break keep asking until the name, subject count, or mark is valid.
  • A for loop reads the marks because the subject count is known before the loop starts.
  • An accumulator collects the total, comparisons track the highest and lowest marks, and counters track passed and failed subjects.
  • A cast to double avoids integer division when calculating the average.
  • The failure check comes before the average-based grade, so one failed subject always gives grade F.

Mõtle enne

Tulekul

Kontrollküsimused, mille puhul valid vastuse enne, kui õppetund selle näitab.