Programming and Java Fundamentals
Project: Build a Console-Based Grade Calculator
আপনি একটি 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:
- Calculate a student result
- View grade rules
- Exit the program
Concepts Used
In this project, we will use:
- Variables
- Constants
- Primitive data types
String- Operators
- Type conversion
Scannerif-elseswitchforwhiledo-whilebreakcontinue- 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, andcontinuepractically - 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 Mark | Grade |
|---|---|
80–100 | A |
70–79.99 | B |
60–69.99 | C |
50–59.99 | D |
40–49.99 | E |
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:
| Grade | Point |
|---|---|
A | 5.0 |
B | 4.0 |
C | 3.0 |
D | 2.0 |
E | 1.0 |
F | 0.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
Scannerto 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.