Được chỉnh sửa ngày 08/12/2022.
Chào mừng các bạn đến với bài học Java số 11, bài học về Mảng. Bài học này nằm trong chuỗi bài học lập trình ngôn ngữ Java của Yellow Code Books.
Đầu tiên mình nói một chút về Mảng trước khi đi vào chi tiết. Có một số tài liệu hoặc chương trình học Java nói rất muộn về Mảng, thường thì họ dành để nói về lập trình hướng đối tượng (OOP) trước. Theo mình thì điều này mới nghĩ sẽ thấy hợp lý, vì trong Java, Mảng không phải là kiểu dữ liệu nguyên thủy mà là một cấu trúc dữ liệu mới dựa trên các nền tảng của hướng đối tượng. Vì vậy, biết về hướng đối tượng rồi mới tới Mảng thì xem ra không sai tí nào.
Tuy nhiên để hiểu và sử dụng tốt Mảng trong Java, mình không nghĩ bạn phải cần một kiến thức sâu rộng về OOP. Vả lại Mảng rất hiệu quả, mà nếu sử dụng Mảng trễ quá về sau, mình e rằng bạn sẽ đánh mất một số cơ hội tốt để tiếp cận một số kiến thức thú vị của Java ở giai đoạn này. Thêm nữa, Mảng cũng có thể xem như nền tảng để tạo thành khái niệm Chuỗi (String) mà chúng ta cùng nói đến ở bài sau nữa, và String cũng là một khái niệm của OOP mà chúng ta cũng sẽ phải làm quen sớm vì tính hiệu quả của nó.
Khái Niệm Mảng
Mảng, hay còn gọi là Array, là một cấu trúc dữ liệu, dùng để chứa một tập hợp các phần tử có kiểu dữ liệu tương tự nhau. Giả sử chúng ta có mảng các số nguyên, Mảng này sẽ chứa tập hợp các phần tử có cùng kiểu dữ liệu là int. Ngoài tập hợp số nguyên như ví dụ vừa nêu, hay tập hợp các kiểu dữ liệu nguyên thủy mà bạn cũng dần được làm quen, Mảng còn chứa đựng tập hợp các dữ liệu “không nguyên thủy” mà chúng ta sẽ nói đến ở các bài sau nữa.
Khi bạn khai báo một Mảng, bạn phải chỉ định độ lớn cho nó, tức là chỉ định số phần tử tối đa mà Mảng đó có thể chứa. Mỗi một phần tử trong Mảng sẽ được quản lý theo chỉ số (index), chỉ số sẽ bắt đầu bằng số 0 (bạn sẽ được làm quen với cách truy cập các phần tử Mảng dựa vào chỉ số ở các ví dụ phía dưới).
Giả sử mình đã tạo ra một Mảng có 10 phần tử kiểu int, khi lưu trữ mảng này vào bộ nhớ, chúng sẽ được sắp xếp gần nhau theo mô hình giả lập sau, mỗi ô là một phần tử kiểu int với các số trong đó là giá trị được lưu trữ vào.

Bạn đã rõ hơn về Mảng, vậy tại sao phải dùng cấu trúc này?
Tại Sao Phải Dùng Mảng?
Ý nghĩa của phần này muốn nói đến lợi ích của việc dùng Mảng.
Đúng như tên gọi và định nghĩa Mảng trên đây, cấu trúc dữ liệu Mảng sẽ giúp bạn lưu trữ danh sách các phần tử. Mình ví dụ như bạn sẽ cần lưu danh sách các sinh viên. Danh sách này sẽ được tổ chức sao cho bạn có thể truy xuất ngẫu nhiên nhanh chóng đến từng phần tử con. Chẳng hạn bạn muốn lấy thông tin sinh viên ở vị trí thứ 10. Pùm! Có ngay!. Danh sách này có thể được sắp xếp lại trật tự theo một tiêu chí nào đó, khi đó bạn có thể nhanh chóng đọc ra top 10 sinh viên có điểm số cao nhất. Hay một lợi thế nữa của Mảng đó là với việc tổ chức các phần tử có kiểu dữ liệu tương tự nhau như vậy sẽ làm cho code của chúng ta tường minh và dễ quản lý hơn, giúp tối ưu code.
Tuy nhiên Mảng cũng có một bất lợi là bạn phải khai báo độ lớn, tức khai báo sẵn số lượng phần tử mà Mảng này sẽ sử dụng. Điều này làm code của bạn kém linh động vì có khi chúng ta muốn số lượng phần tử của Mảng đã khai báo được nới rộng hơn. Hoặc làm hiệu năng của hệ thống bị giảm do bạn khai báo sẵn một mảng với độ lớn quá cao mà không sử dụng hết số lượng vùng nhớ đã khai báo. Tất nhiên để khắc phục nhược điểm này của Mảng thì Java cũng có khái niệm Array List mà chúng ta sẽ làm quen ở một bài học khác.
Cách Sử Dụng Mảng
Cũng giống như khi bạn làm quen đến khái niệm biến, bạn phải biết cách khai báo, gán dữ liệu, sử dụng biến đó trong biểu thức. Với Mảng cũng vậy, nhưng bởi vì Mảng hơi đặc biệt là nó chứa đựng các phần tử con, cho nên ngoài những gì bạn có thể vận dùng từ việc sử dụng biến, sẽ có một vài cái mới ở đây mà bạn phải làm quen. Chúng ta cùng đi qua các bước trong việc sử dụng Mảng như sau nhé.
Khai Báo Mảng
Bạn có thể chọn một trong hai cách khai báo sau.
kiểu_dữ_liệu[] tên_mảng;
hoặc
kiểu_dữ_liệu tên_mảng[];
Bạn nhớ là phải có cặp [ ] ở phần kiểu_dữ_liệu hoặc tên_mảng. Sở dĩ Java định nghĩa cả 2 cách khai báo như trên là vì cách thứ nhất là đúng chuẩn Java, trong khi cách thứ 2 thì Java hỗ trợ cách khai báo Mảng từ C/C++.
Cặp [ ] cũng thể hiện rằng đây là Mảng, bạn có để ý thấy là nếu không có cặp ngoặc đó thì khai báo trên đây không khác gì việc khai báo một biến cả đúng không nào.
Uhm… Nhưng mà khác với biến ở chỗ Mảng ở bước khai báo này vẫn chưa sử dụng được, như đã nói, chúng ta cần chỉ định độ lớn của mảng, vấn đề này sẽ được nói ở mục sau.
Bây giờ là một ví dụ. Để khai báo một mảng các số nguyên, chúng ta code như sau.
int[] myArray;
Cấp Phát Bộ Nhớ Cho Mảng
Bạn phải dùng từ khóa new để cấp phát bộ nhớ cho Mảng. Lần trước bạn dùng đến new là ở Bài 7, khi đó bạn khởi tạo một biến scanner, bạn có nhớ không nào.

Với Mảng, việc cấp phát bộ nhớ cũng sẽ tương tự, như sau.
tên_mảng = new kiểu_dữ_liệu[kích_cỡ_mảng];
Ở bước này rất cần thiết phải có kích_cỡ_mảng, nếu không truyền vào tham số này, việc cấp phát sẽ phát sinh lỗi. Kích cỡ này là do bạn quyết định, thông thường trong một ứng dụng, nếu biết chính xác thông số kích cỡ này và kích cỡ này sẽ không bị thay đổi trong suốt quá trình sống của ứng dụng, thì bạn hãy sử dụng mảng, nếu không biết chính xác hoặc kích cỡ luôn luôn thay đổi thì chúng ta nên dùng đến Array List như mình có nhắc đến.
Tiếp nối ví dụ khai báo ở trên kia, chúng ta thêm phần cấp phát như sau.
int[] myArray = new int[10];
Khi ứng dụng chạy đến bước này, nó sẽ tạo ra một mảng với 10 phần tử số nguyên như minh họa sau.

Sở dĩ bạn thấy hình minh họa tạo ra Mảng với các phần tử có giá trị 0, nó đúng với thực tế bạn code. Nếu bạn khai báo một Mảng rồi cấp phát độ lớn cho nó, với Mảng kiểu số bạn sẽ có một Mảng mặc định là các phần tử mang giá trị 0. Với Mảng kiểu boolean sẽ là các phần tử false. Và với Mảng kiểu đối tượng thì các phần tữ mặc định sẽ là null (bạn sẽ hiểu giá trị này khi làm quen với kiểu đối tượng sau).
Khởi Tạo Mảng
Như bạn thấy, bước cấp phát trên đây đã thực hiện một thao tác giữ chỗ trong hệ thống một vùng nhớ đủ rộng để chứa 10 phần tử số nguyên. Mảng của bạn đã chứa các phần thử mang giá trị mặc định và đã sẵn sàng sử dụng rồi. Nhưng để cho Mảng thực sự mang đúng trọng trách của nó, việc kế tiếp là khởi tạo, hay còn hiểu là chứa dữ liệu thực sự vào cho các phần tử.
Có nhiều cách khởi tạo giá trị cho các phần tử Mảng.
Cách Thứ Nhất
Khởi tạo ngay khi vừa cấp phát bộ nhớ cho Mảng, khi đó bạn không cần dùng từ khóa new nữa, chỉ khai báo và khởi tạo trên một dòng như ví dụ dưới. Dùng cách này khi bạn đã biết trước mình cần khởi tạo một Mảng như thế nào ngay từ ban đầu. Với ví dụ mảng kiểu int như trên kia mình sẽ khởi tạo Mảng theo cách thứ nhất như sau.
int[] myArray = {3, 5, 7, 30, 10, 5, 8, 23, 0, -5};
Cách Thứ Hai
Khởi tạo từng giá trị cho từng phần tử Mảng bằng cách truy xuất đến chúng dựa vào chỉ số và gán cho chúng giá trị. Cách này được sử dụng khi bạn không biết ban đầu nên khởi tạo Mảng ra sao, nhưng sau đó, với logic của ứng dụng, bạn sẽ điền tuần tự từng phần tử theo chỉ số của nó.
int[] myArray = new int[10]; myArray[0] = 3; myArray[1] = 5; myArray[2] = 7; myArray[3] = 30; myArray[4] = 10; myArray[5] = 5; myArray[6] = 8; myArray[7] = 23; myArray[8] = 0; myArray[9] = -5;
Cả 2 cách trên đây đều cho ra Mảng trong hệ thống diễn đạt như sơ đồ sau.

Cách Khác
Ngoài ra thì đôi khi bạn còn dùng cả vòng lặp để khởi tạo giá trị, dùng trong trường hợp các giá trị mảng giống nhau, hay theo một trật tự nào đó, mình ví dụ với khởi tạo như sau.
int arraySize = 10; int[] myArray = new int[arraySize]; for (int i = 0; i < arraySize; i++) { myArray[i] = i; }
Khi này mảng sẽ chứa danh sách các giá trị giống như vầy.

Truy Cập Mảng
Như bạn đã làm quen với những cách trên đây, chúng ta sẽ truy cập vào mảng dựa vào chỉ số. Bạn luôn phải nhớ rằng chỉ số đầu tiên (chỉ số thứ nhất) của phần tử mảng bắt đầu từ 0, và chỉ số của phần tử thứ n sẽ là n-1.
Ví dụ như bạn muốn in ra console giá trị phần tử cuối cùng trong mảng 10 phần tử trên đây.
int[] myArray = {3, 5, 7, 30, 10, 5, 8, 23, 0, -5}; System.out.println("Phan tu thu 10: " + myArray[9]);
Bạn có thể dùng myArray.length
để biết được độ lớn của Mảng một cách tự động, thay vì nhớ số lượng này rồi dùng một con số cứng như ví dụ trên. Khi đó ví dụ trên có thể viết lại như sau.
int[] myArray = {3, 5, 7, 30, 10, 5, 8, 23, 0, -5}; System.out.println("Phan tu thu 10: " + myArray[myArray.length - 1]);
Nên nhớ rằng
myArray.length
sẽ là 10, còn vị trí của phần tử cuối cùng trong mảng làmyArray.length - 1
nhé.
Hay nếu bạn muốn in ra tất cả các giá trị phần tử trong mảng, cách tốt nhất là hãy dùng vòng for.
int[] myArray = {3, 5, 7, 30, 10, 5, 8, 23, 0, -5}; for (int i = 0; i < myArray.length; i++) { System.out.println("Phan tu thu " + (i + 1) + ": " + myArray[i]); }
Một Số Thực Hành Với Mảng
Bài Thực Hành Số 1
Bạn hãy tạo Mảng CÁC SỐ NGUYÊN và khởi tạo giá trị cho mảng như sau {3, 5, 7, 30, 10, 5, 8, 23, 0, -5}. Hãy in ra console TỔNG và TRUNG BÌNH CỘNG của các giá trị phần tử trong Mảng.
Và đây là code của bài thực hành.
int[] myArray = { 3, 5, 7, 30, 10, 5, 8, 23, 0, -5 }; int sum = 0; double avg; int count = myArray.length; for (int i = 0; i < count; i++) { sum += myArray[i]; } avg = (double) sum / count; System.out.println("Sum is " + sum); System.out.println("Avegare is " + avg);
Bài Thực Hành Số 2
Với Mảng các số nguyên như bài thực hành trên. Bạn hãy in ra VỊ TRÍ (thứ tự) của các phần tử nhỏ hơn hay bằng 0.
Và code của chương trình.
int[] myArray = { 3, 5, 7, 30, 10, 5, 8, 23, 0, -5 }; int count = myArray.length; boolean isFound = false; for(int i = 0; i < count; i++) { if (myArray[i] <= 0) { System.out.println("The position below or equal zero is: " + i); isFound = true; } } if (!isFound) { System.out.println("Can not found the position you need"); }
Bài Thực Hành Số 3
Cũng với Mảng các số nguyên như bài thực hành trên. Giờ bạn hãy sắp xếp lại các phần thử mảng theo thứ tự TĂNG DẦN, sao cho khi in ra console nội dung sẽ như vầy “-5 0 3 5 5 7 8 10 23 30”.
Và code như sau.
int[] myArray = {3, 5, 7, 30, 10, 5, 8, 23, 0, -5}; for (int i = 0; i < myArray.length - 1; i++) { for (int j = i; j <= myArray.length - 1; j++) { if (myArray[i] > myArray[j]) { // Thao tác này đổi chỗ 2 giá trị ở 2 vị trí i, j của mảng int temp; temp = myArray[i]; myArray[i] = myArray[j]; myArray[j] = temp; } } } for (int i = 0; i < myArray.length; i++) { System.out.print(myArray[i] + " "); }
Kết Luận
Chúng ta lại cùng nhau đi qua một kiến thức mới nữa trong Java, kiến thức Mảng. Tuy vậy kiến thức Mảng đã nói ở bài hôm nay vẫn còn một tí tẹo nữa chưa được nói đến vì bài viết cũng khá dài, và… dài quá thì bạn lười đọc lắm :). Nói vậy thôi chứ tổng cộng kiến thức của Mảng cũng không nhiều và khó đâu, bao nhiêu đây cũng đủ cho bạn thử nghiệm giải các bài toán trên mạng hay trên lớp rồi nhé. Phần sau chỉ nói thêm cách sử dụng foreach trên Mảng. Và hơi đau đầu một tí đó là Mảng nhiều chiều, các bạn cùng đón đọc nhé.
Cảm ơn bạn đã đọc các bài viết của Yellow Code Books. Bạn hãy ủng hộ blog bằng cách:
– Đánh giá 5 sao ở mỗi bài viết nếu thấy thích.
– Comment bên dưới mỗi bài viết nếu có thắc mắc.
– Để lại địa chỉ email của bạn ở thanh bên phải để nhận được thông báo sớm nhất khi có bài viết mới.
– Chia sẻ các bài viết của Yellow Code Books đến nhiều người khác.
– Ủng hộ blog theo hướng dẫn ở thanh bên phải để blog ngày càng phát triển hơn.
Bài Kế Tiếp
Như đã nói, bạn sẽ được làm quen với phần 2 của Mảng, đó là foreach trên Mảng, và Mảng nhiều chiều.
Ad cho e hỏi Mảng này có sử dụng thay thế cho ArrayList đc k ạ
Mảng này mình chỉ nói đến Array thôi bạn ạ, tức là mảng cố định, không thể thêm hay xóa các phần tử trong mảng. Còn ArrayList và các kiểu mảng động khác mình sẽ nói ở bài sau nhé.
Anh cho em hỏi, ở bài thực hành số 2:
if (!isFound) {
System.out.println(“Can not found the position you need”);
}
– Câu này anh làm bằng cách nào vậy, em không hiểu cơ chế hoạt động của code để đưa ra được câu “can not found the position you need”. Anh có thể giải thích dùm em được không
Bạn xem vì ban đầu isFound được gán là false, do đó nếu hết vòng for mà isFound vẫn là false thì kết quả câu điều kiện if (!isFound) sẽ được thực hiện. Bạn có thể kiểm chứng bằng cách sửa các phần tử mảng sao cho đừng có phần tử nào nhỏ hơn 0 hết. Để dễ hiểu nhất các thuật toán trong lập trình, bạn có thể tập sử dụng chức năng debug, bằng cách đặt breakpoint rồi chạy ở chế độ debug để xem ứng dụng sẽ chạy ra sao nhé (mình nhớ các bài học đầu đã nói về debug rồi đấy).
em hiểu rùi, đầu tiên anh cho isFound là false, nếu tìm được giá trị <0 thì isfound sẽ được chuyển thành true, còn câu if (!isFound) tức là if (isFound = false) là trong trường hợp vòng lặp for không thực hiện được. cảm ơn anh nhiều
myArray.length – 1 nghĩa là gì vậy a
Mỉnh có nói rõ trong bài học đó bạn: (Lưu ý là nếu bạn dùng myArray.length thì hệ thống sẽ trả ra cho bạn độ lớn của mảng, trong trường hợp của ví dụ này độ lớn là 10. Toán tử “.” trong biểu thức trên sẽ được nói rõ hơn ở mục OOP.)
anh ơi tại soa phải dùng arr.length ạ mà không dùng số 10 luôn ạ
Là vì mong muốn thôi bạn. Với ví dụ này thì bạn thấy rõ ràng một mảng có 10 phần tử, nên bạn mới thắc mắc tại sao không dùng 10 thay arr.length (với bài thực hành này thì 10 hay arr.length là như nhau). Nhưng mình vẫn muốn giới thiệu arr.length, vì sẽ có những ví dụ trong thực tế bạn không biết được mảng đó có bao nhiêu phần tử, khi này sử dụng arr.length là một cách hiệu quả nhất để ứng dụng của bạn có thể linh động biết được số lượng phần tử của mảng.
Bai Thuc hang sap xep Theo thu tu tang dan thieu lenh if de so sanh arr[i] va arr[j]
Cảm ơn bạn đã nhìn ra lỗi. Mà hình như không phải code thiếu lệnh so sánh đâu bạn, nó bị trôi code qua bên phải í, bạn có thể xem lại, nếu có thời gian mình sẽ sửa lại nội dung bài học này theo format mới hết, format cũ này đã không được WordPress hỗ trợ nữa nên phát sinh nhiều lỗi hiển thị.
Anh co th giai thich ba huong dan chi tiet hon bai thuc hanh so 3 “sap xep theo thu tu tang dan”, tai sao minh phai dung myArray.length -1, tai sao luc i< myArray.length -1 ma j lai la <=. cam on
À là do mình thực hiện 2 vòng for để kiểm tra rồi hoán đổi 2 vị trí của mảng với nhau. Vòng for bên ngoài, chạy bằng biến i, mình chạy từ phần tử 0 của mảng, đến phần tử KẾ CUỐI của mảng thôi, do đó i < myArray.lenght - 1 là vậy. Sở dĩ i chạy kế cuối, là vì sau đó j ở vòng for bên trong mới sẽ chạy đến cuối mảng. Bạn tưởng tượng khi này các cặp sau sẽ được kiểm tra: [i=0; j=1], [i=0, j=2],... [i=lenght-2(kế cuối),j=lenght-1(cuối)]. Nếu i chạy đến cuối thì ứng dụng sẽ báo lỗi vì j chạy sau 1 số sẽ ra khỏi index của mảng.
Trong ví dụ phần truy cập mảng mình nghĩ ad nên code như này sẽ hợp lý hơn
int[] myArray = {3, 5, 7, 30, 10, 5, 8, 23, 0, -5};
for (int i = 0; i < myArray.length; i++) {
System.out.println("Phan tu thu " + (i + 1) + ": " + myArray[i]);
}
Mình hiểu ý bạn rồi. Góp ý tuy nhỏ mà tinh tế, mình sẽ sửa lại nội dung bài viết :))