Mục lục bài họcĐang ở d04-b1
One-Dimensional Arrays and Traversals
Fixed length, zero-based indexing
An array holds a fixed number of values of the same type. The length is decided when the array is created and can never change: int[] a = new int[6]; creates six slots, and a.length is 6 forever. Note that length is a field, not a method — there are no parentheses, unlike String.length().
Valid indices run from 0 to a.length − 1. Touching any other index throws an ArrayIndexOutOfBoundsException at run time — the compiler will not catch it.
New arrays are filled with default values: 0 for int, 0.0 for double, false for boolean, and null for object types such as String.
Two ways to traverse
for (int i = 0; i < a.length; i++) { // indexed loop
a[i] = a[i] * 2; // CAN modify
}
for (int x : a) { // enhanced for (for-each)
System.out.println(x); // read only
}The enhanced for loop copies each element into the loop variable. Assigning to that variable changes the copy, never the array. Use the indexed loop whenever you must write into the array, compare neighbouring elements, or know where you are.
Mảng có độ dài cố định. Tạo xong là khoá luôn: int[] a = new int[6]; thì a.length bằng 6 vĩnh viễn, không thêm không bớt được. Chú ý length của mảng là một trường, viết không có ngoặc — khác hẳn length() của String. Viết lẫn hai cái là lỗi biên dịch, và đề thi cố tình trộn cả mảng lẫn chuỗi trong một đoạn để bắt chỗ đó.
Chỉ số chạy từ 0 đến a.length − 1. Chạm ra ngoài là ném ArrayIndexOutOfBoundsException lúc chạy, trình biên dịch không hề báo trước. Mảng mới tạo được điền giá trị mặc định: 0 cho int, 0.0 cho double, false cho boolean, và null cho kiểu đối tượng như String — nên duyệt một mảng String chưa gán mà gọi .length() là NullPointerException.
Hai kiểu duyệt, chọn đúng kiểu. Vòng lặp có chỉ số cho phép ghi vào mảng, so sánh phần tử kề nhau, và biết mình đang ở đâu. Vòng for-each thì chép giá trị từng phần tử vào biến lặp: gán cho biến đó chỉ sửa bản chép, mảng gốc không suy suyển. Quy tắc chọn nhanh: cần đọc thì for-each, cần ghi hoặc cần chỉ số thì vòng lặp có chỉ số.
i < a.length; đổi thành i <= a.length là vòng lặp chạy thêm đúng một nhịp vào ô không tồn tại. Đó là lỗi lệch một đơn vị (off-by-one), và nó không sai ở mọi lần chạy mà chỉ sai ở nhịp cuối, nên kiểm thử sơ sài rất dễ bỏ qua.Viết đoạn mã đếm số lần một phần tử của mảng int[] a lớn hơn phần tử ngay sau nó, rồi giải thích vì sao không dùng được for-each.
int dem = 0;
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i + 1]) {
dem++;
}
}Vì sao là a.length - 1. Thân vòng lặp chạm tới a[i + 1], nên chỉ số lớn nhất mà i được phép nhận là a.length - 2. Nguyên tắc chung: chỉ số lớn nhất bị chạm trong thân vòng lặp quyết định điều kiện dừng, không phải chỉ số của biến lặp.
Vì sao không dùng for-each. Vòng for-each chỉ đưa cho ta giá trị của phần tử hiện tại, không đưa vị trí, nên không có cách nào hỏi “phần tử ngay sau nó là gì”. Mọi bài toán nhìn hai phần tử cùng lúc đều bắt buộc dùng chỉ số.
Với a = {3, 8, 1, 6, 2} đoạn mã trả về 2, ứng với hai cặp (8, 1) và (6, 2).
i <= a.length. Cách chặn — trước khi viết điều kiện dừng, đọc thân vòng lặp và hỏi “chỉ số lớn nhất bị chạm là bao nhiêu”; chạm a[i + 1] thì dừng ở a.length - 1, chạm a[i] thì dừng ở a.length. Hai: dùng for-each rồi gán vào biến lặp và tưởng mảng đổi theo. Cách chặn — đặt luật cho mình: hễ trong thân vòng lặp có dấu = ghi vào phần tử, lập tức đổi sang vòng lặp có chỉ số.length - 1, length không có ngoặc. Cần ghi hoặc cần biết vị trí thì dùng chỉ số; chỉ đọc thì for-each gọn hơn và không hỏng được.Đọc xong rồi — làm thử ngay
Bài tập của chương Unit 4 — Data Collections gồm 14 câu trắc nghiệm và 8 đề tự luận. Đáp án hiện ngay khi chọn, miễn phí.