Introduction
Conditional statements and loops are a very important tool in programming. There aren't many things we could do with code that can only execute line-by-line.
That's what "flow control" means - guiding the execution of our program, instead of letting it execute line-by-line regardless of any internal or external factors. Every programming language supports some form of flow control, if not explicitly via ifs and fors or similar statements - then it implicitly gives us the tools to create such constructs, i.e. low-level programming languages usually achieve that affect with a lot of go-to commands.
Loops were a concept used long before computer programming was even a thing, but the first person to use a software loop was Ada Lovelace, commonly known by her maiden name - Byron, while calculating Bernoulli numbers, back in the 19th century.
go-to commands are to be avoided in most situations, whenever we're using a programming language that gives us the tools to avoid it, like Java and all remotely similar languages do (there's a slight exception to this rule when breaking nested loops).
In Java, there are several ways to control the flow of the code:
- if and if-else statements
- switch statements
whileanddo-whilestatementsforandenhanced forstatementsbreakandcontinuestatements
The if Statement
The if statement is probably the most common form of flow control, regardless of the language. It's very simple and intuitive:
if(true) {
//execute this code block if the argument/expression is true
//some more code
}
Since in a lot of cases, only a single line needs to be executed, you can skip using the curly brackets and a block of code and simply indent the next line, though this only works for a single line:
if(true)
System.out.println("Inside the if block");
System.out.println("I have nothing to do with the if block!");
System.out.println("Neither do I!");
Typically, we don't input boolean values like in these examples, but rather, we use an expression:
if(username != null)
System.out.println(username);
if(argument >= 10)
System.out.println("The input is higher or equal than 10");
If the expression is false, the code belonging to the if statement is simply skipped:
if(1 > 5)
System.out.println("Hello");
System.out.println(" World!");
And the output is:
World!
The if-else Statement
We rarely wish to simply skip a piece of code if the expression is evaluated to be false. Typically, we want to do something else in that case:
if(expression) {
//code that executes only if the expression is true
}
else {// optional
//code that executes only if the expression is false
}
Of course, you can use the else statement in conjunction with the shortened if statement:
if(expression)
//code that executes only if the expression is true
else
//code that executes only if the expression is false
However this is unrecommended to if you're not dealing with simple statements, especially with nested ifs since it's hard to figure out "which if does a particular else belong to". Using brackets will take ambiguity out of the problem if you find this approach unreadable.
The else statement statement is optional, so there's no need to write an empty else {} block if we don't want anything to happen if is the expression is false.
The else statement is intrinsically tied to the if statement and can't exist without it. It must appear right after the if statement otherwise an "else without if" compiler error will appear.
In most cases, we want to compare something for equality - whether one variable has the same value as another or whether it's smaller/larger than another:
String s = "smol";
if (s.length() > 8)
System.out.println("s has too many characters!");
else
System.out.println("Ok, so basically, s is very " + s);
The > operator here has the usual "greater than" meaning, and Java supports the usual group of relational operators. These include <, >, <=, =>, == checks for equality and != checks for inequality.
Note: Make sure to use == in if statements instead of =, or else you may assign a value instead of compare it.
2 < 5 //true
2 < 2 //false
2 <= 2 //true
2 == 3 //false
2 != 3 //true
Note: Most of the time, we don't compare String variables using == but with the .equals() method. == checks for object reference equality. For primitive types (int, char, etc.) it's the same as checking whether they have the same value, but with Strings it most commonly isn't.
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
if(string1.equals(string2))
//code to be executed if the strings are equal by value
Nested if Statements
We can have more than one if statement connected, either by nesting (putting one if statement inside another) or adding an else if at the end of our previous if:
int ourNumber = 10;
if(ourNumber > 8){
if(ourNumber % 2 == 0){
System.out.println("The number is larger than 8 and even");
}
}
else if (ourNumber == 1) {
System.out.println("1 is less than 8, so the previous if block isn't executed");
}
else {
System.out.println("ourNumber is less than 8 and different than 1");
}
else blocks always "belong" to the if of the same level, so the else if (ourNumber == 1) in our code belongs to the if(ourNumber > 8) and not the nested if that checks whether the number is even.
You can have as many else if blocks as you'd like, but only one else block, which comes last. Each if, else if and else block that evaluates to true will execute:
Multiple Expressions in a Single if Statement
Another very useful thing is the ability to check multiple conditions in a single if:
int ourNumber = 10;
if(ourNumber > 5 && (ourNumber % 2 == 0)){
System.out.println("The number is larger than 8 and even");
}
The && operator is one of the logical operators Java supports. boolExpr is used as shorthand for boolean expression. Reminder: a boolean expression is an expression that can be evaluated as true or false, i.e. it can also be an expression containing a logical operator, as we can see here:
!boolExpr-!is negation, it evaluates atrueexpression tofalseand vice versa.boolExpr1 & boolExpr2- the AND operator evaluates totrueif both expressions aretrue.boolExpr1 | boolExpr2- the OR operator evaluates totrueif at least one of the expressions istrue.boolExpr1 && boolExpr2- the short-circuit AND operator evaluates totrueonly ifboolExpr1andboolExpr2are bothtrue. It's called a short-circuit operator because if the first expression isfalse, it won't even evaluate the second expression as the basic condition that both need to betruecan never occur. With simple expressions, this doesn't affect the code in a meaningful way, but in production code, both expressions can be costly operations and this approach can significantly optimize code.boolExpr1 || boolExpr2- the short-circuit OR operator evaluates totrueif at least one ofboolExpr1andboolExpr2istrue. A short-circuit version of the|operator.boolExpr1 ^ boolExpr2- the XOR operator evaluates totrueonly ifboolExpr1andboolExpr2are evaluate as differently, i.e. if only one of them istrueand the other one isfalse.
true && false //false
(2 < 5) && (2 != 3) //true
false || true //true
true && ((false || false) ^ true) //true
(true && false) || false // false
It's highly recommended to use parentheses whenever it makes sense to use them. The last example works the same without parentheses but relying on operator precedence is extremely risky and leads to unreadable code.
Ternary Constructs
The only ternary operator (an operator that takes three operands) in Java is the ?: operator. It works like a very compact if-else statement.
int max = 0;
if (a > b)
max = a;
else max = b;
//can be written as
int max = (a > b) ? a : b;
Here's how a ternary construct generally looks like:
(expression) ? returnValueIfTrue : returnValueIfFalse
Ternary constructs can work without parentheses as well, though it's generally more readable to use parentheses:
int max = a > b ? a : b;
You can also use ternary constructs to modify variables:
System.out.println("10% discount for orders above $50!");
double orderPrice = 55;
double finalPrice = orderPrice > 50 ? orderPrice*09 : orderPrice;
System.out.println("Your final price is $" + finalPrice);
And the output is:
Your final price is $49.5
Using the construct, we can also call methods:
public void someMethod() {
String userRole = "Admin";
String result = userRole.equals("Admin") ? greetAdmin() : greetUser();
System.out.println(result);
}
static String greetAdmin() {
return "Hello Admin!";
}
static String greetUser() {
return "Hello User!";
}
Logically, this would result in:
Hello Admin!
Nested Ternary Constructs
System.out.println("10% discount for all orders above $50 and additional $5 off if your order exceedes 2 items!");
double orderPrice = 140;
int quantity = 5;
double finalPrice = (orderPrice > 50) ? (quantity > 2) ? (orderPrice*0.9)-5 : orderPrice*0.9 : orderPrice;
System.out.println("Your final price is: $" + finalPrice);
Since both conditions are true, the output is:
10% discount for all orders above $50 and additional $5 off if your order exceedes 2 items!
Your final price is: $121.0
However, this approach is horribly unreadable. If possible, avoid nesting ternary constructs, though if you must, break it down into simpler blocks. For an example, this example can be made a bit more readable:
System.out.println("10% discount for all orders above $50 and additional $5 off if your order exceedes 2 items!");
double orderPrice = 140;
int quantity = 5;
double finalPrice = (orderPrice > 50) ?
(quantity > 2) ?
(orderPrice*0.9)-5 : orderPrice*0.9
: orderPrice;
System.out.println("Your final price is: $" + finalPrice);
Conclusion
Flow control in code is essential for absolutely every application. Statements such as if and if-else are fundamental building blocks and every aspiring developer should be completely in control/aware of how they work.


