Create program flow control constructs including if/else, switch statements and expressions, loops, and break and continue statements.
if
StatementOne of the most fundamental control flow statements in Java and many other programming languages is the if
statement. It allows your program to make decisions and execute different code paths based on whether certain conditions are met.
In essence, the purpose of an if
statement is to conditionally execute a block of code. If the specified condition evaluates to true
, the code block will run. If not, that block is skipped over and the program continues with the next statement after the if block.
Here’s the flowchart diagram for the if
statement:
┌─────────┐
│ Start │
└────┬────┘
│
┌─────┴─────┐
│ Condition │
└─────┬─────┘
│
┌──────┴──────┐
┌────┤ Is true? ├────┐
│ └─────────────┘ │
│ │
┌──┴──┐ ┌──┴──┐
│ Yes │ │ No │
│ │ │ │
│─────┴──────────┐ ┌──┴─────┴─────┐
│ Execute │ │ Execute │
│ if block │ │ else block │
└─────────┬──────┘ └──────┬───────┘
│ │
└────────┬────────┘
│
┌─────┴─────┐
│ End │
└───────────┘
The basic syntax of an if
statement looks like this:
if (condition) {
// Code to execute if condition is true
}
The condition goes inside parentheses and must evaluate to a boolean value, either true
or false
. The code to conditionally execute goes between curly braces. If the code block contains only a single statement, you can omit the curly braces:
if (x > 10)
System.out.println("x is greater than 10");
However, using curly braces is considered good practice even for single statements, as it makes your code clearer and less prone to errors if you later add more statements to the block.
You can chain multiple conditions together using the else if
construct:
if (condition1) {
// Code to execute if condition1 is true
} else if (condition2) {
// Code to execute if condition1 is false and condition2 is true
} else {
// Code to execute if both condition1 and condition2 are false
}
Here, each else if
condition will only be checked if all the prior if
/else if
conditions evaluated to false
. As soon as one condition is found to be true
, its corresponding block executes and the rest of the if
/else if
/else
chain is skipped. The final else
block runs if none of the conditions were true
.
There’s no hard limit to how many else if
statements you can have, but if you find yourself with very long if
/else if
chains, you may want to consider refactoring to a cleaner approach, such as a switch
statement or polymorphism.
A common point of confusion is attempting to access variables declared inside an if
block from the corresponding else
block:
if (condition) {
int x = 10;
} else {
System.out.println(x); // Compile error - x is not in scope!
}
This fails because variables declared inside an if
or else
block are only in scope within that block. To use a variable in both the if
and else
sections, you must declare it outside (before) the if
statement.
Also, if
statements can use pattern matching along with the instanceof
operator:
if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}
Here, obj
is tested to see if it’s an instance of String
. If so, it’s cast to String
and assigned to the pattern variable s
, which can then be used in the if
block.
There are a few rules when using pattern matching in if
statements:
instanceof
.For example:
if (getObject() instanceof String s) {
System.out.println(s); // s in scope here
} else {
System.out.println(s); //Compile error! s is definitely not a String
}
// ...
Object getObject() {
return "hi";
}
In the above example, the type of the pattern variable is String
, a subtype of Object
(the type returned by the getObject()
method), so there’s no problem. However, in the else
block, the compiler cannot infer the type of s
. Let’s talk about why.
One important aspect to understand when using pattern matching in if
statements is the concept of flow scoping. This refers to how the compiler reasons about the scope and availability of pattern variables based on the flow of control through your code.
Consider this example:
if (obj instanceof String s) {
System.out.println(s); // s is definitely a String here
} else {
System.out.println(s); // Compiler error: s might not be initialized
}
System.out.println(s); // Compiler error: s is not in scope here
Inside the if
block, s is definitely a String
, the compiler knows this because the instanceof
check must have succeeded for that block to execute. Therefore, it’s safe to use s
as a String
within this scope.
However, in the corresponding else
block, s
is not considered initialized. The compiler doesn’t assume the opposite of the if
condition, it reasons that if the else
block is executing, the instanceof
check must have failed, and so s
was never assigned a value. Attempting to use s
here results in a compile error.
Outside the if-else
statement entirely, s
is not in scope at all. Pattern variables are only accessible within the if
block where they’re declared, and in subsequent else if
or else
blocks if the compiler can prove they were definitely assigned.
Flow scoping becomes more complex when you have multiple pattern variables in play:
if (obj instanceof String s || obj instanceof Integer i) {
// s or i is in scope, but not both
} else {
// neither s nor i are in scope
}
In this case, inside the if
block, only one of s
or i
will be in scope, depending on which instanceof check succeeded. The compiler doesn’t let you use a pattern variable unless it can definitively say it was assigned.
If you need to use a pattern variable in multiple scopes, you must assign it separately:
String s = null;
if (obj instanceof String temp) {
s = temp;
}
// s is now in scope, but may be null if the if block didn't execute
This may feel like a limitation, but it is actually a powerful safety feature. By tightly controlling the scope of pattern variables, Java helps prevent common bugs and makes your code more robust.
It’s worth noting that flow scoping only applies to the declared pattern variables themselves, not the original variables. In the example above, obj
remains in scope throughout, because it was declared before the if
statement.
switch
StatementSometimes, you need to check the value of a variable or expression and execute different code depending on what that value is. If there are only a couple of options, an if-else
statement works fine:
String animal = "cat";
if(animal.equals("dog")) {
System.out.println("Woof!");
} else {
System.out.println("Meow!");
}
But what if there are many possible values to check? You could chain a bunch of if-else
statements together:
String animal = "horse";
if(animal.equals("dog")) {
System.out.println("Woof!");
} else if(animal.equals("cat")) {
System.out.println("Meow!");
} else if(animal.equals("pig")) {
System.out.println("Oink!");
} else if(animal.equals("horse")) {
System.out.println("Neigh!");
} else {
System.out.println("Unknown animal!");
}
However, this can get cumbersome and messy fast. That’s where the switch
statement comes in. It allows you to define separate code blocks for different values of a variable or expression.
Here’s the diagram for the switch
statement:
┌─────────────────────────────────────┐
│ switch (variable) │
│ ┌───────────────────────────────┐ │
│ │ case value1: │ │
│ │ // code block │ │
│ │ break; │ │
│ ├───────────────────────────────┤ │
│ │ case value2: │ │
│ │ // code block │ │
│ │ break; │ │
│ ├───────────────────────────────┤ │
│ │ case value3: │ │
│ │ // code block │ │
│ │ break; │ │
│ ├───────────────────────────────┤ │
│ │ default: │ │
│ │ // code block │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────┘
And this is its basic syntax:
switch(variable) {
case value1:
// code to run if variable == value1
break;
case value2:
// code to run if variable == value2
break;
default:
// code to run if no case matches
}
So the animal example could be rewritten more cleanly as:
String animal = "horse";
switch(animal) {
case "dog":
System.out.println("Woof!");
break;
case "cat":
System.out.println("Meow!");
break;
case "pig":
System.out.println("Oink!");
break;
case "horse":
System.out.println("Neigh!");
break;
default:
System.out.println("Unknown animal!");
}
Each case
defines a value to compare the switch variable against. If there’s a match, the code for that case executes. The break
causes execution to jump to the end of the switch
block. If no case matches, the default
block runs.
It’s important to include a break
(or return
) statement for each case, otherwise execution falls through to the next case, which is rarely what you want. The default case doesn’t need an explicit break
since it’s the last one.
case
StatementsNot just any type can be used in a switch
. Historically, switches could only work with these integral types and their wrapper classes:
int
/Integer
byte
/Byte
short
/Short
char
/Character
Then, in later versions of Java, String
and the constants of an enum
were added as an option.
Also, you can use var
in a switch
statement as long as the type resolves to one of the other permitted types:
var animal = "horse";
switch(animal) {
case "dog":
System.out.println("Woof!");
break;
case "cat":
System.out.println("Meow!");
break;
case "pig":
System.out.println("Oink!");
break;
case "horse":
System.out.println("Neigh!");
break;
default:
System.out.println("Unknown animal!");
}
In this case, animal
is inferred to be a String
based on the value assigned to it. Since String
is a valid type for a switch, using var
here is perfectly fine.
However, if you try to do something like this:
var data = 3.14;
switch(data) {
// ...
}
You will get a compilation error because data
is inferred to be a double
, which is not a permitted type for switch
statements.
case
StatementsWhen defining the values for each case
, there are some important rules to keep in mind. The value must be a compile-time constant, meaning it has to be known at the time the code is compiled, not determined at runtime.
So you can use literal values like "dog"
or 3
, final
variables (as long as they’re initialized with a constant value), and enum
constants. But you can’t use a regular variable or a method call, even if the method always returns the same value. For example:
final int NUMBER = 2;
int getSome() {
return 1;
}
int x = 3;
switch(value) {
case NUMBER: // OK, NUMBER is final and initialized with a constant
case getSome(): // Error! Method calls aren't allowed
case x: // Error! x is not final
...
}
Sometimes, you might want to run the same code for multiple case
values. Rather than duplicating the code, you can simply list the values together for a single case:
int dayNumber;
switch(dayName) {
case "Monday":
dayNumber = 1;
break;
case "Tuesday":
dayNumber = 2;
break;
case "Saturday", "Sunday": // Runs the same code for "Saturday" and "Sunday"
dayNumber = 0;
break;
default:
throw new IllegalArgumentException("Invalid day: " + dayName);
}
I mentioned this earlier, but it’s worth reiterating, don’t forget to break
out of each case block (or use return
), unless you specifically want execution to fall through to the next case. Forgetting a break
is a common source of bugs in switch statements.
switch
ExpressionJava 14 officially introduced a new form of switch
, known as the switch
expression. It has a few key differences from the traditional switch
statement. First, here’s the syntax:
variable = switch(anotherVariable) {
case value1 -> expression1;
case value2 -> { statements; yield expression2; }
default -> expression3;
};
Instead of case:
and break
, the switch expression uses ->
to map each case to a value or block of code. If you need multiple statements for a case, use curly braces and the yield
keyword to specify the value to return.
Note the semicolons. Each case needs one at the end, as does the entire switch
expression.
The switch
expression must always return a value, and each case must cover all possibilities (either explicitly or with a default
). The data types of all the case
results must also be consistent with each other.
Here’s a more concrete example:
String animal = "horse";
String sound = switch(animal) {
case "dog" -> "Woof!";
case "cat" -> "Meow!";
case "pig" -> "Oink!";
case "horse" -> "Neigh!";
case "human" -> {
String greeting = "Hello!";
yield greeting; // Use yield when there are multiple statements
}
default -> throw new IllegalArgumentException("Unknown animal: " + animal);
};
In this case, each animal is mapped directly to the sound it makes, except for human
which has a block of code. The default
case throws an exception since the switch
expression must cover all possible input values.
while
LoopA while
loop allows you to repeatedly execute a block of code as long as a specified boolean
condition remains true
.
Here’s the flowchart diagram for the while
statement:
┌─────────┐
│ Start │
└────┬────┘
│
┌─────┴─────┐
┌────┤ Condition │
│ └─────┬─────┘
│ │
│ ┌─────┴─────┐
│ │ Is true? ├───────┐
│ └─────┬─────┘ │
│ │ │
│ ┌─────┴─────┐ ┌─────┴─────┐
│ │ Yes │ │ No │
│ └─────┬─────┘ └─────┬─────┘
│ │ │
│ ┌─────┴─────┐ │
│ │ Execute │ │
│ │ Loop │ │
│ │ Body │ │
│ └─────┬─────┘ │
│ │ │
└──────────┘ │
│
┌────┴────┐
│ End │
└─────────┘
There are actually two variants of the while
loop in Java:
while
loopdo-while
loopThe standard while
loop has the following structure:
while(condition) {
// code block to be executed
}
The condition is a boolean
expression that is evaluated before each iteration of the loop. If the condition is true
, the code block is executed. This process repeats until the condition becomes false
.
It’s important to note that if the condition is false when the loop is first reached, the code block will not be executed at all. The loop will be skipped entirely.
Here’s an example that prints the numbers 0 through 9:
int count = 0;
while(count < 10) {
System.out.println(count);
count++;
}
The loop will continue executing until count is no longer less than 10.
The do-while
loop is similar to the standard while
loop but with one key difference: the condition is evaluated after the code block has executed. This means the code block will always execute at least once, even if the condition is initially false.
Here’s the syntax of a do-while
loop:
do {
// code block to be executed
} while(condition);
As you can see, the code block comes before the while
keyword and condition. The condition is checked after each iteration, determining whether the loop should continue or terminate.
The following example is functionally equivalent to the previous while
loop example:
int count = 0;
do {
System.out.println(count);
count++;
} while(count < 10);
Even though the structure is different, this do-while
loop achieves the same result as the standard while
loop, printing the numbers 0 through 9.
So why would you choose a do-while
loop over a standard while
loop? It really depends on the specific problem you’re trying to solve. If you know you always want the code block to execute at least once regardless of the initial condition state, a do-while
can be a good choice and can make your intention clearer. However, in many cases, a standard while
loop is sufficient and more commonly used.
It’s possible to place one loop inside the body of another loop. This is known as loop nesting. Nested loops allow you to iterate over multiple dimensions, such as the rows and columns of a 2D array.
Here’s an example that uses nested while
loops to print out a multiplication table:
int i = 1;
while(i <= 10) {
int j = 1;
while(j <= 10) {
System.out.print(i * j + "\t");
j++;
}
System.out.println();
i++;
}
The outer loop iterates from 1 to 10, representing the rows of the multiplication table. For each iteration of the outer loop, the inner loop also iterates from 1 to 10, representing the columns. The product of the current row and column values is printed, followed by a tab (\t
) character for formatting. After each row is complete, a newline is printed to move to the next row.
While this example uses while
loops, you can also nest do-while
loops in a similar manner. The choice of loop type depends on the specific requirements of your use case.
break
and continue
StatementsThe break
statement is used to immediately terminate a loop or switch statement. When encountered inside a loop, break
causes program control to transfer to the next statement after the loop.
Here’s an example of using break
in a while
loop:
int count = 0;
while(true) {
System.out.println(count);
count++;
if(count >= 5) {
break;
}
}
This loop will continue infinitely because the condition is always true. However, the break
statement inside the loop will cause it to terminate once count reaches 5.
On the other hand, the continue
statement is used to skip the rest of the current loop iteration and immediately move on to the next iteration.
Here’s an example that uses continue
:
int i = 0;
while(i < 10) {
if(i % 2 == 0) {
i++;
continue;
}
System.out.println(i);
i++;
}
This loop iterates from 0 to 9. However, when i
is even (divisible by 2), the continue
statement is executed, causing the rest of the iteration to be skipped. As a result, only the odd numbers are printed.
However, it’s important to note that using break
or continue
can sometimes lead to unreachable code, which will cause a compilation error.
Consider this example:
while(condition) {
// code block
break;
// more code
}
The code after the break
statement will never be executed because break
always causes the loop to terminate. The Java compiler will detect this and raise an “unreachable code” compilation error.
The same applies to continue
. Any code placed after a continue
statement in the same loop iteration will be unreachable.
To avoid these errors, make sure that any code placed after a break
or continue
has a chance to execute under some condition.
Finally, you can associate a label with a loop. Labels provide a way to break out of or continue a specific outer loop from within a nested loop. Here’s the syntax for adding a label to a loop:
label:
while(condition) {
// code block
}
The label is an identifier followed by a colon. It’s placed just before the loop declaration.
Here’s an example that demonstrates the use of labels:
int i = 0;
outerLoop:
while(i < 10) {
int j = 0;
while(j < 10) {
if(j == 5) {
break outerLoop;
}
System.out.println("i: " + i + ", j: " + j);
j++;
}
i++;
}
In this case, the outer loop is labeled outerLoop
. Inside the nested loop, there’s a condition that checks if j
is equal to 5. When this condition is met, the break
statement is used with the outerLoop
label, causing execution to jump out of both the inner and outer loops. Without the label, the break would only exit the inner loop.
Like break
, continue
can also be used with a label to skip to the next iteration of an outer loop.
Here’s an example that demonstrates this:
int i = 0;
outerLoop:
while(i < 3) {
int j = 0;
while(j < 3) {
if(i == 1 && j == 1) {
i++;
continue outerLoop;
}
System.out.println("i: " + i + ", j: " + j);
j++;
}
i++;
}
In this example, the outer loop is labeled outerLoop
. The outer loop iterates over the values of i
from 0 to 2, and the inner loop iterates over the values of j
from 0 to 2.
Inside the nested loops, there’s a condition that checks if both i
and j
are equal to 1. When this condition is met, the continue
statement is used with the outerLoop
label. This causes the program control to immediately jump to the next iteration of the outer loop, skipping the rest of the inner loop.
As a result, the output of this code will be:
i: 0, j: 0
i: 0, j: 1
i: 0, j: 2
i: 1, j: 0
i: 2, j: 0
i: 2, j: 1
i: 2, j: 2
Notice that the output i: 1, j: 1
is missing because when i
and j
are both 1, the continue outerLoop
statement is executed, causing the program to skip to the next iteration of the outer loop, bypassing the print statement.
Using continue
with a label is less common than using break
with a label, but it can be useful in situations where you want to skip multiple levels of nested loops based on a certain condition.
for
LoopLike while
loops, for
loops are used to repeatedly execute a block of code. However, for
loops provide a more concise syntax for iterating over a range of values or elements in a collection.
In Java, there are two types of for
loops:
for
loopfor-each
loop (also known as the enhanced for
loop)Here’s a diagram with the key points of the for
loops:
┌─────────────────────────────────────────────────────────────┐
│ Java for Loops │
│ │
│ Traditional for Loop │ for-each Loop │
│ │ │
│ for (int i = 0; i < 5; i++) │ for (int num : numbers) { │
│ { │ // code block │
│ // code block │ } │
│ } │ │
│ │ │
│ Components: │ Components: │
│ 1. Initialization │ 1. Element variable │
│ 2. Condition │ 2. Collection to iterate │
│ 3. Update statement │ │
│ │ │
│ Use when: │ Use when: │
│ - Need index │ - Don't need index │
│ - Custom increments │ - Iterating full collection │
│ - Multiple counters │ - Simpler syntax preferred │
└─────────────────────────────────────────────────────────────┘
Let’s start by examining in more detail the traditional for
loop.
for
LoopThe traditional for
loop has the following structure:
for(initialization; booleanExpression; updateStatement) {
// code block to be executed
}
The loop consists of three parts separated by semicolons:
Initialization: This is where you initialize the loop variable(s). It’s executed only once at the beginning of the loop.
Boolean Expression: This is the condition that’s checked before each iteration. If it evaluates to true
, the loop continues. If it’s false
, the loop terminates.
Update Statement: This is where you specify how the loop variable(s) should be updated after each iteration. It’s executed at the end of each iteration.
Here’s a simple example that prints the numbers 0 to 4:
for(int i = 0; i < 5; i++) {
System.out.println(i);
}
The loop initializes i
to 0, checks if i
is less than 5, and if so, executes the code block (printing the value of i
). After each iteration, i
is incremented by 1. The loop continues until i
is no longer less than 5.
You can also use the var
keyword in the initialization part:
for(var i = 0; i < 5; i++) {
System.out.println(i);
}
If you omit the boolean expression, it defaults to true
, creating an infinite loop:
for(int i = 0; ; i++) {
System.out.println(i);
}
This loop will continue indefinitely because there’s no condition to make it false
. To stop an infinite loop, you’d need to use a break
statement or some other means of interrupting the loop.
You can initialize multiple variables and include multiple update statements in a for
loop by separating them with commas:
for(int i = 0, j = 10; i < j; i++, j--) {
System.out.println("i: " + i + ", j: " + j);
}
This loop initializes i
to 0 and j
to 10, checks if i
is less than j
, and if so, executes the code block. After each iteration, i
is incremented, and j
is decremented.
It’s important to note that you cannot redeclare a variable in the initialization block of a for
loop:
int i = 0;
for(int i = 0; i < 5; i++) { // Doesn't compile
System.out.println(i);
}
This code will not compile because i
is declared twice. If you need to use a variable that’s already declared, simply omit the data type in the initialization block:
int i = 0;
for(i = 0; i < 5; i++) { // OK
System.out.println(i);
}
Also, all variables declared in the initialization block must be of the same data type or compatible types:
for(int i = 0, long j = 10; i < j; i++, j--) { // Doesn't compile
System.out.println("i: " + i + ", j: " + j);
}
This code will not compile because i
is of type int
, and j
is of type long
. Here is the corrected example:
for(int i = 0, j = 10; i < j; i++, j--) {
System.out.println("i: " + i + ", j: " + j);
}
Alternatively, if you need to use different data types, you should declare them before the loop:
int i = 0;
long j = 10;
for(; i < j; i++, j--) {
System.out.println("i: " + i + ", j: " + j);
}
Regarding the scope of a variable declared in the initialization block, it is limited to the for
loop. You cannot use it outside the loop:
for(int i = 0; i < 5; i++) {
System.out.println(i);
}
System.out.println(i); // Doesn't compile
Once again, if you need to use the final value of the loop variable after the loop, you must declare it before the loop:
int i;
for(i = 0; i < 5; i++) {
System.out.println(i);
}
System.out.println(i); // OK, prints 5
In many cases, you may need to compare the current loop variable with other elements in the loop. The traditional for
loop makes this possible by allowing you to read elements forward or backward:
int[] arr = {1,2,3,4,5};
for(int i = 0; i < arr.length; i++) {
// Read forward
if(i < arr.length - 1) {
System.out.println("Current: " + arr[i] + ", Next: " + arr[i+1]);
}
// Read backward
if(i > 0) {
System.out.println("Current: " + arr[i] + ", Previous: " + arr[i-1]);
}
}
The forward reading if condition checks if the current element is not the last one and if so, it prints the current element and the next one.
The backward reading if condition checks if the current element is not the first one and if so, it prints the current element and the previous one.
for-each
LoopThe for-each
loop, also known as the enhanced for
loop, provides a simpler way to iterate over arrays and collections. It eliminates the need to explicitly declare and update loop variables.
The structure of a for-each
loop is as follows:
for(dataType item : collection) {
// code block to be executed
}
The loop consists of two parts with three elements:
dataType: The data type of the elements in the collection.
item: A variable that will hold the current element during each iteration.
collection: The array or collection to be iterated over.
Here’s an example that prints the elements of an array using a for-each
loop:
int[] numbers = {1, 2, 3, 4, 5};
for(int num : numbers) {
System.out.println(num);
}
In each iteration, the loop assigns the next element of the numbers array to the num
variable and executes the code block.
The for-each
loop can be used with with arrays and with any object that implements the Iterable
interface, which includes most collection classes, such as ArrayList
and HashSet
.
If you’re wondering if everything that applies to for
loops applies to for-each
loops, the answer is not quite. While for
loops and for-each
loops share some similarities, there are a few key differences in how they behave and what they can do:
Iteration: A for-each
loop automatically iterates over all elements in an array or collection, from the first to the last. You don’t have control over the index or the order of iteration. A traditional for
loop, on the other hand, gives you full control over the initialization, condition, and update statements, allowing you to iterate in any order or skip elements.
Modification: A for-each
loop does not prevent you from modifying the elements of the array or collection within the loop, but it does not provide direct access to the index. You can modify the elements if the underlying collection supports modification. In contrast, a traditional for
loop allows you to modify elements by accessing them via their index.
Iterating over arrays and collections: A for-each
loop can be used to iterate over arrays and any object that implements the Iterable
interface, which includes most collection classes. A traditional for
loop can be used to iterate over arrays and collections, but you need to use an explicit index or iterator.
Accessing index: In a for-each
loop, you don’t have direct access to the index of the current element. If you need the index, you’ll have to use a traditional for
loop, which gives you access to the index through the loop variable.
Performance: For arrays, the performance difference between a for-each
loop and a traditional for loop is generally negligible. For collections, the performance is similar as a for-each loop
is syntactic sugar for using an iterator.
Here’s an example that demonstrates a situation where a for-each
loop cannot be used:
int[] numbers = {1, 2, 3, 4, 5};
for(int i = 0; i < numbers.length; i++) {
if(numbers[i] % 2 == 0) {
numbers[i] *= 2; // Double even numbers
}
}
In this case, we need to modify the elements of the array based on a condition. We also need access to the index to perform the modification. This cannot be done with a for-each
loop.
However, if we just needed to print the doubled even numbers, a for-each
loop would be suitable:
int[] numbers = {1, 2, 3, 4, 5};
for(int num : numbers) {
if(num % 2 == 0) {
System.out.println(num * 2); // Print doubled even numbers
}
}
In summary, for-each
loops provide a concise syntax for iterating over all elements, while for loops offer more control and flexibility, allowing you to access indexes and iterate in custom ways.
Just like while
loops, for
loops can also be nested. This allows you to iterate over multidimensional arrays or perform complex iterations.
int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
for(int[] row : matrix) {
for(int cell : row) {
System.out.print(cell + " ");
}
System.out.println();
}
This code uses two nested for-each
loops to iterate through a 2D array. The outer loop iterates over each row, and the inner loop iterates over each cell in the current row.
break
and continue
StatementsThe break
statement can be used in for
loops to prematurely terminate the loop.
int[] numbers = {1, 2, 3, 4, 5};
for(int num : numbers) {
if(num == 3) {
break;
}
System.out.println(num);
}
In this example, the loop will terminate when num
is equal to 3. The output will be:
1
2
On the other hand, the continue
statement can be used in for
loops to skip the rest of the current iteration and move on to the next one.
int[] numbers = {1, 2, 3, 4, 5};
for(int num : numbers) {
if(num % 2 == 0) {
continue;
}
System.out.println(num);
}
This loop will print only the odd numbers in the array. When num
is even, the continue
statement is executed, and the rest of the iteration is skipped.
Also, using break
or continue
in for
loops can sometimes lead to unreachable code, resulting in compilation errors.
for(int i = 0; i < 10; i++) {
System.out.println(i);
break;
System.out.println("Unreachable"); // Unreachable code
}
In this example, the code after the break
statement is unreachable because break
always causes the loop to terminate. The Java compiler will detect this and throw a compilation error.
The same principle applies to continue
. Any code after a continue
statement in the same iteration will be unreachable.
To avoid these errors, ensure that any code placed after a break
or continue
statement has a chance to execute under some condition.
Labels can be added to for
loops in the same way as while
loops. They are useful for breaking out of or continuing outer loops from within nested loops:
int[][] matrix = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
outerLoop:
for(int[] row : matrix) {
for(int cell : row) {
if(cell == 5) {
break outerLoop;
}
System.out.print(cell + " ");
}
System.out.println();
}
In this example, the outer loop is labeled as outerLoop
. When the value of cell
is 5, the break
statement is used with the outerLoop
label, causing the program to terminate both the inner and outer loops. This is what happens:
(1, 2, 3)
of matrix
.
(4, 5, 6)
.
break outerLoop;
is executed.The program ends at this point. The output is:
1 2 3
4
The third row (7, 8, 9)
is never processed because the loops were terminated early.
The if
statement allows your program to conditionally execute a block of code based on a boolean condition.
The basic syntax of an if
statement is: if (condition) { code }
. The code block executes if the condition is true.
You can chain multiple conditions using else if
. The conditions are checked in order until one is true or the else
block is reached.
Variables declared inside an if
or else
block are only in scope within that block.
if
statements can use pattern matching with the instanceof
operator, assigning the matched object to a pattern variable for use in the if
block.
The scope of pattern variables is tightly controlled by the compiler based on flow scoping rules to prevent bugs.
The switch
statement allows executing different code blocks based on the value of a variable or expression.
Each case
in a switch
defines a value to compare against. If there’s a match, that case’s code block executes.
Include a break
statement at the end of each case block to prevent fall-through, unless fall-through is desired.
switch
statements can work with String
, enum
constants, and integral types like int
, char
, etc.
Case values must be compile-time constants.
Java 14 officially introduced switch
expressions, which use ->
to map cases to result values and must cover all input possibilities.
The while
loop repeatedly executes a code block as long as its boolean condition remains true.
If the condition is initially false
, the code block will not execute at all.
The do-while
loop is similar but the condition is checked after each iteration, so the code block always executes at least once.
You can nest one loop inside another to iterate over multiple dimensions.
The break
statement immediately terminates a loop, while continue
skips to the next iteration.
You can give a loop a label and then use break
or continue
with that label to break out of or continue an outer labeled loop.
The for
loop provides a concise syntax for iterating over a range of values.
The traditional for
loop has an initialization, condition, and update statement. The code block executes repeatedly until the condition is false
.
Variables declared in the initialization block are limited in scope to the for
loop.
The for-each
loop (enhanced for
loop) simplifies iterating over arrays/collections, eliminating the need for explicit indexing.
for-each
can’t be used if you need the index or want to iterate in a custom order. Use a traditional for
loop in those cases.
You can use break
/continue
and labels with for
loops just like with while
loops.
Avoid unreachable code after break
or continue
statements.
1. What will be the output of the following program?
public class IfStatementTest {
public static void main(String[] args) {
int x = 10;
if (x > 5) {
if (x < 20) {
System.out.println("x is between 5 and 20");
}
} else {
System.out.println("x is 5 or less");
}
}
}
A) x is between 5 and 20
B) x is 5 or less
C) x is greater than 20
D) The program does not compile
E) The program compiles but does not produce any output
2. Which of the following code snippets compile without error?
public class FlowScopingTest {
public static void main(String[] args) {
int x = 10;
if (x > 5) {
int y = x * 2;
}
// Code snippet 1
System.out.println(y);
if (x < 20) {
int z = x + 5;
}
// Code snippet 2
z += 5;
int a = 5;
if (a > 0) {
a = 15;
}
// Code snippet 3
System.out.println(a);
if (x > 0) {
int b = x + 3;
if (b > 15) {
b -= 2;
}
}
// Code snippet 4
System.out.println(b);
}
}
A) Code snippet 1
B) Code snippet 2
C) Code snippet 3
D) None of the above
3. What will be the output of the following program?
public class SwitchTest {
public static void main(String[] args) {
int dayOfWeek = 3;
String dayType;
switch (dayOfWeek) {
case 1:
case 7:
dayType = "Weekend";
break;
case 2:
case 3:
case 4:
case 5:
case 6:
dayType = "Weekday";
break;
default:
dayType = "Invalid day";
}
System.out.println(dayType);
}
}
A) Weekend
B) Invalid day
C) Weekday
D) The program does not compile
E) The program compiles but does not produce any output
4. What will be the output of the following program?
public class SwitchExpressionTest {
public static void main(String[] args) {
int score = 85;
String grade = switch (score) {
case 90, 100 -> "A";
case 80, 89 -> "B";
case 70, 79 -> "C";
case 60, 69 -> "D";
default -> "F";
};
System.out.println(grade);
}
}
A) A
B) F
C) The program does not compile
D) B
E) The program compiles but does not produce any output
5. What will be the output of the following program?
public class LabeledBreakTest {
public static void main(String[] args) {
int count = 0;
outerLoop:
while (count < 5) {
while (true) {
count++;
if (count == 3) {
break outerLoop;
}
}
}
System.out.println(count);
}
}
A) 2
B) 3
C) 4
D) 5
E) The program does not compile
6. What will be the output of the following program?
public class ForLoopTest {
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum += i;
}
System.out.println(sum);
}
}
A) 5
B) 10
C) 15
D) 20
E) The program does not compile
7. What will be the output of the following program?
public class EnhancedForLoopTest {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
int sum = 0;
for (int num : numbers) {
if (num % 2 == 0) {
continue;
}
sum += num;
}
System.out.println(sum);
}
}
A) 9
B) 10
C) 12
D) 15
E) The program does not compile
Do you like what you read? Would you consider?
Do you have a problem or something to say?