Programming and Java Fundamentals

Project: Build a Console-Based Grade Calculator

ReadingPreview

আপনি একটি 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.