Danh sách tự thay đổi kích thước
Mảng (array) thường trong Java có độ dài cố định: chọn mười ô thì bạn có mười ô mãi mãi. ArrayList là lựa chọn co giãn được trong java.util: nó lớn lên khi bạn thêm và thu nhỏ khi bạn xóa, và có sẵn những phương thức tiện lợi cho những việc bạn thực sự làm với một danh sách.
Để ý kiểu trong dấu ngoặc nhọn, List<String>, cho trình biên dịch biết danh sách này chứa giá trị String. Dấu <> (gọi là "diamond") ở bên phải giúp Java tự suy ra cùng kiểu đó mà không cần viết lại. Và để ý rằng bạn phải import java.util.ArrayList; nó không có sẵn mặc định.
Khai báo là List, khởi tạo là ArrayList
Bạn gần như luôn thấy biến được khai báo theo interface List thay vì lớp cụ thể ArrayList:
List<String> names = new ArrayList<>();
Đây là thói quen tốt, không phải quy tắc bắt buộc. Viết code theo interface List nghĩa là phần còn lại của code không quan tâm bạn dùng cách cài đặt danh sách nào, nên sau này bạn có thể đổi sang loại khác mà không phải sửa gì. Với việc dùng hằng ngày, hai cách hoạt động như nhau.
Thêm, lấy và gán phần tử
add(value)thêm vào cuối danh sách.add(index, value)chèn vào một vị trí, đẩy các phần tử phía sau lùi lại.get(index)đọc phần tử tại một vị trí (đánh số từ 0).set(index, value)ghi đè một phần tử đã có.
Chỉ số bắt đầu từ 0, và gọi get với chỉ số nằm ngoài phạm vi sẽ ném ra IndexOutOfBoundsException.
Xóa phần tử
Có một cái bẫy kinh điển khi danh sách chứa Integer. remove(int) là "xóa theo chỉ số" còn remove(Object) là "xóa theo giá trị", nên:
List<Integer> nums = new ArrayList<>(List.of(10, 20, 30));
nums.remove(1); // removes index 1 -> the value 20
nums.remove(Integer.valueOf(20)); // removes the value 20
Bọc giá trị trong Integer.valueOf(...) khi bạn muốn "xóa giá trị này", chứ không phải "xóa chỉ số này".
size, contains và tìm chỉ số
List.of(...) tạo nhanh một danh sách bất biến; truyền nó vào hàm khởi tạo của ArrayList sẽ cho bạn một bản sao có thể thay đổi, chứa sẵn các giá trị đó.
Duyệt ArrayList
Cách duyệt gọn nhất là vòng lặp for nâng cao (vòng lặp for-each):
Khi cần cả chỉ số, hãy dùng vòng lặp đếm với size() và get(i):
Một quy tắc: đừng thêm hay xóa phần tử khỏi danh sách trong khi vòng lặp for-each đang duyệt nó, vì việc đó ném ra ConcurrentModificationException. Để xóa an toàn các phần tử thỏa điều kiện, hãy dùng removeIf:
Sắp xếp
Collections.sort sắp xếp danh sách tại chỗ theo thứ tự tự nhiên (theo bảng chữ cái với chuỗi, theo giá trị với số):
Với thứ tự tùy chỉnh, hãy truyền một Comparator vào list.sort(...), ví dụ names.sort(Comparator.comparingInt(String::length)) để sắp xếp theo độ dài.
ArrayList chứa đối tượng, không chứa kiểu nguyên thủy
Bạn không thể viết ArrayList<int>. Generics chỉ làm việc với kiểu đối tượng, nên hãy dùng lớp bao Integer, Double, Boolean và các lớp tương tự:
Cơ chế autoboxing của Java tự chuyển đổi giữa int và Integer cho bạn, nên code đọc rất tự nhiên; chỉ cần nhớ rằng bản thân danh sách lưu các đối tượng Integer.
Tiếp theo: HashMap
ArrayList là công cụ phù hợp khi bạn quan tâm đến thứ tự và vị trí. Khi cần tra cứu theo khóa, như tên người dùng ra người dùng hay mã sản phẩm ra giá, bạn cần HashMap, nội dung của trang tiếp theo.
Câu hỏi thường gặp
Làm sao tạo ArrayList trong Java?
Khai báo với kiểu phần tử trong dấu ngoặc nhọn và gọi hàm khởi tạo: ArrayList<String> names = new ArrayList<>();. Dấu <> ở bên phải (gọi là diamond) giúp Java tự suy ra kiểu. Thường thì bạn khai báo biến theo interface List: List<String> names = new ArrayList<>();.
Mảng và ArrayList trong Java khác nhau thế nào?
Mảng thường có độ dài cố định được đặt khi tạo và có thể chứa kiểu nguyên thủy như int. ArrayList tự lớn lên và thu nhỏ khi bạn thêm và xóa phần tử, chỉ chứa đối tượng (nên int trở thành Integer), và đi kèm các phương thức như add, remove, contains và size. Dùng mảng cho dữ liệu kiểu nguyên thủy có kích thước cố định; dùng ArrayList khi kích thước thay đổi.
Làm sao xóa một phần tử khỏi ArrayList?
Gọi remove(index) để xóa theo vị trí, hoặc remove(object) để xóa phần tử khớp đầu tiên. Cẩn thận với danh sách Integer: list.remove(2) xóa chỉ số 2, còn list.remove(Integer.valueOf(2)) xóa giá trị 2. Để xóa trong khi đang duyệt, hãy dùng remove() của Iterator hoặc removeIf(...) để tránh ConcurrentModificationException.