Mục tiêu bài học:
- Hiểu và sử dụng các vòng lặp: for, while, do-while
- Sử dụng enhanced for loop (for-each) để duyệt collection
- Áp dụng Stream API (Java 8+) cho xử lý dữ liệu hàm thức
- Sử dụng các lệnh điều khiển vòng lặp: break, continue
- Ứng dụng vòng lặp lồng nhau trong thực tế
Phần 1: Vòng Lặp Cơ Bản
1.1. Vòng lặp for
Cú pháp cơ bản:
for (khởi_tạo; điều_kiện; cập_nhật) {
// Khối lệnh lặp
}Thành phần:
khởi_tạo: Khởi tạo biến điều khiển (thực hiện 1 lần)điều_kiện: Kiểm tra trước mỗi vòng lặpcập_nhật: Cập nhật biến điều khiển sau mỗi vòng lặp
Ví dụ:
public class ForLoopBasic {
public static void main(String[] args) {
// In các số từ 1 đến 10
System.out.print("Các số từ 1 đến 10: ");
for (int i = 1; i <= 10; i++) {
System.out.print(i + " ");
}
System.out.println();
// Đếm ngược từ 10 đến 1
System.out.print("Đếm ngược: ");
for (int i = 10; i >= 1; i--) {
System.out.print(i + " ");
}
System.out.println();
// Tăng bước nhảy
System.out.print("Số chẵn từ 2 đến 20: ");
for (int i = 2; i <= 20; i += 2) {
System.out.print(i + " ");
}
System.out.println();
}
}Ví dụ tính tổng:
public class ForSum {
public static void main(String[] args) {
// Tính tổng từ 1 đến 100
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
System.out.println("Tổng từ 1 đến 100 là: " + sum);
// Tính tổng các số lẻ từ 1 đến 50
int oddSum = 0;
for (int i = 1; i <= 50; i++) {
if (i % 2 != 0) {
oddSum += i;
}
}
System.out.println("Tổng các số lẻ từ 1 đến 50 là: " + oddSum);
}
}1.2. Vòng lặp while
Cú pháp:
while (điều_kiện) {
// Khối lệnh lặp
}Đặc điểm: Kiểm tra điều kiện trước, nếu đúng thì thực thi
Ví dụ:
public class WhileLoop {
public static void main(String[] args) {
// In các số từ 1 đến 10
int i = 1;
System.out.print("Các số từ 1 đến 10: ");
while (i <= 10) {
System.out.print(i + " ");
i++;
}
System.out.println();
// Tính giai thừa của 5
int number = 5;
int factorial = 1;
int counter = 1;
while (counter <= number) {
factorial *= counter;
counter++;
}
System.out.println(number + "! = " + factorial);
}
}Ví dụ với điều kiện phức tạp:
import java.util.Scanner;
public class WhilePassword {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String correctPassword = "java123";
String userPassword;
int attempts = 3;
while (attempts > 0) {
System.out.print("Nhập mật khẩu (" + attempts + " lần còn lại): ");
userPassword = scanner.nextLine();
if (userPassword.equals(correctPassword)) {
System.out.println("Đăng nhập thành công!");
break;
} else {
attempts--;
if (attempts > 0) {
System.out.println("Mật khẩu sai. Vui lòng thử lại.");
}
}
}
if (attempts == 0) {
System.out.println("Tài khoản bị khóa!");
}
scanner.close();
}
}1.3. Vòng lặp do-while
Cú pháp:
do {
// Khối lệnh lặp
} while (điều_kiện);Đặc điểm: Thực thi ít nhất 1 lần rồi mới kiểm tra điều kiện
Ví dụ:
import java.util.Scanner;
public class DoWhileMenu {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int choice;
do {
System.out.println("\n=== MENU CHƯƠNG TRÌNH ===");
System.out.println("1. Tính tổng hai số");
System.out.println("2. Tính tích hai số");
System.out.println("3. Thoát chương trình");
System.out.print("Chọn chức năng (1-3): ");
choice = scanner.nextInt();
switch (choice) {
case 1:
System.out.print("Nhập số thứ nhất: ");
double a = scanner.nextDouble();
System.out.print("Nhập số thứ hai: ");
double b = scanner.nextDouble();
System.out.println("Tổng: " + (a + b));
break;
case 2:
System.out.print("Nhập số thứ nhất: ");
double x = scanner.nextDouble();
System.out.print("Nhập số thứ hai: ");
double y = scanner.nextDouble();
System.out.println("Tích: " + (x * y));
break;
case 3:
System.out.println("Cảm ơn bạn đã sử dụng!");
break;
default:
System.out.println("Lựa chọn không hợp lệ!");
}
} while (choice != 3);
scanner.close();
}
}Phần 2: Enhanced For Loop (For-Each)
2.1. Cú pháp cơ bản
Cú pháp:
for (Type variable : collection) {
// code sử dụng variable
}Đặc điểm:
- Tự động duyệt qua tất cả phần tử
- Không cần chỉ số hoặc iterator
- Không thể sửa đổi collection trong lúc duyệt
2.2. Duyệt mảng
public class ForEachArray {
public static void main(String[] args) {
// Duyệt mảng số nguyên
int[] numbers = {1, 2, 3, 4, 5};
System.out.print("Các số trong mảng: ");
for (int num : numbers) {
System.out.print(num + " ");
}
System.out.println();
// Tính tổng mảng
int sum = 0;
for (int num : numbers) {
sum += num;
}
System.out.println("Tổng: " + sum);
// Tìm số lớn nhất
int max = numbers[0];
for (int num : numbers) {
if (num > max) {
max = num;
}
}
System.out.println("Số lớn nhất: " + max);
}
}2.3. Duyệt Collection
import java.util.ArrayList;
import java.util.List;
public class ForEachCollection {
public static void main(String[] args) {
// Duyệt List
List<String> fruits = new ArrayList<>();
fruits.add("Táo");
fruits.add("Chuối");
fruits.add("Cam");
fruits.add("Xoài");
System.out.println("Danh sách trái cây:");
for (String fruit : fruits) {
System.out.println("- " + fruit);
}
// Duyệt và xử lý
List<Integer> scores = List.of(85, 92, 78, 95, 88);
int total = 0;
for (int score : scores) {
total += score;
}
double average = (double) total / scores.size();
System.out.println("Điểm trung bình: " + average);
}
}2.4. For-each với var (Java 10+)
import java.util.Map;
import java.util.HashMap;
public class ForEachVar {
public static void main(String[] args) {
// Sử dụng var với mảng
var colors = new String[] {"Đỏ", "Xanh", "Vàng"};
for (var color : colors) {
System.out.println("Màu: " + color);
}
// Sử dụng var với Map
Map<String, Integer> studentScores = new HashMap<>();
studentScores.put("An", 85);
studentScores.put("Bình", 92);
studentScores.put("Châu", 78);
for (var entry : studentScores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}Phần 3: Stream API và forEach (Java 8+)
3.1. Cú pháp cơ bản
collection.stream()
.forEach(element -> {
// Xử lý phần tử
});3.2. So sánh các cách duyệt
import java.util.List;
public class LoopComparison {
public static void main(String[] args) {
List<String> names = List.of("An", "Bình", "Châu", "Dũng");
System.out.println("1. For truyền thống:");
for (int i = 0; i < names.size(); i++) {
System.out.println("- " + names.get(i));
}
System.out.println("\n2. Enhanced for loop:");
for (String name : names) {
System.out.println("- " + name);
}
System.out.println("\n3. Stream API với forEach:");
names.stream().forEach(name -> System.out.println("- " + name));
System.out.println("\n4. Method reference:");
names.forEach(System.out::println);
}
}3.3. Stream với các phương thức khác
import java.util.List;
import java.util.stream.Collectors;
public class StreamOperations {
public static void main(String[] args) {
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
System.out.println("Danh sách gốc: " + numbers);
// Filter: Lọc số chẵn
System.out.print("Số chẵn: ");
numbers.stream()
.filter(n -> n % 2 == 0)
.forEach(n -> System.out.print(n + " "));
System.out.println();
// Map: Chuyển đổi
System.out.print("Bình phương: ");
numbers.stream()
.map(n -> n * n)
.forEach(n -> System.out.print(n + " "));
System.out.println();
// Sorted: Sắp xếp giảm dần
System.out.print("Sắp xếp giảm dần: ");
numbers.stream()
.sorted((a, b) -> b - a)
.forEach(n -> System.out.print(n + " "));
System.out.println();
// Limit và Skip
System.out.print("Phần tử từ 3 đến 7: ");
numbers.stream()
.skip(2)
.limit(5)
.forEach(n -> System.out.print(n + " "));
System.out.println();
// Collect để tạo List mới
List<Integer> evenSquares = numbers.stream()
.filter(n -> n % 2 == 0)
.map(n -> n * n)
.collect(Collectors.toList());
System.out.println("Bình phương số chẵn: " + evenSquares);
}
}3.4. Parallel Stream
import java.util.List;
import java.util.stream.IntStream;
public class ParallelStreamDemo {
public static void main(String[] args) {
// Tạo danh sách số lớn
List<Integer> bigList = IntStream.rangeClosed(1, 1000000)
.boxed()
.collect(java.util.stream.Collectors.toList());
long startTime, endTime;
// Xử lý tuần tự
startTime = System.currentTimeMillis();
long sequentialSum = bigList.stream()
.mapToLong(Integer::longValue)
.sum();
endTime = System.currentTimeMillis();
System.out.println("Tuần tự: " + sequentialSum + " - Thời gian: " + (endTime - startTime) + "ms");
// Xử lý song song
startTime = System.currentTimeMillis();
long parallelSum = bigList.parallelStream()
.mapToLong(Integer::longValue)
.sum();
endTime = System.currentTimeMillis();
System.out.println("Song song: " + parallelSum + " - Thời gian: " + (endTime - startTime) + "ms");
}
}Phần 4: Các Lệnh Điều Khiển Vòng Lặp
4.1. Lệnh break
Công dụng: Thoát khỏi vòng lặp ngay lập tức
Ví dụ:
public class BreakDemo {
public static void main(String[] args) {
// Tìm số đầu tiên chia hết cho 7 và 5
System.out.print("Số đầu tiên chia hết cho 7 và 5: ");
for (int i = 1; i <= 100; i++) {
if (i % 7 == 0 && i % 5 == 0) {
System.out.println(i);
break; // Thoát khi tìm thấy
}
}
// Break với nhãn (labeled break)
outerLoop:
for (int i = 1; i <= 3; i++) {
System.out.println("Vòng ngoài: " + i);
for (int j = 1; j <= 3; j++) {
System.out.println(" Vòng trong: " + j);
if (i == 2 && j == 2) {
break outerLoop; // Thoát cả hai vòng lặp
}
}
}
}
}4.2. Lệnh continue
Công dụng: Bỏ qua phần còn lại của vòng lặp hiện tại
Ví dụ:
public class ContinueDemo {
public static void main(String[] args) {
// In số lẻ từ 1 đến 10
System.out.print("Số lẻ từ 1 đến 10: ");
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // Bỏ qua số chẵn
}
System.out.print(i + " ");
}
System.out.println();
// Bỏ qua số chia hết cho 3
System.out.print("Số không chia hết cho 3: ");
for (int i = 1; i <= 20; i++) {
if (i % 3 == 0) {
continue;
}
System.out.print(i + " ");
}
System.out.println();
}
}4.3. Vòng lặp vô hạn và cách thoát
import java.util.Scanner;
public class InfiniteLoop {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Vòng lặp vô hạn có điều kiện dừng
while (true) {
System.out.print("Nhập số (0 để dừng): ");
int number = scanner.nextInt();
if (number == 0) {
System.out.println("Đã dừng chương trình.");
break;
}
System.out.println("Bạn nhập: " + number);
}
scanner.close();
}
}Kiến thức quan trọng cần nhớ:
- for: Khi biết số lần lặp chính xác
- while: Khi không biết số lần lặp, kiểm tra điều kiện trước
- do-while: Thực thi ít nhất 1 lần, kiểm tra điều kiện sau
- for-each: Ưu tiên khi duyệt collection
- Stream API: Cách tiếp cận hàm thức, code ngắn gọn, dễ đọc
- Vòng lặp lồng nhau: Độ phức tạp O(n²), cần cẩn thận với dữ liệu lớn
Bảng so sánh:
| Vòng lặp | Khi nào dùng | Ưu điểm | Nhược điểm |
|---|---|---|---|
| for | Biết số lần lặp | Kiểm soát tốt | Cú pháp dài |
| while | Không biết số lần lặp | Linh hoạt | Dễ vô hạn |
| do-while | Cần chạy ít nhất 1 lần | Đảm bảo chạy | Ít dùng |
| for-each | Duyệt collection | Đơn giản | Không có chỉ số |
| Stream | Xử lý dữ liệu phức tạp | Code ngắn | Khó debug |
Bài tập về nhà:
Bài 1: Game đoán số
Viết chương trình:
- Máy chọn ngẫu nhiên số từ 1-100
- Người chơi có 10 lần đoán
- Sau mỗi lần đoán, thông báo “lớn hơn” hoặc “nhỏ hơn”
- Tính điểm dựa trên số lần đoán
- Cho phép chơi lại
Bài 2: Quản lý điểm sinh viên
Viết chương trình:
- Nhập số lượng và điểm của n sinh viên
- Hiển thị danh sách điểm
- Tính điểm trung bình, cao nhất, thấp nhất
- Sắp xếp điểm tăng dần
- Sử dụng Stream API cho các tính toán
Bài 3: Xử lý văn bản
Viết chương trình:
- Đọc một đoạn văn bản
- Đếm số từ, số câu
- Tìm từ xuất sứ hiện nhiều nhất
- Đảo ngược văn bản
- Sử dụng parallelStream để xử lý văn bản lớn
Chuẩn bị cho Bài 6: Mảng (Arrays)
- Khai báo và khởi tạo mảng
- Mảng một chiều và đa chiều
- Các thuật toán cơ bản với mảng
- Arrays.sort, Arrays.copyOf
Lời khuyên: Thực hành nhiều với các loại vòng lặp khác nhau. Bắt đầu với cú pháp cơ bản, sau đó chuyển sang Stream API. Nhớ rằng Stream API không phải lúc nào cũng tốt hơn – đôi khi vòng lặp truyền thống vẫn là lựa chọn tốt nhất!
