Luồng điều khiển (Control Flow)
Sau bài này, bạn sẽ:
- Áp dụng các cấu trúc điều khiển if/else, switch (traditional và enhanced) để ra quyết định
- Sử dụng các vòng lặp for, for-each, while, do-while để xử lý dữ liệu lặp đi lặp lại
- Kiểm soát luồng chương trình với break, continue và labeled statements
- Hiểu unreachable code detection của Java compiler
Bài trước: Toán tử (Operators) — Đã học về các loại operators và operator precedence. Bài này sẽ học cách điều khiển luồng chương trình.
If/Else
1. if Statement
if (condition) {
// Execute nếu condition = true
}
Ví dụ:
int age = 20;
if (age >= 18) {
System.out.println("Bạn đã trưởng thành");
}
2. if-else Statement
if (condition) {
// Execute nếu true
} else {
// Execute nếu false
}
Ví dụ:
int score = 75;
if (score >= 50) {
System.out.println("Đậu");
} else {
System.out.println("Rớt");
}
3. if-else if-else Statement
if (condition1) {
// Execute nếu condition1 = true
} else if (condition2) {
// Execute nếu condition2 = true
} else {
// Execute nếu tất cả đều false
}
Ví dụ:
int score = 85;
if (score >= 90) {
System.out.println("Grade: A");
} else if (score >= 80) {
System.out.println("Grade: B");
} else if (score >= 70) {
System.out.println("Grade: C");
} else if (score >= 60) {
System.out.println("Grade: D");
} else {
System.out.println("Grade: F");
}
4. Nested if
int age = 25;
boolean hasLicense = true;
if (age >= 18) {
if (hasLicense) {
System.out.println("Có thể lái xe");
} else {
System.out.println("Cần bằng lái");
}
} else {
System.out.println("Chưa đủ tuổi");
}
- Dùng
{}braces ngay cả khi chỉ có 1 statement// ❌ BAD - Error-prone
if (condition)
statement1;
statement2; // Không thuộc if! (indentation misleading)
// ✅ GOOD - Clear
if (condition) {
statement1;
statement2;
}
Switch Statement
Traditional Switch (Java 1-13)
switch (expression) {
case value1:
// Statements
break;
case value2:
// Statements
break;
default:
// Default statements
}
Ví dụ:
int day = 3;
switch (day) {
case 1:
System.out.println("Monday");
break;
case 2:
System.out.println("Tuesday");
break;
case 3:
System.out.println("Wednesday");
break;
default:
System.out.println("Other day");
}
Fall-through behavior:
int month = 2;
switch (month) {
case 12:
case 1:
case 2:
System.out.println("Winter");
break; // Quan trọng! Không có break → fall through
case 3:
case 4:
case 5:
System.out.println("Spring");
break;
default:
System.out.println("Other season");
}
Nếu quên break, code sẽ "fall through" sang cases tiếp theo!
int x = 1;
switch (x) {
case 1:
System.out.println("One");
// ❌ Forgot break!
case 2:
System.out.println("Two");
break;
}
// Output:
// One
// Two (fall-through!)
Enhanced Switch (Java 14+)
Switch expressions - modern, concise syntax.
int day = 3;
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
case 3 -> "Wednesday";
case 4 -> "Thursday";
case 5 -> "Friday";
case 6 -> "Saturday";
case 7 -> "Sunday";
default -> "Invalid day";
};
System.out.println(dayName); // "Wednesday"
Benefits:
- ✅ No
breakneeded - ✅ Can return values directly
- ✅ More concise
- ✅ No fall-through (safer)
Multiple values:
String season = switch (month) {
case 12, 1, 2 -> "Winter";
case 3, 4, 5 -> "Spring";
case 6, 7, 8 -> "Summer";
case 9, 10, 11 -> "Fall";
default -> "Invalid month";
};
Block with yield:
int score = 85;
String grade = switch (score / 10) {
case 10, 9 -> "A";
case 8 -> "B";
case 7 -> "C";
case 6 -> {
System.out.println("Barely passed");
yield "D"; // yield để return value từ block
}
default -> "F";
};
Switch Statement OCP Traps
Trap 1: Fall-through behavior (traditional switch)
int day = 1;
String result = "";
switch (day) {
case 1:
result = "Monday";
// ❌ Forgot break!
case 2:
result = "Tuesday";
break;
}
System.out.println(result); // "Tuesday" (not "Monday"!)
Trap 2: Switch type restrictions
Switch expression chỉ accept:
- Primitive:
byte,short,char,int(KHÔNG cólong,float,double) - Wrapper:
Byte,Short,Character,Integer String(Java 7+)enumtypesvar(nếu type hợp lệ)
// ✅ Valid
int x = 5;
switch (x) { }
String s = "Hello";
switch (s) { }
// ❌ Invalid types
long l = 100L;
switch (l) { } // Compile error! long not allowed
double d = 3.14;
switch (d) { } // Compile error! double not allowed
boolean b = true;
switch (b) { } // Compile error! boolean not allowed
Trap 3: Case values must be constants
final int OPTION_A = 1;
int optionB = 2; // Not final!
int choice = 1;
switch (choice) {
case OPTION_A: // ✅ OK - final constant
break;
case optionB: // ❌ Compile error! Not a constant expression
break;
}
Trap 4: Duplicate case labels
int x = 5;
switch (x) {
case 1:
System.out.println("One");
break;
case 1: // ❌ Compile error! Duplicate case
System.out.println("Also one");
break;
}
Trap 5: Default placement (traditional switch)
// ✅ Default có thể ở bất kỳ đâu (nhưng nên ở cuối)
int x = 5;
switch (x) {
default: // ✅ OK - default đầu tiên
System.out.println("Default");
break;
case 1:
System.out.println("One");
break;
}
// Nhưng vẫn fall-through!
switch (x) {
default:
System.out.println("Default");
// ❌ Forgot break → falls through to case 1!
case 1:
System.out.println("One");
break;
}
// Output: Default\nOne
Trap 6: Enhanced switch requires exhaustiveness (for expressions)
int day = 1;
// ❌ Compile error if not exhaustive
String dayName = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
// Missing other cases and no default!
};
// ✅ Must have default or cover all cases
String dayName2 = switch (day) {
case 1 -> "Monday";
case 2 -> "Tuesday";
default -> "Other day";
};
Trap 7: yield vs return
String grade = switch (score / 10) {
case 10, 9 -> "A";
case 8 -> {
System.out.println("Good!");
yield "B"; // ✅ Use yield in switch expression
// return "B"; // ❌ return exits method, not switch!
}
default -> "C";
};
Trap 8: Mixing arrow and colon syntax
// ❌ Cannot mix syntaxes in same switch
switch (day) {
case 1 -> System.out.println("Monday"); // Arrow syntax
case 2: // ❌ Compile error! Cannot mix with colon syntax
System.out.println("Tuesday");
break;
}
Unreachable Code Detection
Java compiler detects unreachable statements và báo compile error.
Case 1: After return
public int test() {
return 10;
System.out.println("Hello"); // ❌ Compile error: unreachable statement
}
Case 2: After break in loop
for (int i = 0; i < 10; i++) {
break;
System.out.println(i); // ❌ Unreachable
}
Case 3: After continue
while (true) {
continue;
System.out.println("Hi"); // ❌ Unreachable
}
Case 4: Constant condition
while (false) {
System.out.println("Never runs"); // ❌ Unreachable
}
// But this is OK (compiler doesn't analyze variable values):
boolean flag = false;
while (flag) {
System.out.println("OK"); // ✅ Compiles (even though never runs)
}
// if với constant condition:
if (false) {
System.out.println("Never"); // ❌ Unreachable
}
Case 5: After throw
public void test() {
throw new RuntimeException();
System.out.println("Hi"); // ❌ Unreachable
}
Case 6: Unreachable catch block
try {
// ...
} catch (FileNotFoundException e) {
// Handle file not found
} catch (IOException e) {
// ❌ Unreachable if FileNotFoundException is subclass of IOException
// (must put more specific exception first)
}
Tricky case: Infinite loop không báo unreachable
while (true) {
System.out.println("Runs forever");
}
System.out.println("After loop"); // ❌ Unreachable (compile error!)
// Nhưng:
for (;;) {
System.out.println("Runs forever");
}
System.out.println("After loop"); // ❌ Unreachable (compile error!)
Loops (Vòng lặp)
1. for Loop
Syntax:
for (initialization; condition; update) {
// Loop body
}
Ví dụ:
// In số từ 1 đến 5
for (int i = 1; i <= 5; i++) {
System.out.println(i);
}
// Output: 1 2 3 4 5
Execution flow:
- Initialization:
int i = 1(chỉ chạy 1 lần) - Condition: Check
i <= 5 - Body: Execute loop body
- Update:
i++ - Repeat từ bước 2
Common patterns:
// Đếm lên
for (int i = 0; i < 10; i++) {
System.out.println(i); // 0 to 9
}
// Đếm xuống
for (int i = 10; i > 0; i--) {
System.out.println(i); // 10 to 1
}
// Bước nhảy 2
for (int i = 0; i < 10; i += 2) {
System.out.println(i); // 0, 2, 4, 6, 8
}
// Multiple variables
for (int i = 0, j = 10; i < j; i++, j--) {
System.out.println(i + " " + j);
}
2. Enhanced for Loop (for-each)
Dùng để iterate qua arrays hoặc collections.
Syntax:
for (type variable : array/collection) {
// Loop body
}
Ví dụ:
int[] numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
System.out.println(num);
}
String[] names = {"Alice", "Bob", "Charlie"};
for (String name : names) {
System.out.println(name);
}
Dùng for-each khi:
- ✅ Chỉ cần đọc giá trị (không modify)
- ✅ Không cần index
Dùng for khi:
- ✅ Cần index
- ✅ Cần modify elements
- ✅ Cần iterate theo pattern khác (backward, skip, ...)
3. while Loop
Syntax:
while (condition) {
// Loop body
}
Ví dụ:
int i = 1;
while (i <= 5) {
System.out.println(i);
i++;
}
// Output: 1 2 3 4 5
Use cases:
// Read input until valid
Scanner sc = new Scanner(System.in);
int age = -1;
while (age < 0 || age > 120) {
System.out.print("Nhập tuổi (0-120): ");
age = sc.nextInt();
}
// Process unknown number of items
while (sc.hasNext()) {
String line = sc.nextLine();
// Process line
}
4. do-while Loop
Execute body ít nhất 1 lần, sau đó check condition.
Syntax:
do {
// Loop body (execute at least once)
} while (condition);
Ví dụ:
int i = 1;
do {
System.out.println(i);
i++;
} while (i <= 5);
// Output: 1 2 3 4 5
while vs do-while:
// while: Check trước, có thể không chạy body
int x = 10;
while (x < 5) {
System.out.println(x); // Không chạy (x = 10)
}
// do-while: Chạy body trước, check sau
do {
System.out.println(x); // Chạy 1 lần (in 10)
} while (x < 5);
Use case: Menu:
Scanner sc = new Scanner(System.in);
int choice;
do {
System.out.println("1. Option A");
System.out.println("2. Option B");
System.out.println("0. Exit");
System.out.print("Choice: ");
choice = sc.nextInt();
switch (choice) {
case 1 -> System.out.println("Selected A");
case 2 -> System.out.println("Selected B");
case 0 -> System.out.println("Goodbye!");
default -> System.out.println("Invalid!");
}
} while (choice != 0);
break và continue
break - Thoát khỏi loop
// Tìm số đầu tiên > 50
for (int i = 1; i <= 100; i++) {
if (i > 50) {
System.out.println("Found: " + i);
break; // Thoát loop
}
}
// Output: Found: 51
break trong nested loops:
// Chỉ thoát loop trong cùng
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (j == 2) {
break; // Chỉ thoát inner loop
}
System.out.println(i + "," + j);
}
}
// Output: 1,1 2,1 3,1
continue - Bỏ qua iteration hiện tại
// In số lẻ
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Skip even numbers
}
System.out.println(i);
}
// Output: 1 3 5 7 9
Labeled loops (Ít dùng)
Thoát khỏi nested loops.
outer:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == 2 && j == 2) {
break outer; // Thoát cả 2 loops
}
System.out.println(i + "," + j);
}
}
// Output: 1,1 1,2 1,3 2,1
Bài tập thực hành
Bài 1: Calculator với Switch
Viết calculator với các phép toán: +, -, *, /, % dùng enhanced switch expression.
Expected output:
Nhập số thứ nhất: 10
Nhập phép toán (+, -, *, /, %): *
Nhập số thứ hai: 5
Kết quả: 10 * 5 = 50
Xem đáp án
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhập số thứ nhất: ");
double num1 = sc.nextDouble();
System.out.print("Nhập phép toán (+, -, *, /, %): ");
char operator = sc.next().charAt(0);
System.out.print("Nhập số thứ hai: ");
double num2 = sc.nextDouble();
double result = switch (operator) {
case '+' -> num1 + num2;
case '-' -> num1 - num2;
case '*' -> num1 * num2;
case '/' -> num1 / num2;
case '%' -> num1 % num2;
default -> {
System.out.println("Phép toán không hợp lệ!");
yield 0;
}
};
System.out.printf("Kết quả: %.2f %c %.2f = %.2f%n",
num1, operator, num2, result);
sc.close();
}
}
Bài 2: In bảng cửu chương
Viết chương trình in bảng cửu chương từ 1 đến 10.
Expected output:
1 x 1 = 1
1 x 2 = 2
...
10 x 10 = 100
Xem đáp án
public class MultiplicationTable {
public static void main(String[] args) {
for (int i = 1; i <= 10; i++) {
for (int j = 1; j <= 10; j++) {
System.out.printf("%d x %d = %d%n", i, j, i * j);
}
System.out.println(); // Blank line
}
}
}
Bài 3: Tìm số nguyên tố
Viết chương trình kiểm tra một số có phải số nguyên tố không.
Expected output:
Nhập số: 17
17 là số nguyên tố
Nhập số: 20
20 không phải số nguyên tố
Xem đáp án
import java.util.Scanner;
public class PrimeChecker {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhập số: ");
int num = sc.nextInt();
boolean isPrime = true;
if (num <= 1) {
isPrime = false;
} else {
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
isPrime = false;
break;
}
}
}
if (isPrime) {
System.out.println(num + " là số nguyên tố");
} else {
System.out.println(num + " không phải số nguyên tố");
}
sc.close();
}
}
Bài 4: Fibonacci Sequence
In ra n số đầu tiên của dãy Fibonacci.
Expected output:
Nhập n: 10
0 1 1 2 3 5 8 13 21 34
Xem đáp án
import java.util.Scanner;
public class Fibonacci {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("Nhập n: ");
int n = sc.nextInt();
int a = 0, b = 1;
for (int i = 0; i < n; i++) {
System.out.print(a + " ");
int next = a + b;
a = b;
b = next;
}
sc.close();
}
}
Tổng kết
Trong bài này, bạn đã học:
✅ Control Flow:
- if/else if/else
- switch (traditional + enhanced với arrow syntax)
✅ Loops:
- for loop
- for-each loop
- while loop
- do-while loop
✅ Loop control:
- break (thoát loop)
- continue (skip iteration)
- labeled loops (thoát nested loops)
Bài tiếp theo chúng ta sẽ học về Packages và Import - tổ chức code trong Java!