Programming and Java Fundamentals

Project: Build a Console-Based Grade Calculator

ReadingPreview

You are viewing a free preview lesson.

Project Overview

So far, we have learned Java's fundamental building blocks separately.

In this project, we will combine them to build a complete interactive console application.

Our Grade Calculator will take the following input from the user:

  • Student name
  • Subject count
  • Mark for each subject

Then it will calculate:

  • Total marks
  • Average mark
  • Highest mark
  • Lowest mark
  • Passed subject count
  • Failed subject count
  • Final grade
  • Final result
  • Performance message

The application will be menu-driven.

The user will be able to:

  1. Calculate a student result
  2. View grade rules
  3. Exit the program

Concepts Used

In this project, we will use:

  • Variables
  • Constants
  • Primitive data types
  • String
  • Operators
  • Type conversion
  • Scanner
  • if-else
  • switch
  • for
  • while
  • do-while
  • break
  • continue
  • Input normalization
  • Range validation
  • Text blocks

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

Project Requirements

Main menu:

=== Grade Calculator ===

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

Student Information

When the calculation option is selected, the program will ask for:

Student name
Number of subjects
Mark for each subject

Student Name Rule

The student name cannot be blank.

Invalid:

   

Valid:

Sakib

Subject Count Rule

The subject count must be:

1 to 10

If the value is outside this range, the program will ask for the subject count again.

Mark Rule

Each mark must be:

0 to 100

If an invalid mark is entered, the mark for the same subject will be requested again.

Passing Rule

The passing mark for each subject is:

40

If the mark in even one subject is below 40, the final result is:

Failed

and the grade is:

F

Grade Rules

If the student passes all subjects, the grade is based on the average:

Average MarkGrade
80–100A
70–79.99B
60–69.99C
50–59.99D
40–49.99E

If any subject is failed:

Grade: F
Result: Failed

Program Flow

Start
  ↓
Display Menu
  ↓
Read Option
  ↓
1 → Calculate Result
  │
  ├─ Read Student Name
  ├─ Read Subject Count
  ├─ Read Marks
  ├─ Calculate Statistics
  ├─ Determine Grade
  └─ Display Result
  ↓
2 → Display Grade Rules
  ↓
3 → Exit
  ↓
Otherwise → Invalid Option
  ↓
Return to Menu

Step 1: Define Constants

We will store the program's fixed rules as constants.

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;

This reduces unexplained magic numbers in the code.

Step 2: Create the Scanner

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:

Integer.parseInt(...)

Step 3: Create the Menu Loop

The menu must be displayed at least once.

Therefore, do-while is suitable:

int menuOption;

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

Step 4: Validate Student Name

The student name cannot be blank.

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;
}

Here:

  • Invalid name → continue
  • Valid name → break

Step 5: Validate Subject Count

int subjectCount;

while (true) {
    System.out.print(
            "Enter number of subjects (1-10): "
    );

    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.

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:

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.

int mark;

while (true) {
    System.out.print(
            "Enter mark for subject "
            + subjectNumber
            + " (0-100): "
    );

    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:

totalMarks += mark;

Highest mark:

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

Lowest mark:

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

Pass/fail count:

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

Step 10: Calculate the Average

double averageMark =
        totalMarks
        / (double) subjectCount;

The cast is needed because:

totalMarks / subjectCount

would perform integer division because both operands are int.

Step 11: Determine the Final Result

The student has passed all subjects if:

failedSubjectCount == 0
boolean passedAllSubjects =
        failedSubjectCount == 0;

Final result:

String finalResult;

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

Step 12: Determine the Grade

Subject failure takes priority over the average.

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
F

Therefore, a switch expression is suitable:

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

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-100 → Grade A
                            Average 70-79  → Grade B
                            Average 60-69  → Grade C
                            Average 50-59  → Grade D
                            Average 40-49  → 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();
    }
}

Program Walkthrough

Why do-while for the Menu?

do {
    // Menu
} while (menuOption != EXIT_OPTION);

The menu must be displayed at least once.

Therefore, do-while is a natural choice.

Why while for Validation?

We do not know in advance how many times the subject count or a mark may be invalid.

while (true) {
    // Read value

    if (invalid) {
        continue;
    }

    break;
}

Here:

  • Invalid → try again
  • Valid → end the validation loop

Why for for Subject Marks?

The subject count is already known:

subjectCount

Therefore:

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

is a natural choice.

Why Check Failure Before Grade?

Marks:

100
100
39

The student's average may be high.

However, the project rule says:

Every subject must be passed individually.

Therefore:

if (!passedAllSubjects) {
    grade = "F";
}

is checked before the average-based grade.

Sample Run: Passed Student

=== 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

Sample Run: Failed Subject

Input:

90
35
85

Total:

210

Average:

70.0

The average falls within the Grade B range.

However, one subject was failed.

Final:

Grade: F
Result: Failed
Performance: One or more subjects were failed

Important Boundary Cases

Mark Exactly 40

40

Passed.

Because:

mark >= PASSING_MARK

Average Exactly 80

Grade:

A

Average Exactly 70

Grade:

B

One Subject

Subject count: 1
Mark: 75

Result:

Total: 75
Average: 75.0
Highest: 75
Lowest: 75
Grade: B

All Marks Zero

0
0
0

Result:

Total: 0
Average: 0.0
Grade: F
Result: Failed

Testing Checklist

Test the program with at least the following values:

Menu

1
2
3
4

Subject Count

0
1
10
11

Marks

-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.

For example:

-10
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

Wrong:

double averageMark =
        totalMarks / subjectCount;

Correct:

double averageMark =
        totalMarks
        / (double) subjectCount;

Calculating the Grade Before Checking Failure

Wrong:

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

This can ignore a failed subject.

Correct:

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

Processing an Invalid Mark

Wrong order:

totalMarks += mark;

if (
        mark < MINIMUM_MARK
        || mark > MAXIMUM_MARK
) {
    continue;
}

The invalid mark has already been added to the total.

Validate first, process later.

Wrong Loop Selection

The subject count is known in advance.

Therefore, for reading marks:

for

is natural.

However, we do not know how many attempts will be required to obtain one valid mark.

Therefore, for validation:

while

is natural.

Project Improvement Exercises

Exercise 1: Percentage

Calculate:

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:

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:

calculate
rules
exit

Normalize the input:

.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.

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

Answer 9

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

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
F

Answer 12

When the user selects option:

3

Project Summary

In this project, we:

  • Built a menu-driven console application
  • Used Scanner to collect user input
  • Validated blank text and numeric ranges
  • Repeated the menu using do-while
  • Ensured valid input using while
  • Read multiple subject marks using for
  • Retried invalid values using continue
  • Ended validation loops using break
  • Calculated a total using an accumulator
  • Tracked the highest and lowest marks
  • Counted passed and failed subjects
  • Calculated a decimal average using type conversion
  • Determined the final grade using if-else
  • Created a performance message using a switch expression
  • Tested boundary cases

We also saw an important point:

Knowing individual syntax and building a complete program are not the same thing.

The main purpose of this project is to combine variables, conditions, loops, and input handling into one coherent program flow.