Mảng (Array)
Khái niệm.
Một mảng bao gồm các đối tượng có số lương cố định các giá
trị của cùng một kiểu. Độ dài của một mảng được thành lập khi nó được tạo ra.
Sau khi được tạo ra, độ dài đó là cố định. Ví dụ về mảng đã nói đến là trong
hàm main của ứng dụng “Hello World”. Trong phần này sẽ thảo luận chi tiết hơn về
mảng.
Mỗi thành viên của mảng được gọi là một phần tử và mỗi phần
tử được truy cập thông qua chỉ số mảng (index). Trong minh họa ở
trên chỉ số bắt đầu từ 0. Phần tử có thứ tự thứ 9 có chỉ mảng là 8.
Trong ví dụ ArrayDemo dưới đây, tạo ra mảng các số nguyên, đặt
một vài giá trị vào trong mảng, và in mỗi giá trị đó theo hàm xuất chuẩn.
Kết quả khi chạy chương trình như sau:
Element at index 0: 100
Element at index 1: 200
Element at index 2: 300
Element at index 3: 400
Element at index 4: 500
Element at index 5: 600
Element at index 6: 700
Element at index 7: 800
Element at index 8: 900
Element at index 9: 1000
Trong các tình huống lập trình thực tế, bạn cần sử dụng mảng
với các cấu trúc lặp để duyệt các phần tử mảng. Ở đây, mỗi phần tử mảng thường
được viết xử lý trên một dòng riêng như trong ví dụ. Tuy nhiên ví dụ này minh họa
cú pháp truy cập phần tử một cách rõ ràng. Bạn sẽ được học về các cấu trúc lặp
(for, while và do-while) trong phần cấu trúc điều khiển trong phần sau này.
Cú pháp khai báo mảng.
Trong chương trình có khai báo mảng trong mục trên (tên mảng là anArray) chúng ta thấy dòng code sau:
//Khai báo một mảng số nguyên
int[] anArray;
Giống như định nghĩa các của các kiểu biến khác, một biến mảng
được định nghĩa bao gồm hai thành phần: Kiểu mảng và tên của mảng. Kiểu mảng được
viết như type[], tại chữ type là kiểu dữ liệu của các phần tử chứa
trong mảng; dấu ngoặc vuông là ký tự đặc biệt xác định đây là biến mảng. Kích
thước mảng không được khai báo trong kiểu mảng (đó là lý do tại sao trong dấu
ngoặc vuông lại là trống rỗng). Tên của mảng có thể là bất kỳ thứ gì mà bạn muốn,
được tuân theo quy tắc đặt tên mà đã được bàn trong phần định danh ở mục trước.
Cũng giống như các kiểu biến khác, việc khai báo không thực sự tạo ra một mảng;
nó chỉ đơn giản là thông báo cho trình biên dịch biết biến này là biến mảng và
có kiểu dữ liệu đi kèm.
Tương tự bạn có thể dịnh nghĩa các mảng với các kiểu dữ liệu
khác như sau:
byte[] anArrayOfBytes;
short[] anArrayOfShorts;
long[] anArrayOfLongs;
float[] anArrayOfFloats;
double[] anArrayOfDoubles;
boolean[] anArrayOfBooleans;
char[] anArrayOfChars;
String[] anArrayOfStrings;
Bạn có thể thấy rằng các dấu ngoặc vuông được đặt phía trước
các tên mảng.
// Hình thức khai báo này không được khuyến khích.
float anArrayOfFloats[];
Tuy nhiên quy ước không được khuyến khích đó, dấu ngoặc
vuông xác định đây là kiểu mảng, xuất hiện với kiểu chỉ định.
Cách tạo mảng, khởi tạo mảng và truy cập một
vào một mảng.
Một cách tạo ra một mảng là dùng toán tử new. Ví dụ
dưới đây, lấy từ chương trình ArrayDemo, xác định một mảng với 10 phần tử
số nguyên nằm trong một biến mảng.
// Tạo một mảng có các phần tử số nguyên
anArray = new int[10];
Với câu lệnh này là thiếu khi dùng mảng, chương trình sẽ in
ra dòng thông báo lỗi như sau khi biên dịch
Ý chỉ rằng biến mảng này chưa được khởi tạo. Chúng ta thêm
vài dòng code gán các giá trị vào từng phần tử mảng như sau:
anArray[0] = 100; // initialize first element
anArray[1] = 200; // initialize second element
anArray[2] = 300; // and so forth
Mỗi phần tử mảng được truy cập thông qua chỉ số mảng:
System.out.println("Element 1 at index 0: " + anArray[0]);
System.out.println("Element 2 at index 1: " + anArray[1]);
System.out.println("Element 3 at index 2: " + anArray[2]);
Ngoài ra, bạn có thể sử dụng cú pháp tắt để tạo và khởi tạo
mảng:
int[] anArray = {
100, 200, 300,
400, 500, 600,
700, 800, 900, 1000
};
Ở đây kích thước của mảng được quyết định bởi những số nằm
trong dấu ngoặc nhọn.
Bạn có thể định nghĩa một mảng của mảng (được biết đến với
cái tên mảng đa chiều) được sử dụng 2 hoặc nhiều hơn dấu ngoặc vuông, như ví dụ
String[][] names
. Mỗi phần
tử, vì thế phải được truy cập số tương ứng với các chỉ số.
Trong ngôn ngữ lập trình Java, một mảng đa chiều là một mảng
mà các thành phần của chúng chính là các mảng. Điều này không giống trong ngôn
ngữ lập trình C và ngôn ngữ lập trình Fortran. Một hệ quả tất yếu của việc này
đó là các dòng cho phép thay đổi kích thước, giống như ví dụ MultiDimArrayDemo
sau:
class MultiDimArrayDemo { public static void main(String[] args) { String[][] names = { {"Mr. ", "Mrs. ", "Ms. "}, {"Smith", "Jones"} }; // Mr. Smith System.out.println(names[0][0] + names[1][0]); // Ms. Jones System.out.println(names[0][2] + names[1][1]); } }
Cuối cùng, bạn cần sử dụng độ thuộc tính đô dài (length) xác
định độ dài của mảng. Như đoạn mã nguồn sau:
System.out.println(anArray.length);
Copy mảng.
Trong lớp System, có một phương thức copy mảng arraycopy
bạn có thể sử dụng để sao chép dữ liệu từ mảng này sang mảng khác.
public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
Hai tham số Object trong mảng từ mảng đến mảng. Tham số thứ
3 là int là từ vị trí bắt đầu trong mảng nguồn, và vị trí bắt đầu trong mảng
đích, và số lượng phần tử cần sao chép.
Trong chương trình ArrayCopyDemo dưới dây, định nghĩa một mảng
có các phần tử kiểu chuỗi. Sử dụng phương thức System.arraycopy để chép ra một
mảng con là mảng thứ 2.
class ArrayCopyDemo {
public static void main(String[] args) {
String[] copyFrom = {
"Affogato", "Americano", "Cappuccino", "Corretto", "Cortado",
"Doppio", "Espresso", "Frappucino", "Freddo", "Lungo", "Macchiato",
"Marocchino", "Ristretto" };
String[] copyTo = new String[7];
System.arraycopy(copyFrom, 2, copyTo, 0, 7);
for (String coffee : copyTo) {
System.out.print(coffee + " ");
}
}
}
Kết quả của chương trình là:
Cappuccino Corretto Cortado Doppio Espresso Frappucino Freddo |
Các thao tác mảng.
Sử dụng mảng là một sức mạnh trong lập trình. Java SE cung cấp
các phương thức thực phổ biến nhất cho các thao tác liên quan đến mảng. Trong
ví dụ ArrayCopyDemo ở trên sử dụng phương thức arraycopy trong lớp System
để thay thế việc lặp giữa các phần tử trong mảng nguồn và các phần tử trong mảng
đích. Điều này thực thi đằng sau, cho phép lập trình viên chỉ sử dụng một dòng
code để gọi phương thức.
Để công việc lập trình của bạn tiện lợi, Java SE cung cấp các
thao tác thực thi với mảng (các nhiệm vụ phổ biến, như sao chép, sắp xếp, tìm
kiếm trong mảng) trong lớp java.util.Arrays.
Ví dụ, trong ví dụ trước có thể sửa thành sử dụng phương thức copyOfRange
trong lớp java.util.Arrays
để thay thế, xem trong ví dụ ArrayCopyOfDemo
sau. Sự khác biệt ở đây là sử dụng phương thức copyOfRange không
yêu cầu bạn phải tạo mảng đích trước khi gọi phương thức, bởi vì mảng đích được
trả về bởi phương thức này.
class ArrayCopyOfDemo {
public static void main(String[] args) {
String[] copyFrom = {
"Affogato", "Americano", "Cappuccino", "Corretto", "Cortado",
"Doppio", "Espresso", "Frappucino", "Freddo", "Lungo", "Macchiato",
"Marocchino", "Ristretto" };
String[] copyTo = java.util.Arrays.copyOfRange(copyFrom, 2, 9);
for (String coffee : copyTo) {
System.out.print(coffee + " ");
}
}
}
Bạn có thể thấy rằng, đầu ra của chương trình là giống nhau,
trong khi viết một vài dòng code. Tham số thứ hai của phương thức copyOfRange
là chỉ số bắt đầu phạm vi sao chép, bao gồm tham số thứ ba là chỉ số kết thúc của
phạm vi sao chép, không bao gồm phần tử này. Trong ví dụ này phạm vi được sao
chép không bao gồm phần tử có chỉ số là 9 (chứa chuỗi Lungo). Một vài thao tác được cung cấp
trong lớp java.util.Arrays là:
- Tìm kiếm một giá trị và trả về chỉ số mảng.
- So sánh 2 mảng.
- Điền giá trị vào một mảng vào mỗi phẩn tử của mảng.
- Sắp xếp một mảng theo chiều tăng dần. Điều này có thể được sử dụng một cách tuần tự, sử dụng phương thức sort hoặc sử dụng phương thức parallelSort trong Java SE 9. Sắp xếp song song cho các dãy số lớn trên hệ thống đa xử lý nhanh hơn phương thức sắp xếp mảng tuần tự.
- Tạo một luồng có sử dụng một mảng là nguồn (phương thức stream). Ví dụ, câu lệnh in nội dung của mảng copyTo trong ví dụ trước có thể được làm như sau:
- java.util.Arrays.stream(copyTo).map(coffee -> coffee + " ").forEach(System.out::print);
- Chuyển đổi mảng thành một chuỗi. Phương thức toString chuyển đổi mỗi phần tử mảng sang thành một chuỗi, phân cách giữa chúng là dấu phẩy, bao quanh chúng sẽ là dấu ngoặc vuông. Ví dụ, câu lệnh chuyển đổi mảng copyTo sang thành chuỗi và in chúng ra màn hình như sau:
System.out.println(java.util.Arrays.toString(copyTo)); |
Kết quả nhận được:
[Cappuccino, Corretto, Cortado, Doppio, Espresso, Frappucino, Freddo]