Control flow, methods and the modern main
Conditionals, the enhanced switch, loops and method design, plus compact source files for scripts and small tools.
Conditionals and the enhanced switch
int score = 87;
String grade = score >= 90 ? "A" : score >= 80 ? "B" : "C";
enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }
String kind = switch (day) { // switch expression: it returns a value
case SAT, SUN -> "weekend";
case MON, TUE, WED, THU, FRI -> "weekday";
};
String describe(Object o) { // pattern matching with a guard
return switch (o) {
case null -> "nothing";
case Integer i when i < 0 -> "negative " + i;
case Integer i -> "int " + i;
case String s -> "text of length " + s.length();
default -> "other";
};
}| Construct | Use it when | Watch out for |
|---|---|---|
if / else if | A few conditions with different actions | Long chains are a switch waiting to happen |
Ternary ?: | Choosing one of two values | Nesting more than twice |
switch statement | A block of side effects per case | Fall-through when a break is missing |
switch expression | Mapping an input to a value | Every path must yield or throw |
| Pattern switch | Dispatching on type or shape | Order matters — specific cases first |
Labelled break | Leaving a nested loop | Usually clearer as an extracted method |
⚠️
A classic
switch statement without break falls through into the next case and runs code you did not intend. The arrow form of switch removes the hazard entirely, so prefer it in all new code.Loops and method design
for (int i = 0; i < 3; i++) System.out.print(i);
for (String n : names) System.out.print(n);
while (!queue.isEmpty()) process(queue.poll());
names.removeIf(String::isBlank); // never modify a collection inside a for-each
static int max(int first, int... rest) { // varargs: last parameter, at most one
int best = first;
for (int value : rest) best = Math.max(best, value);
return best;
}
max(1);
max(1, 2, 3);- Java passes primitives by value and object references by value, so reassigning a parameter never affects the caller, but mutating the object does.
- Overloads are chosen at compile time from the static types, which is why a null argument can bind to an unexpected method.
- Varargs are an array at run time: passing no arguments gives an empty array, but passing
nullexplicitly does not. - Return a value instead of mutating a parameter when you can; it makes the method easier to test and to reason about.
- Keep methods short enough to read without scrolling, and give one reason to change.
Compact source files and instance main
// Hello.java — a compact source file: no class declaration, no static, no args
void main() {
String name = IO.readln("Name? ");
IO.println("Hello, " + name);
}java Hello.java # compiles and runs in one step, no build file neededA compact source file allows top-level methods, gives the file an implicit unnamed class, and makes main instance-based and argument-free. The java.lang.IO convenience API removes the ceremony of System.out and a reader for small tools.
- The unnamed class cannot be imported from another file; a compact source file is a program, not a library.
- Add ordinary classes and methods after
mainin the same file when the program grows a little. - Move to a normal package with explicit classes as soon as you need tests, visibility control or reuse.
- The traditional
public static void main(String[] args)still works and is what any framework expects.
FAQ
Is a compact source file suitable for production?
For scripts, internal tools and teaching, yes. For anything with tests, packages or public API surface, use ordinary classes so visibility, imports and build layout stay explicit.
When should I prefer a switch expression over if/else?
Whenever the code maps one input to one result and the set of cases is closed — enums, sealed hierarchies, command strings. The compiler then checks exhaustiveness, so adding a case later surfaces every place that must change.
Related
Setting up a modern Java toolchain Generics, lambdas and the streams API
Last refreshed 2026-09-18.