🔄 Mảng Động - ArrayList
Chào mừng đến với bài học về ArrayList - mảng linh hoạt tự động thay đổi kích thước trong Café!
🎯 Món Ăn Hôm Nay
Tưởng tượng bạn đang quản lý danh sách đặt hàng:
- Thêm/xóa khách linh hoạt → Không cần biết trước số lượng
- Tự động mở rộng → Không lo overflow
- Dễ thao tác → Nhiều method tiện lợi
Đó chính là ArrayList - mảng thông minh!
🔄 ArrayList Là Gì?
ArrayList = Mảng động (tự động thay đổi kích thước)
import java.util.ArrayList;
// Array thường: Cố định
String[] menu = new String[3]; // Chỉ 3 phần tử
// ArrayList: Linh hoạt
ArrayList<String> menuDong = new ArrayList<>();
menuDong.add("Latte"); // Tự động thêm
menuDong.add("Mocha"); // Không giới hạn!
menuDong.add("Espresso");
☕ Ẩn Dụ Café:
- Array = Khay cố định (10 ly)
- ArrayList = Giá kệ mở rộng (thêm ly thoải mái)
- add() = Thêm ly mới
- remove() = Lấy ly ra
- size() = Đếm số ly hiện tại
📊 So Sánh Array vs ArrayList
| Đặc điểm | Array | ArrayList |
|---|---|---|
| Kích thước | Cố định | Tự động |
| Kiểu dữ liệu | Primitive & Object | Chỉ Object |
| Thêm/xóa | Khó | Dễ (method) |
| Hiệu năng | Nhanh hơn | Chậm hơn |
| Cú pháp | arr[i] | list.get(i) |
👨🍳 Câu Chuyện Trong Quán
Tình huống 1: Quản Lý Danh Sách Chờ
import java.util.ArrayList;
public class DanhSachCho {
public static void main(String[] args) {
ArrayList<String> danhSachCho = new ArrayList<>();
// Thêm khách vào hàng chờ
danhSachCho.add("Anh Minh");
danhSachCho.add("Chị Lan");
danhSachCho.add("Anh Tùng");
System.out.println("👥 DANH SÁCH CHỜ:\n");
for (int i = 0; i < danhSachCho.size(); i++) {
System.out.println((i + 1) + ". " + danhSachCho.get(i));
}
// Phục vụ khách đầu tiên
System.out.println("\n✅ Đang phục vụ: " + danhSachCho.remove(0));
System.out.println("\n👥 CÒN LẠI:");
for (String khach : danhSachCho) {
System.out.println("- " + khach);
}
}
}
Output:
👥 DANH SÁCH CHỜ:
1. Anh Minh
2. Chị Lan
3. Anh Tùng
✅ Đang phục vụ: Anh Minh
👥 CÒN LẠI:
- Chị Lan
- Anh Tùng
Tình huống 2: Menu Linh Hoạt
import java.util.ArrayList;
public class MenuLinhHoat {
public static void main(String[] args) {
ArrayList<String> menu = new ArrayList<>();
// Thêm món
menu.add("Espresso");
menu.add("Latte");
menu.add("Mocha");
System.out.println("☕ MENU BAN ĐẦU:");
System.out.println(menu);
System.out.println("Số món: " + menu.size());
// Thêm món mới
menu.add("Cappuccino");
menu.add("Americano");
System.out.println("\n☕ SAU KHI THÊM:");
System.out.println(menu);
System.out.println("Số món: " + menu.size());
// Xóa món
menu.remove("Mocha");
System.out.println("\n☕ SAU KHI XÓA MOCHA:");
System.out.println(menu);
}
}
Output:
☕ MENU BAN ĐẦU:
[Espresso, Latte, Mocha]
Số món: 3
☕ SAU KHI THÊM:
[Espresso, Latte, Mocha, Cappuccino, Americano]
Số món: 5
☕ SAU KHI XÓA MOCHA:
[Espresso, Latte, Cappuccino, Americano]
📝 Công Thức Nấu (Code Examples)
Ví Dụ 1: Các Method Cơ Bản
import java.util.ArrayList;
public class MethodCoBan {
public static void main(String[] args) {
ArrayList<String> menu = new ArrayList<>();
// add() - Thêm phần tử
menu.add("Latte");
menu.add("Mocha");
System.out.println("Sau add: " + menu);
// add(index, element) - Thêm tại vị trí
menu.add(1, "Espresso"); // Chèn vào giữa
System.out.println("Sau add(1, ...): " + menu);
// get(index) - Lấy phần tử
String mon = menu.get(0);
System.out.println("\nget(0): " + mon);
// set(index, element) - Thay thế
menu.set(2, "Cappuccino");
System.out.println("Sau set(2, ...): " + menu);
// remove(index) - Xóa theo index
menu.remove(1);
System.out.println("Sau remove(1): " + menu);
// remove(object) - Xóa theo giá trị
menu.remove("Mocha");
System.out.println("Sau remove('Mocha'): " + menu);
// size() - Kích thước
System.out.println("\nKích thước: " + menu.size());
// contains() - Kiểm tra tồn tại
System.out.println("Có Latte? " + menu.contains("Latte"));
// clear() - Xóa tất cả
menu.clear();
System.out.println("Sau clear: " + menu);
System.out.println("isEmpty: " + menu.isEmpty());
}
}
Ví Dụ 2: ArrayList Với Integer
import java.util.ArrayList;
public class ArrayListInteger {
public static void main(String[] args) {
ArrayList<Integer> gia = new ArrayList<>();
// Thêm giá
gia.add(45000);
gia.add(50000);
gia.add(55000);
gia.add(60000);
System.out.println("💰 BẢNG GIÁ:\n");
// Tính tổng
int tong = 0;
for (int g : gia) {
System.out.printf("%,d VND%n", g);
tong += g;
}
System.out.printf("%nTổng: %,d VND%n", tong);
// Tìm giá cao nhất
int max = gia.get(0);
for (int g : gia) {
if (g > max) {
max = g;
}
}
System.out.printf("Giá cao nhất: %,d VND%n", max);
}
}
Ví Dụ 3: Tìm Kiếm Và Xóa
import java.util.ArrayList;
public class TimKiemXoa {
public static void main(String[] args) {
ArrayList<String> danhSach = new ArrayList<>();
danhSach.add("Latte");
danhSach.add("Mocha");
danhSach.add("Espresso");
danhSach.add("Latte"); // Trùng
danhSach.add("Cappuccino");
System.out.println("📋 DANH SÁCH:");
System.out.println(danhSach);
// indexOf() - Vị trí đầu tiên
int viTri = danhSach.indexOf("Latte");
System.out.println("\nVị trí Latte đầu tiên: " + viTri);
// lastIndexOf() - Vị trí cuối cùng
int viTriCuoi = danhSach.lastIndexOf("Latte");
System.out.println("Vị trí Latte cuối: " + viTriCuoi);
// Xóa tất cả "Latte"
while (danhSach.contains("Latte")) {
danhSach.remove("Latte");
}
System.out.println("\nSau khi xóa tất cả Latte:");
System.out.println(danhSach);
}
}
Ví Dụ 4: Sắp Xếp ArrayList
import java.util.ArrayList;
import java.util.Collections;
public class SapXep {
public static void main(String[] args) {
ArrayList<Integer> gia = new ArrayList<>();
gia.add(60000);
gia.add(45000);
gia.add(55000);
gia.add(50000);
System.out.println("💰 TRƯỚC KHI SẮP XẾP:");
System.out.println(gia);
// Sắp xếp tăng dần
Collections.sort(gia);
System.out.println("\n📈 TĂNG DẦN:");
System.out.println(gia);
// Sắp xếp giảm dần
Collections.sort(gia, Collections.reverseOrder());
System.out.println("\n📉 GIẢM DẦN:");
System.out.println(gia);
// Sắp xếp String
ArrayList<String> ten = new ArrayList<>();
ten.add("Mocha");
ten.add("Espresso");
ten.add("Latte");
Collections.sort(ten);
System.out.println("\n🔤 A-Z:");
System.out.println(ten);
}
}
Ví Dụ 5: ArrayList 2D (Nested)
import java.util.ArrayList;
public class ArrayList2D {
public static void main(String[] args) {
// ArrayList của ArrayList
ArrayList<ArrayList<String>> menuTheoNgay = new ArrayList<>();
// Ngày 1
ArrayList<String> ngay1 = new ArrayList<>();
ngay1.add("Espresso");
ngay1.add("Latte");
menuTheoNgay.add(ngay1);
// Ngày 2
ArrayList<String> ngay2 = new ArrayList<>();
ngay2.add("Mocha");
ngay2.add("Cappuccino");
ngay2.add("Americano");
menuTheoNgay.add(ngay2);
// Ngày 3
ArrayList<String> ngay3 = new ArrayList<>();
ngay3.add("Latte");
menuTheoNgay.add(ngay3);
System.out.println("📅 MENU THEO NGÀY:\n");
for (int i = 0; i < menuTheoNgay.size(); i++) {
System.out.println("Ngày " + (i + 1) + ":");
for (String mon : menuTheoNgay.get(i)) {
System.out.println(" - " + mon);
}
System.out.println();
}
}
}
Ví Dụ 6: Clone Và Copy
import java.util.ArrayList;
public class CloneCopy {
public static void main(String[] args) {
ArrayList<String> goc = new ArrayList<>();
goc.add("Latte");
goc.add("Mocha");
// ❌ SAI: Gán tham chiếu
ArrayList<String> list1 = goc;
list1.add("Espresso"); // Thêm vào cả goc!
// ✅ ĐÚNG: Clone
ArrayList<String> list2 = (ArrayList<String>) goc.clone();
list2.add("Cappuccino"); // Không ảnh hưởng goc
// ✅ ĐÚNG: Constructor copy
ArrayList<String> list3 = new ArrayList<>(goc);
list3.add("Americano");
System.out.println("Gốc: " + goc);
System.out.println("List1 (tham chiếu): " + list1);
System.out.println("List2 (clone): " + list2);
System.out.println("List3 (copy): " + list3);
}
}
🔥 Thực Hành Trong Quán
Bài Tập 1: Giỏ Hàng
import java.util.ArrayList;
public class GioHang {
public static void main(String[] args) {
ArrayList<String> gioHang = new ArrayList<>();
ArrayList<Integer> soLuong = new ArrayList<>();
// Thêm món
gioHang.add("Latte");
soLuong.add(2);
gioHang.add("Mocha");
soLuong.add(1);
gioHang.add("Espresso");
soLuong.add(3);
System.out.println("🛒 GIỎ HÀNG:\n");
int tongSoLuong = 0;
for (int i = 0; i < gioHang.size(); i++) {
System.out.printf("%d. %s × %d%n",
(i + 1), gioHang.get(i), soLuong.get(i));
tongSoLuong += soLuong.get(i);
}
System.out.println("\n━━━━━━━━━━━━━━━");
System.out.println("Tổng: " + tongSoLuong + " ly");
}
}
Bài Tập 2: Lọc Món Theo Giá
import java.util.ArrayList;
public class LocTheoGia {
public static void main(String[] args) {
ArrayList<String> tenMon = new ArrayList<>();
ArrayList<Integer> gia = new ArrayList<>();
tenMon.add("Espresso"); gia.add(45000);
tenMon.add("Latte"); gia.add(50000);
tenMon.add("Mocha"); gia.add(60000);
tenMon.add("Cappuccino"); gia.add(55000);
int giaMax = 52000;
System.out.println("🔍 MÓN DƯỚI " + giaMax + " VND:\n");
ArrayList<String> ketQua = new ArrayList<>();
for (int i = 0; i < gia.size(); i++) {
if (gia.get(i) <= giaMax) {
ketQua.add(tenMon.get(i));
System.out.printf("%s: %,d VND%n",
tenMon.get(i), gia.get(i));
}
}
System.out.println("\nTìm thấy: " + ketQua.size() + " món");
}
}
Bài Tập 3: Xóa Món Hết Hàng
import java.util.ArrayList;
public class XoaHetHang {
public static void main(String[] args) {
ArrayList<String> menu = new ArrayList<>();
ArrayList<Integer> soLuong = new ArrayList<>();
menu.add("Espresso"); soLuong.add(10);
menu.add("Latte"); soLuong.add(0); // Hết
menu.add("Mocha"); soLuong.add(5);
menu.add("Cappuccino"); soLuong.add(0); // Hết
System.out.println("📋 MENU TRƯỚC:");
for (int i = 0; i < menu.size(); i++) {
System.out.printf("%s (%d ly)%n", menu.get(i), soLuong.get(i));
}
// Xóa món hết hàng (duyệt ngược)
for (int i = menu.size() - 1; i >= 0; i--) {
if (soLuong.get(i) == 0) {
System.out.println("\n❌ Xóa: " + menu.get(i));
menu.remove(i);
soLuong.remove(i);
}
}
System.out.println("\n📋 MENU SAU:");
for (int i = 0; i < menu.size(); i++) {
System.out.printf("%s (%d ly)%n", menu.get(i), soLuong.get(i));
}
}
}
⚠️ Lỗi Thường Gặp
Lỗi 1: Dùng Primitive Type
// ❌ SAI: Không dùng được int, double, boolean
ArrayList<int> gia = new ArrayList<>(); // ❌ Lỗi!
// ✅ ĐÚNG: Dùng wrapper class
ArrayList<Integer> gia = new ArrayList<>(); // ✅ OK
ArrayList<Double> gia2 = new ArrayList<>();
ArrayList<Boolean> check = new ArrayList<>();
Lỗi 2: IndexOutOfBoundsException
ArrayList<String> list = new ArrayList<>();
list.add("Latte");
String mon = list.get(5); // ❌ Lỗi! Chỉ có 1 phần tử
// ✅ ĐÚNG: Kiểm tra size
if (5 < list.size()) {
String mon = list.get(5);
}
Lỗi 3: ConcurrentModificationException
// ❌ SAI: Sửa ArrayList trong for-each
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
for (String item : list) {
list.remove(item); // ❌ Lỗi!
}
// ✅ ĐÚNG: Dùng iterator hoặc duyệt ngược
for (int i = list.size() - 1; i >= 0; i--) {
list.remove(i); // ✅ OK
}
Lỗi 4: Nhầm Array Với ArrayList
// Array
String[] arr = {"A", "B"};
arr[0] = "C"; // OK
// ArrayList
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list[0] = "C"; // ❌ Lỗi! Phải dùng set()
list.set(0, "C"); // ✅ OK
💡 Bí Quyết Của Barista
- Dùng wrapper class: Integer, Double, Boolean (không phải int, double, boolean)
- add() để thêm: Không dùng
list[i] = value - get() để lấy: Không dùng
list[i] - size() không phải length:
list.size()chứ không phảilist.length - Duyệt ngược khi xóa: Tránh ConcurrentModificationException
- Clone đúng cách: Dùng
clone()hoặc constructor
🎓 Bạn Đã Học Được
- ✅ ArrayList = Mảng động tự thay đổi kích thước
- ✅ Import:
import java.util.ArrayList; - ✅ Khai báo:
ArrayList<Type> name = new ArrayList<>(); - ✅ Methods:
add(),get(),set(),remove(),size() - ✅ Dùng wrapper class cho primitive
- ✅ Linh hoạt hơn Array thường
- ✅ Sắp xếp với
Collections.sort()
☕ Món Tiếp Theo
Đã biết ArrayList! Giờ học về định nghĩa method:
👉 Định Nghĩa Method - Defining Methods
💡 Lời Khuyên Cuối: ArrayList như giá kệ mở rộng trong quán - linh hoạt thêm/bớt theo nhu cầu thực tế!