Chuyển tới nội dung chính

🔄 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ểmArrayArrayList
Kích thướcCố địnhTự động
Kiểu dữ liệuPrimitive & ObjectChỉ Object
Thêm/xóaKhóDễ (method)
Hiệu năngNhanh hơnChậm hơn
Cú pháparr[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

  1. Dùng wrapper class: Integer, Double, Boolean (không phải int, double, boolean)
  2. add() để thêm: Không dùng list[i] = value
  3. get() để lấy: Không dùng list[i]
  4. size() không phải length: list.size() chứ không phải list.length
  5. Duyệt ngược khi xóa: Tránh ConcurrentModificationException
  6. 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ế!