Duyệt qua ArrayList
Đã giới thiệu| English | Ý nghĩa |
|---|---|
| ConcurrentModificationException/kənˈkʌrənt ˌmɒdɪfɪˈkeɪʃn ekˈsepʃn/ | ConcurrentModificationException |
Chọn một cách duyệt phù hợp với sự thay đổi mong muốn
- Một ArrayList chứa [2, 3, 4]. Bạn muốn nhân đôi mọi giá trị đã lưu trữ, trong khi giữ nguyên số lượng phần tử không đổi.
- Vòng lặp có chỉ số có thể dùng list.set(i, 2 * list.get(i)). Gán x = 2*x trong for (int x : list) chỉ thay đổi biến vòng lặp cục bộ.
Bắt đầu từ danh sách [2, 3, 4], chạy for (int x : list) { x = 2 * x; }. List.get(1) là gì?
Độ khó 2/5 · 140 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Gán biến cục bộ primitive x không thay thế Integer đã lưu trữ. Phần tử ở giữa của danh sách vẫn là 3.
Duyệt qua một danh sách
- Duyệt một ArrayList giống hệt như mảng, nhưng sử dụng các phương thức của nó. Có chỉ số:
for (int i = 0; i < list.size(); i++) { ... list.get(i) ... } - For-each:
for (String s : list) { ... s ... }— sạch sẽ khi đọc giá trị.size()(không phảilength) giới hạn cho vòng lặp có chỉ số.
Các quy trình giống nhau
- Tổng, đếm, min/max, và tìm kiếm đều hoạt động giống hệt như với mảng. Chỉ cần thay
a[i]bằnglist.get(i)vàa.lengthbằnglist.size(). - Bộ tích lũy và logic max/đếm là giống hệt nhau. Tất cả những gì bạn học được cho việc duyệt mảng đều áp dụng được.
Đọc so với sửa đổi
- Một vòng lặp nâng cao sao chép giá trị của mỗi phần tử vào biến vòng lặp của nó. Đối với
Integerphần tử được đọc nhưint x, việc gán choxkhông thay thế một phần tử trong danh sách; một vòng lặp có chỉ số có thể thay thế nó bằngset(i, x). - Đối với các thay đổi cấu trúc (thêm/xóa), hãy sử dụng vòng lặp có chỉ số một cách cẩn thận. Việc đọc là đơn giản; xóa trong khi đang duyệt đòi hỏi sự cẩn thận đặc biệt (bài học sau).
Tính tổng một ArrayList theo chỉ số
Giới hạn bằng size(), đọc bằng get(i) (list = [10,20,30]).
Điều kiện đúng cho vòng lặp có chỉ số của ArrayList là...
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
ArrayList sử dụng size(); mảng sử dụng length.
Why should a program avoid direct structural changes during an ArrayList enhanced-for traversal?
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
ArrayList fail-fast behaviour is best-effort. Avoid unsafe traversal rather than relying on a guaranteed exception.
Các mẫu duyệt mảng (tổng, đếm, max) hoạt động tương tự đối với ArrayList.
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Chỉ cần thay a[i]/a.length bằng list.get(i)/list.size().
Để xóa phần tử an toàn trong khi duyệt qua danh sách, bạn nên sử dụng...
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
for-each không thể thay đổi cấu trúc; vòng lặp có chỉ số có thể (cẩn thận).
Không có sự thay đổi cấu trúc trong khi duyệt, một vòng lặp nâng cao có thể đọc tất cả các mục của một ArrayList
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Vòng lặp đọc từng tham chiếu đã lưu trữ. Sự thay đổi cấu trúc trong khi duyệt là một vấn đề riêng; tuyên bố này không đảm bảo rằng tất cả các thao tác trên mỗi phần tử có thể đều an toàn.
Đừng sửa đổi trong lúc for-each
- Thêm hoặc xóa trong một vòng lặp for-each có thể gây ra ConcurrentModificationException; phát hiện fail-fast chỉ mang tính cố gắng tốt nhất. Vòng lặp for-each giả định rằng danh sách không thay đổi cấu trúc bên dưới nó.
- Để xóa trong khi duyệt, hãy sử dụng vòng lặp có chỉ số (và quản lý chỉ số). Đọc dữ liệu với for-each phù hợp khi danh sách không bị thay đổi cấu trúc trong quá trình duyệt. Ngoài ra, hãy kiểm tra yêu cầu về phần tử: unboxing một Integer null vẫn sẽ ném ngoại lệ.
Giới hạn vòng lặp ArrayList có chỉ mục bằng list.size(), không phải .length, và tuyệt đối không thay đổi cấu trúc trong vòng for-each. Việc gọi add/remove bên trong một for (x : list) có thể kích hoạt ConcurrentModificationException, nhưng khả năng phát hiện không được đảm bảo. Để xóa phần tử khi duyệt qua, hãy sử dụng vòng lặp có chỉ mục — và nhớ rằng remove(i) sẽ dịch chuyển các phần tử sau, vì vậy đừng vô tình i++ vượt qua phần tử đã bị dịch chuyển.
After the indexed doubling update, what is list.get(1)?
Độ khó 2/5 · 140 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
The middle stored value 3 is replaced by 6. Reassigning a primitive loop variable would leave it at 3.
Đối với các mục Student không null, s.addScore(5) bên trong for (Student s : students) có thể thay đổi sinh viên đã lưu trữ mà không thêm hoặc xóa phần tử khỏi danh sách.
Độ khó 1/5 · 100 xu + một phần thưởng nhỏ cho lần hoàn thành đầu tiên trong ngày
Các tham chiếu được sao chép trỏ đến các đối tượng Student có thể thay đổi. Các trường của chúng có thể thay đổi mà không làm thay đổi cấu trúc danh sách.
Tính tổng mộtArrayList
- Có chỉ mục:
for (int i = 0; i < list.size(); i++) { sum += list.get(i); } - For-each:
for (int x : list) { sum += x; }(tự động đóng gói/giải mã tự động xử lý Integer↔int). - Cả hai đều tính tổng danh sách; for-each gọn gàng hơn cho việc đọc chỉ.
Mở rộng suy luận sang trường hợp mới
- Thêm hoặc xóa trực tiếp trong quá trình duyệt nâng cao là không an toàn; các ngoại lệ fail-fast chỉ mang tính nỗ lực tốt nhất, chứ không phải là phép kiểm tra độ chính xác được đảm bảo.
- Một danh sách chứa các đối tượng Student có thể thay đổi trạng thái có thể được duyệt với
for (Student s : students) { s.addScore(5); }, với giả định rằng các phần tử đều khác null. Điều này sẽ thay đổi trạng thái của mỗi đối tượng mà không làm thay đổi cấu trúc của danh sách; việc gán một tham chiếu khác chossẽ không thay thế phần tử đang được lưu trữ.
Duyệt một ArrayList bằng vòng lặp có chỉ mục (i < list.size(), list.get(i)) hoặc vòng lặp nâng cao nhận giá trị từng phần tử. Các mẫu xử lý mảng (tổng, đếm, tìm min/max, tìm kiếm) đều áp dụng được. Tránh thay đổi cấu trúc trực tiếp trong khi duyệt nâng cao: một ConcurrentModificationException có thể phát hiện lỗi, nhưng không được đảm bảo. Hãy sử dụng vòng lặp có chỉ mục được quản lý cẩn thận cho mẫu xóa được dạy ở phần tiếp theo; việc thay đổi các trường của đối tượng được tham chiếu khác với việc thay đổi cấu trúc của danh sách.