Making decisions
int score = 85;
if (score >= 90) {
System.out.println("Excellent");
} else if (score >= 60) {
System.out.println("Pass");
} else {
System.out.println("Fail");
}
Prints Pass. The first test, 85 >= 90, is false. The second, 85 >= 60, is true, so that branch runs and the whole chain is done — the else never gets looked at.
That last part matters. An if/else-if chain is not a list of independent questions. It's a sequence that stops at the first yes. Which is why order matters: if you'd checked >= 60 first, a score of 95 would print Pass, because it would match before the stricter test ever ran. Always put the narrowest condition first.
Compared to Python there are only three differences: the condition goes inside round brackets, the body goes inside curly braces, and elif is spelled else if.
Don't skip the braces
Java lets you leave the braces off when the body is a single statement:
if (score >= 60)
System.out.println("Pass");
Don't. Here's what happens the day you add a second line:
if (score >= 60)
System.out.println("Pass");
System.out.println("Congratulations"); // runs no matter what
Without braces, the if owns exactly one statement — the first one. The second println is just the next statement in the method. It runs whether the score is 95 or 12.
Your eyes read the indentation and conclude both lines belong to the if. The compiler doesn't read indentation at all. This exact mistake shipped in Apple's TLS code in 2014 and broke certificate validation for millions of devices; it's known as "goto fail." Real consequences, from a missing pair of braces.
Habit to build now: every if, every else, every loop gets braces. No exceptions, not even for one line.
Logical operators
&& // and — both sides must be true
|| // or — either side is enough
! // not — flips it
if (age >= 18 && hasTicket) { ... }
if (age < 6 || age >= 65) { ... }
Java uses symbols where Python uses the words and, or, not. If you're coming from Python, you will type and at least once and get a syntax error. That's normal.
&& and || have a property called short-circuit evaluation: in a && b, if a is already false, b is never evaluated at all. There's no point — the answer can't change.
That's not a micro-optimization, it's a safety tool:
if (name != null && name.length() > 0) { ... }
If name is null, the first test fails and Java stops. name.length() never runs. Flip the order and you get a NullPointerException in exactly the case you were trying to guard against. Short-circuiting is what makes null checks work.
Comparing strings: == is the wrong tool
This is the most-asked question in Java interviews, and it isn't trivia — it's a real bug that ships.
String a = "hello";
String b = new String("hello");
System.out.println(a == b); // false
System.out.println(a.equals(b)); // true
a == b prints false even though both hold the word "hello."
Here's the model to hold in your head. A String variable doesn't contain the text. It contains a pointer to where the text lives. == compares the two pointers: "are these the same object?" equals() walks the characters and compares them: "do these say the same thing?"
a and b above are two separate objects that happen to contain identical characters. Same text, different addresses. == says false, and it's telling the truth — it just isn't answering the question you meant to ask.
Rule: always compare strings with .equals().
There's a safer spelling worth adopting:
if ("admin".equals(role)) { ... }
Put the literal first. If role is null, "admin".equals(null) calmly returns false. Written the other way round, role.equals("admin") throws a NullPointerException. This trick is called a Yoda condition (because it reads backwards), and it eliminates a whole category of crash for free.
switch: many branches, one value
When you're comparing one variable against a list of fixed values, a long else-if chain gets noisy. switch is clearer:
int day = 3;
switch (day) {
case 1:
case 2:
case 3:
case 4:
case 5:
System.out.println("Weekday");
break;
case 6:
case 7:
System.out.println("Weekend");
break;
default:
System.out.println("Not a valid day");
}
Prints Weekday.
Never forget break. Without it, execution doesn't stop at the end of a case — it keeps running straight into the next one. This is called fall-through, and it is on by default.
The code above uses fall-through deliberately: cases 1 through 4 have no body at all, so they fall into case 5's body. That's the idiomatic way to make several values share one action. But deliberate fall-through and forgotten-break fall-through look identical on the page, which is why the accidental kind is such a classic bug.
Java 14 added a form with no break at all:
String type = switch (day) {
case 1, 2, 3, 4, 5 -> "Weekday";
case 6, 7 -> "Weekend";
default -> "Invalid";
};
System.out.println(type);
Prints Weekday. The arrow form never falls through, and it produces a value you can assign.
Check your version with java -version before reaching for it. On Java 11 or older this is a syntax error, and plenty of environments — including some classroom setups and this site's code runner — are still on 11. Prefer the arrow form where you can, and stay fluent in the old form, because it's in every codebase written before 2020.
The ternary operator
int score = 85;
String result = (score >= 60) ? "Pass" : "Fail";
System.out.println(result);
Prints Pass. Read it as: if the condition holds, take the value after ?; otherwise take the value after :.
It's good for a short either/or. Don't nest them — nested ternaries are unreadable, and a plain if/else costs you nothing.
Ten-second check
Can "abc" == "abc" be true in Java?
Yes, sometimes — Java keeps a pool of string literals and reuses the same object for identical ones written in source code, so both sides may genuinely be the same object. But never rely on it. The moment one side is built at runtime — read from Scanner, joined with +, loaded from a file — you get a different object and == turns false. Use .equals() every time and the question stops mattering.