The result-day grading program
Results are out. Arjun Sir asks Riya to write a small program that converts marks into a grade: 90 and above is A+, 75 and above is A, 60 and above is B, 40 and above is C, and below 40 is Fail. Her first version gives a student with 95 marks the grade C.
Sir, my first check was if (marks >= 40), then else if (marks >= 60) and so on. A student with 95 got a C!
An else-if ladder stops at the first true condition. 95 is ≥ 40, so the very first check matched, and Java never looked further. Order the checks from the strictest to the loosest.
So for 72, Java checks 90, then 75, then 60, finds a match, and skips everything else?
Exactly. Behind the screen, the JVM literally jumps over the code it skips. Let's see those jumps.
What is an if statement?
The if statement is a conditional control-flow statement that executes a statement or block only when a boolean expression evaluates to true. An optional else clause runs when the condition is false. Several conditions can be chained with else if, forming an if-else-if ladder in which only the first matching branch executes.
if asks a yes/no question. Yes → run this block. No → skip it (or run the else block). With a ladder, Java asks the questions in order and stops at the first “yes”.
Words you'll meet in this lesson
marks >= 40.{ } that belong to a branch.if that handles a bad case and returns immediately.The four forms
| Form | Syntax | Use when |
|---|---|---|
| if | if (cond) { … } | Something should happen only sometimes |
| if-else | if (cond) { … } else { … } | Exactly one of two things must happen |
| else-if ladder | if (a) { … } else if (b) { … } else { … } | Choosing one of several ranges or cases |
| nested if | if (a) { if (b) { … } } | A second check only makes sense after the first passes |
Exam tip: the condition must be a boolean. Unlike C, if (1) or if (x = 5) won't compile. Braces are optional for a single statement, but without them only the first statement belongs to the if, which is a classic trap question.
Each form, with its typical use
Simple if
if (balance < 100) { warnLowBalance(); }
Do something extra only in some cases.
if-else
if (pinCorrect) { approve(); } else { decline(); }
Two outcomes; exactly one happens.
else-if ladder
Grades, tax slabs, delivery charges by distance. Order matters: the first true condition wins.
RangesNested if
if (age >= 18) { if (hasId) { … } }
Often clearer as age >= 18 && hasId or a guard clause.
Writing clean conditions
| Instead of | Write | Why |
|---|---|---|
if (isPaid == true) | if (isPaid) | It's already a boolean |
if (x) { return true; } else { return false; } | return x; | Shorter, same meaning |
| Deep nesting of ifs | Guard clauses: if (!valid) return; | Keeps the main path flat and readable |
if (a) x = 1; else x = 2; | x = a ? 1 : 2; | Ternary for simple value choices |
Building the grading ladder
Write the strictest condition first
javac compiles the opposite test: “if marks < 90, jump past this block”. The bytecode isif (marks >= 90) { grade = "A+"; }if_icmplt(if int compare less-than).Add else-if branches, from strict to loose
At the end of each block, javac adds a} else if (marks >= 75) { grade = "A"; } else if (marks >= 60) { grade = "B"; }gotothat jumps to the code after the whole ladder. That's how the other branches get skipped.Finish with else
The final} else { grade = "Fail"; }elseguaranteesgradeis always assigned. Without it, javac would complain “variable grade might not have been initialized” when you print it.Always use braces
Indentation means nothing to javac. Without braces, only the first statement is inside the if; the second runs every time.if (balance < 100) System.out.println("Low balance"); System.out.println("Please recharge"); // NOT part of the if!Test the boundaries
Try 90, 89, 75, 74, 60, 59, 40, 39, 0 and 100: the values right at each edge.
Most if-else bugs are off-by-one mistakes at boundaries:>where>=was meant. Testing the exact edge values catches them.
marks = 72 through the ladder: both views
Left: the code, with the line being checked. Right: the bytecode and the jumps the JVM takes.
- The variable
marksholds 72. - First check: is 72 ≥ 90? No, so the A+ block is skipped.
- Second check: is 72 ≥ 75? No, so the A block is skipped.
- Third check: is 72 ≥ 60? Yes! Java enters this block.
gradebecomes "B". The remaining checks are never evaluated.- Execution continues after the ladder and prints the result.
- The real bytecode (from
javap -c): there are no “if blocks”, only compares and jumps. if_icmplt 15: if marks is less than 90, jump to offset 15. javac tests the opposite condition.- 72 < 75 too, so the JVM jumps again, to offset 27.
- 72 is not < 60, so there's no jump: execution falls through into the B block.
- The block ends with
goto 54, which skips the C and Fail branches entirely. - From offset 54 the program continues with
println.
Decisions in real systems
Almost every business rule is an if-else somewhere. Here's where they show up.
Watch it with an example: delivery charge slabs
A food app charges delivery by order value. Follow two orders down the if / else-if ladder: Java checks conditions from the top and stops at the first true one.
- Order 1: Rs 349 arrives. Java starts at the top of the ladder.
- First check:
349 < 199is false, so its block is skipped and Java moves to the nextelse if. - Second check:
349 < 499is true. Its block runs: fee = 29. The rest of the ladder (theelse) is skipped completely. - Bill: 349 + 29 = 378. Exactly one branch ran.
- Order 2: Rs 650. Both conditions are false…
- …so the
elseruns: free delivery. Order matters: if the checks were written biggest-first, the slabs would be wrong. Real apps use the same ladder for tax slabs and discounts.
1. Payment approval
A payment passes a chain of checks: valid PIN? enough balance? under the daily limit? not flagged as fraud? Each failed check declines the payment with a specific reason.
2. Slabs: tax, delivery charges, discounts
Income-tax slabs, delivery fees by distance and discount tiers are else-if ladders. The order of checks must match the business rules exactly. (Slabs shown here are only an illustration.)
3. Input validation with guard clauses
API handlers start with a list of guard clauses: if (email == null) return badRequest(…). Bad requests are rejected early and the main logic stays readable.
4. Feature flags
Companies release new features gradually: if (flags.isEnabled("newCheckout", user)) { … } else { … }. The same code serves both old and new experiences.
5. Time-based rules
“Canteen offer only between 3 and 5 pm”, “late fee after the 10th”, “night charges after 11 pm” are conditions on dates and times, written as ifs.
Examples are simplified to show where decisions fit. Real rules are more detailed.
The grading program
public class Main {
public static void main(String[] args) {
int marks = 72;
String grade;
if (marks >= 90) {
grade = "A+";
} else if (marks >= 75) {
grade = "A";
} else if (marks >= 60) {
grade = "B";
} else if (marks >= 40) {
grade = "C";
} else {
grade = "Fail";
}
System.out.println("Marks " + marks + ": Grade " + grade);
}
}String grade;Declared without a value. Every branch assigns it, so javac is satisfied.if (marks >= 90)The strictest check comes first.else if (…)Only checked if all earlier conditions were false.elseCatches everything else, so there's always a grade.
Follow 72 through the ladder
Notice which lines the tracer visits and which it skips completely.
Worked examples: real problems, solved and traced in memory
Decisions are the heart of business rules. Each program below turns a real rule into if / else if / else. In the trace, watch which lines are skipped: the JVM evaluates a condition and jumps over the branches that don't apply.
Personal loan pre-approval
Problem statement
A bank pre-approves a personal loan if the applicant is 21–58 years old, earns at least Rs 25,000 a month and has a credit score of 700 or more. Otherwise it explains the first reason for rejection.
age 35, income 22000, credit score 760
Rejected: income below Rs 25,000
Approach
- Check each rule in order with
if / else if. - The first failing rule gives the reason.
- If none fail, approve.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Marks to grade
Problem statement
A university converts percentage marks into grades: 90+ O, 75–89 A, 60–74 B, 40–59 C, below 40 F. Grade three students.
marks 82, 39, 90
82 -> A 39 -> F 90 -> O
Approach
- Test from the highest band down.
- Each
else ifonly runs if all earlier tests failed, so lower limits are enough. - Use a helper method so the same rules grade every student.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Electricity slab billing
Problem statement
Electricity is billed in slabs: the first 100 units at Rs 3, the next 200 units (101–300) at Rs 5, and anything above 300 at Rs 8. Compute the bill for 380 units.
380 units
380 units: Rs 1940
Approach
- If units ≤ 100: units × 3.
- Else if ≤ 300: 100 × 3 + (units − 100) × 5.
- Else: full first two slabs + (units − 300) × 8.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Check yourself
Quick revision
Lesson 3.1 in one screen
- Forms: if, if-else, else-if ladder, nested if.
- Condition must be boolean;
=vs==is caught by javac for ints. - Ladder: first true condition wins; order from strictest to loosest; end with
else. - Always use braces; without them only one statement belongs to the if.
elsepairs with the nearest if. - Behind the screen: compare + conditional jump (
if_icmplt…) +gotopast the other branches. - Prefer guard clauses over deep nesting; test boundary values.
Interview and viva questions
What's the difference between if-else-if and multiple separate ifs?
In an else-if ladder, at most one branch runs: checking stops at the first match. With separate if statements, every condition is checked and several blocks can run.
When should you use switch instead of if-else?
When you compare one value against many fixed constants (like menu options or days), switch is clearer and can be faster. For ranges (marks ≥ 60) or complex conditions, if-else is the right tool. Lesson 3.2 covers switch.
What is a guard clause?
An if at the start of a method that handles an invalid or special case and returns immediately, for example if (amount <= 0) return;. It avoids nesting the main logic inside several ifs.
Can an if statement have a semicolon after the condition?
It compiles, but if (x > 5); means “if x > 5, do nothing”, and the following block runs every time. It's a common bug, and IDEs warn about it.
Is the ternary operator a replacement for if-else?
Only for choosing between two values, e.g. String r = marks >= 40 ? "Pass" : "Fail";. For running different statements, or more than two cases, if-else is clearer.
Practice problems
Solve each problem yourself in the live editor first. Then open the solution to compare. The last two are real business rules of the kind you'll write at work.
Even or odd
Given a whole number n, print whether it is even or odd.
n = 17
17 is odd
Show solution and explanation
public class Main {
public static void main(String[] args) {
int n = 17;
if (n % 2 == 0) {
System.out.println(n + " is even");
} else {
System.out.println(n + " is odd");
}
}
}How it works: a number is even when dividing by 2 leaves no remainder, so we test n % 2 == 0. Exactly one of two outcomes is possible, so if-else is the right form. (For negative odd numbers, n % 2 is −1, which is still “not 0”, so the code works for them too.)
Largest of three numbers
Given three numbers a, b and c, print the largest.
a = 12, b = 45, c = 29
Largest: 45
Show solution and explanation
public class Main {
public static void main(String[] args) {
int a = 12, b = 45, c = 29;
int largest;
if (a >= b && a >= c) {
largest = a;
} else if (b >= c) {
largest = b;
} else {
largest = c;
}
System.out.println("Largest: " + largest);
}
}How it works: if a beats both others, it's the answer. Otherwise the answer is either b or c, so one more comparison decides. Using >= means ties are handled correctly. (Later you can simply write Math.max(a, Math.max(b, c)).)
Positive, negative or zero
Print whether n is positive, negative or zero.
n = -8
-8 is negative
Show solution and explanation
public class Main {
public static void main(String[] args) {
int n = -8;
if (n > 0) {
System.out.println(n + " is positive");
} else if (n < 0) {
System.out.println(n + " is negative");
} else {
System.out.println("The number is zero");
}
}
}How it works: three possible outcomes need a ladder with two conditions and an else. The else catches the only remaining case, zero, so we don't need to test n == 0.
Vowel, consonant, digit or symbol
Given a character ch, print whether it is a vowel, a consonant, a digit or something else. Treat upper and lower case the same.
ch = 'E'
E is a vowel
Show solution and explanation
public class Main {
public static void main(String[] args) {
char ch = 'E';
char lower = Character.toLowerCase(ch);
if (lower == 'a' || lower == 'e' || lower == 'i' || lower == 'o' || lower == 'u') {
System.out.println(ch + " is a vowel");
} else if (lower >= 'a' && lower <= 'z') {
System.out.println(ch + " is a consonant");
} else if (ch >= '0' && ch <= '9') {
System.out.println(ch + " is a digit");
} else {
System.out.println(ch + " is a symbol or space");
}
}
}How it works:
- Convert to lowercase once, so we only check five vowels instead of ten.
- Check vowels before letters: every vowel is also a letter, so the stricter test must come first.
- chars are numbers (Lesson 2.2), so
lower >= 'a' && lower <= 'z'is a range check on their codes.
Electricity bill with slabs
A power company charges ₹3 per unit for the first 100 units, ₹5 per unit for the next 100, and ₹8 per unit above 200. Calculate the bill for units.
units = 250
Bill for 250 units: Rs 1200
Show solution and explanation
public class Main {
public static void main(String[] args) {
int units = 250;
int bill;
if (units <= 100) {
bill = units * 3;
} else if (units <= 200) {
bill = 100 * 3 + (units - 100) * 5;
} else {
bill = 100 * 3 + 100 * 5 + (units - 200) * 8;
}
System.out.println("Bill for " + units + " units: Rs " + bill);
}
}How it works: slab pricing charges each part of the usage at its own rate, not the whole usage at the highest rate. For 250 units: 100 × 3 = 300, plus 100 × 5 = 500, plus 50 × 8 = 400, total 1200. Test the edges too: 100, 101, 200 and 201 units.
Classify a triangle
Given three side lengths, print “Not a triangle” if they can't form one (any two sides must add up to more than the third). Otherwise print Equilateral, Isosceles or Scalene.
a = 5, b = 5, c = 8
Isosceles triangle
Show solution and explanation
public class Main {
public static void main(String[] args) {
int a = 5, b = 5, c = 8;
if (a + b <= c || a + c <= b || b + c <= a) {
System.out.println("Not a triangle");
} else if (a == b && b == c) {
System.out.println("Equilateral triangle");
} else if (a == b || b == c || a == c) {
System.out.println("Isosceles triangle");
} else {
System.out.println("Scalene triangle");
}
}
}How it works: the invalid case is checked first, as a guard. Then the strictest type (all three equal) comes before “any two equal”, because an equilateral triangle would also pass the isosceles test.
Food delivery fee calculator
A food delivery app charges a delivery fee by these rules, in this order:
- Members always get free delivery. Orders of ₹499 or more also get free delivery.
- Otherwise: up to 3 km costs ₹20, up to 7 km costs ₹35, and anything further costs ₹50.
- A late-night surcharge of ₹15 is added (on paid deliveries) between 11 pm and 5 am.
orderValue = 349, distanceKm = 6.5, member = false, hour = 23
Delivery fee: Rs 50
Show solution and explanation
public class Main {
public static void main(String[] args) {
int orderValue = 349;
double distanceKm = 6.5;
boolean member = false;
int hour = 23; // 24-hour clock
int fee;
if (member || orderValue >= 499) {
fee = 0;
} else {
if (distanceKm <= 3) {
fee = 20;
} else if (distanceKm <= 7) {
fee = 35;
} else {
fee = 50;
}
boolean lateNight = hour >= 23 || hour < 5;
if (lateNight) {
fee = fee + 15;
}
}
System.out.println("Delivery fee: Rs " + fee);
}
}How it works:
- The “free” rules come first, joined with
||: either one is enough. - Only paid deliveries go through the distance ladder: 6.5 km falls in the “up to 7 km” slab, ₹35.
- Late night wraps around midnight, so it needs
||, not&&: hour 23 or hours 0–4. Writinghour >= 23 && hour < 5would never be true, a very common real bug. - Naming the condition
lateNightmakes the rule readable. ₹35 + ₹15 = ₹50.
Loan pre-eligibility check with reasons
A bank pre-checks personal-loan applicants. Reject with a reason code if any rule fails, checking in this order: age must be 21–60 (AGE); monthly income at least ₹25,000 (INCOME); credit score at least 700 (CREDIT_SCORE); existing EMIs must be at most 40% of income (EMI_TOO_HIGH). Otherwise print “Eligible”. Check two applicants. (The rules are illustrative, not any real bank's.)
Applicant 1: age 27, income 42000, score 712, existing EMI 9000 Applicant 2: age 34, income 30000, score 745, existing EMI 15000
Applicant 1: Eligible Applicant 2: Rejected (EMI_TOO_HIGH)
Show solution and explanation
public class Main {
static String check(int age, int income, int score, int emi) {
if (age < 21 || age > 60) {
return "Rejected (AGE)";
}
if (income < 25_000) {
return "Rejected (INCOME)";
}
if (score < 700) {
return "Rejected (CREDIT_SCORE)";
}
if (emi > income * 0.40) {
return "Rejected (EMI_TOO_HIGH)";
}
return "Eligible";
}
public static void main(String[] args) {
System.out.println("Applicant 1: " + check(27, 42_000, 712, 9_000));
System.out.println("Applicant 2: " + check(34, 30_000, 745, 15_000));
}
}How it works:
- Each rule is a guard clause: if it fails, the method returns immediately with a reason. No deep nesting.
- The order of checks matches the business order, so the reported reason is the first rule that failed.
- Applicant 2: 40% of ₹30,000 is ₹12,000, and their EMIs are ₹15,000, so they fail the last rule.
- Returning a reason code (not just true/false) is how real systems explain decisions to customers and auditors. Methods are covered fully in Module 5.
Real-world scenario questions (asked in company interviews)
Business rules live in if statements, so their bugs cost real money. Decide your answer first, then open the model answer.
Big orders get the small discount
The rule: 5% off above ₹500, 10% off above ₹1000. Customers spending ₹2,000 complain they only got 5%. The code is if (total > 500) { d = 5; } else if (total > 1000) { d = 10; }. Explain and fix.
The interviewer is checking: do you understand that an else-if ladder stops at the first match?
Show a strong answer
₹2,000 is greater than 500, so the first branch matches and the 1000 check is never reached. The 10% branch is effectively dead code.
- Reorder from the highest slab down:
if (total > 1000) d = 10; else if (total > 500) d = 5; else d = 0; - Clarify the exact boundaries with the business (is ₹1000 itself 5% or 10%?) and write them down.
- Add tests at 499, 500, 501, 1000, 1001 and a large value. Slab rules often move to configuration later.
Avoid: making two separate ifs, where the second overwrites the first. It works by accident and confuses readers.
The check that always passed
A login check was written without braces: if (!passwordValid) logFailure(); return deny(); on two lines, with careful indentation. Later someone added a line, and now an important security check after it is never reached. Why do teams insist on braces even for one line?
The interviewer is checking: do you know that indentation means nothing to the compiler, and how style rules prevent real bugs?
Show a strong answer
Without braces, only the first statement belongs to the if. Statements that look indented under it actually run every time. A famous real-world security bug was caused by exactly this kind of mistake, where a duplicated line made later checks unreachable.
- Always use braces, even for single statements. Most style guides and Checkstyle rules require it.
- Use the IDE formatter: it re-indents code to match the real structure and exposes the problem.
- Unit-test both the success and the failure path of every security check.
Avoid saying: “Braces are just style.”
Arrow-shaped code nobody wants to touch
A loan-eligibility method has ifs nested six levels deep (age, income, credit score, existing loans, KYC, city), with else blocks scattered at the bottom. A new rule must be added. How would you restructure it?
The interviewer is checking: do you know guard clauses and how to keep decision logic readable?
Show a strong answer
- Turn each check into a guard clause that returns immediately with a clear reason:
if (age < 21) return reject("AGE");. The happy path ends up at the bottom, unindented. - Extract each rule into a well-named method, such as
hasAcceptableCreditScore(applicant). - Write tests for the current behaviour before refactoring, so nothing changes by accident; then add the new rule as one more guard.
- If rules change often, consider a rules table or configuration instead of code.
Avoid: adding a seventh level of nesting “because that's how the code is”.
Students with exactly 40 marks were failed
The university rule says “40 or more is a pass”. After results were published, students with exactly 40 complained they were marked Fail. The code says if (marks > 40). How did tests miss it, and how do you prevent this class of bug?
The interviewer is checking: do you know boundary-value testing and careful translation of rules into conditions?
Show a strong answer
The rule says “40 or more” (>=), but the code used >. Tests probably used typical values like 25 and 75, never the exact boundary.
- Fix:
if (marks >= PASS_MARK), with the pass mark as a named constant. - Add boundary tests: 39, 40, 41, and the extremes 0 and 100.
- Re-run the result calculation for affected students and communicate the correction.
Avoid: testing only “typical” values. Bugs live at the edges.