Được chỉnh sửa ngày 09/12/2022.
Chào mừng các bạn đến với bài học Java số 12, bài học về Mảng (tiếp theo). 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.
Còn nhớ bài trước chúng ta cùng nói về khái niệm và cách thức sử dụng Mảng trong Java, khi đó mình cũng có nói đến cách thức hiệu quả nhất để duyệt qua các phần tử trong Mảng là dùng vòng lặp for. Hôm nay chúng ta tìm hiểu một “biến thể” khác của for dành riêng cho Mảng, giúp bạn có thể duyệt qua Mảng nhanh hơn, đó là foreach. Và còn một phần nâng cao của Mảng nữa cũng sẽ được nói đến ở bài hôm nay, đó là Mảng nhiều chiều.
foreach
Làm Quen Với foreach
Như lời mở đầu mình có nói, foreach là một biến thể của for, vậy tại sao mình không nói về foreach ở bài học về for? Câu trả lời là, đúng là foreach cũng là for – Vì nó là sự kết hợp giữa for và each. Cú pháp của foreach cũng kế thừa từ for, và cách thức hoạt động của foreach dĩ nhiên cũng sẽ giống for rồi. Nhưng foreach lại sinh ra để làm việc chung với Mảng, foreach giúp thi triển các dòng code để duyệt trên mảng được dễ dàng hơn. Chính vì vậy mà foreach luôn được nói kèm với khái niệm về Mảng.
Vậy foreach có quan trọng không? Câu trả lời là, không quan trọng, nên sẽ không bắt buộc bạn phải dùng foreach đâu nhé. Như nói ở câu trả lời trên thì foreach chỉ giúp cho việc thi triển code trên vòng lặp được dễ dàng hơn thôi, bạn hoàn toàn có thể dùng for truyền thống để duyệt qua Mảng mà không cần đến foreach.
Cách Sử Dụng foreach
Trước hết chúng ta nói về cú pháp của foreach.
for (khai_báo_phần_tử_lặp : mảng) { các_câu_lệnh; }
Bạn có thấy giống với for không nào, uhm mình đồng ý, chỉ giống mỗi chữ for. Mặc dù được gọi với cái tên foreach nhưng khi khai báo chúng ta vẫn chỉ cần đến một chữ for.
Nhớ lại một tí, với for bạn cần đưa vào 3 thành phần để định nghĩa các quy luật lặp cho nó, đồng thời giúp bạn kiểm soát chỉ số (index) mà vòng lặp đang thực hiện đến. Còn với foreach, vòng lặp này sẽ tự động biết nó phải đi qua lần lượt các phần tử trong mảng rồi, bạn cũng không cần khai báo hay quan tâm đến chỉ số mà vòng lặp đang thực hiện, nên việc tham số cho vòng lặp này lại trở nên đơn giản hơn for nhiều. Mời bạn làm quen từng thành phần trong cú pháp foreach này.
- khai_báo_các_phần_tử_lặp là nơi bạn sẽ khai báo một biến mới để dùng trong thân hàm foreach này. Biến này sẽ chứa đựng giá trị của phần tử mà vòng lặp này đang lặp đến, do đó nó phải có kiểu dữ liệu giống như kiểu dữ liệu của từng phần tử Mảng.
- mảng chính là Mảng bạn cần lặp. Đây có thể là một hàm trả về giá trị Mảng. Hàm, hay còn gọi là Phương thức, sẽ được nói đến ở bài học sau nhé.
- Dấu hai chấm (:) được hiểu như là “trong”, vậy nghĩa cho tất cả các tham số trong foreach này là “từng phần tử trong mảng”.
- các_câu_lệnh chính là nơi bạn dùng đến biến ở khai_báo_các_phần_tử_lặp ra dùng.
Bài Thực Hành Số 1
Chúng ta cùng làm lại Bài thực hành số 1 ở bài Mảng hôm trước và thực hiện lại với foreach ở bài hôm nay. Mình copy lại nội dung bài thực hành hôm trước như sau.
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; for (int i : myArray) { sum += i; } avg = (double) sum / myArray.length; System.out.println("Sum is " + sum); System.out.println("Avegare is " + avg);
Trường Hợp Nào Bạn Không Nên Dùng foreach?
Mặc dù foreach khá hay, mình cũng thích dùng nó, nhưng nên nhớ không phải lúc nào bạn cũng dùng foreach được đâu nhé, và sau đây là các trường hợp ngoại lệ đó.
- Không được dùng foreach để remove một phần tử nào đó khỏi Danh sách (mình dùng từ Danh sách – Array List – Chứ không phải Mảng – Array, vì Mảng không cho phép bạn thêm hay bớt một phần tử trong nó, chỉ có Danh sách mới cho phép. Và vì foreach cũng sẽ làm việc trên Danh sách tương tự như Mảng nên mình nhắc đến ý này ở đây, về sau khi nói đến Danh sách mình sẽ nhắc lại cho bạn nhớ).
- Vì foreach tự duyệt tuần tự trên các phần tử Mảng, nên nó rất dở trong việc xác định chỉ số (index) của từng phần tử. Do đó đừng bắt foreach hoạt động khi bạn muốn biết chỉ số của phần tử hiện tại đang xử lý, hay muốn truy xuất nhanh đến vị trí của bất kỳ phần tử nào đó trong Mảng.
Mảng Hai Chiều
Đến bước này chắc chắn bạn đã hiểu về khái niệm Mảng. Khi người ta nói tới Mảng, thì có nghĩa họ đang nói đến “Mảng một chiều”. Như bạn biết thì Mảng được xem như một danh sách (cố định) các phần tử trải dài theo một chiều duy nhất. Như minh họa bài trước thì Mảng (một chiều) nó như thế này.

Bạn nghĩ sao nếu có một biểu diễn Mảng theo một chiều mới, khi này Mảng của bạn được gọi là Mảng hai chiều, mà người ta còn gọi là Ma trận. Biểu diễn của Mảng hai chiều sẽ trông như sau.

Khai Báo Mảng Hai Chiều
Tương tự như khai báo Mảng, khai báo một Mảng hai chiều tương tự như vậy nhưng sẽ cần đến hai cặp ngoặc vuông [ ][ ].
kiểu_dữ_liệu[][] tên_mảng;
hoặc
kiểu_dữ_liệu tên_mảng[][];
Chúng ta thử khai báo Mảng hai chiều cho minh họa trên đây.
int[][] myMatrix;
Cấp Phát Bộ Nhớ Cho Mảng Hai Chiều
Cũng như Mảng. Cú pháp cấp phát cho Mảng hai chiều như sau.
tên_mảng = new kiểu_dữ_liệu[số_lượng_dòng][số_lượng_cột];
Vậy với ví dụ khai báo cho Mảng hai chiều ở trên, chúng ta tiến hình cấp phát như sau.
int[][] myMatrix = new int[4][5];
Khởi Tạo Mảng Hai Chiều
Lại cũng giống như Mảng, Mảng hai chiều cũng có nhiều hình thức khởi tạo. Giả sử mình muốn tạo ra một Mảng hai chiều như hình minh họa trên kia.
Cách Thứ Nhất
Dùng khi bạn biết trước dữ liệu cần khởi tạo cho Mảng hai chiều, như là dữ liệu mình đưa ra trên đây, bạn khởi tạo như sau.
int[][] myMatrix = { {3, 5, 7, 30, 10}, {5, 8, 23, 0, -5}, {100, -9, 4, 2, 55}, {-80, -22, 11, 1, 12}};
Cách Thứ Hai
Dùng cách này khi không biết dữ liệu ban đầu như thế nào, về sau tùy logic chương trình mà Mảng hai chiều sẽ được điền dữ liệu từ từ, khi đó bạn phải làm việc với chỉ số của nó. Một lưu ý là với Mảng hai chiều, chỉ số của nó được thể hiện như sau.

Và để làm việc với chỉ số, thì bạn chú ý cách sử dụng chỉ số như khai báo sau nhé.
int[][] myMatrix = new int[4][5]; myMatrix[0][0] = 3; myMatrix[0][1] = 5; myMatrix[0][2] = 7; myMatrix[0][3] = 30; myMatrix[0][4] = 10; myMatrix[1][0] = 5; myMatrix[1][1] = 8; myMatrix[1][2] = 23; myMatrix[1][3] = 0; myMatrix[1][4] = -5; myMatrix[2][0] = 100; myMatrix[2][1] = -9; myMatrix[2][2] = 4; myMatrix[2][3] = 2; myMatrix[2][4] = 55; myMatrix[3][0] = -80; myMatrix[3][1] = -22; myMatrix[3][2] = 11; myMatrix[3][3] = 1; myMatrix[3][4] = 12;
Cách Khác
Cũng giống như Mảng, Mảng hai chiều cũng có thể được khởi tạo bằng vòng lặp for, tất nhiên là bằng cách lồng hai for vào nhau rồi. Dùng cách này cho việc khởi tạo các giá trị cho Mảng hai chiều theo một trật tự nào đó. Bạn hãy xem ví dụ sau.
int row = 4; int column = 5; int[][] myMatrix = new int[row][column]; for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { myMatrix[i][j] = i + j; } }
Bạn có biết code trên đây sẽ tạo ra một Ma trận như thế nào không. Ma trận bạn tạo ra chính là hình minh họa bên dưới.

Chắc chắn đến đây bạn đã hiểu rõ Mảng hai chiều hay Ma trận rồi, tuy nhiên nếu có thắc mắc thì hãy để lại bình luận bên dưới bài học này cho mình nhé. Bây giờ chúng ta qua phần thực hành cho Ma trận.
Bài Thực Hành Số 2
Bài này chúng ta sẽ thử thao tác với Ma trận. Nhưng thay vì khai báo và khởi tạo sẵn một Ma trận, bạn hãy thử nhập chúng từ console xem sao, sẽ rất thú vị đấy, nội dung của bài thực hành này như sau.
Tạo một Ma trận các số nguyên bằng cách.
- In ra console dòng “Please enter number of row:” và đợi người dùng nhập vào số lượng hàng của Ma trận.
- In ra console dòng “Please enter number of columns:” và đợi người dùng nhập vào số lượng cột của Ma Trận.
- In ra console từng dòng yêu cầu người dùng nhập từng phần tử của Ma trận.
Với Ma trận do người dùng nhập vào ở trên, thực hiện thao tác sau.
- In ra Ma trận mà người dùng vừa mới nhập.
- In ra dòng và cột có tổng lớn nhất trong Ma trận.
Nếu bạn đã hiểu yêu cầu bài thực hành thì tiến hành code nhé, code xong rồi thì mời bạn so sánh với kết quả của mình bên dưới. Hoan nghênh các bạn chia sẻ những suy nghĩ hoặc những giải thuật của bạn về bài thực hành này ở phần bên dưới bài học.
Đại loại của chương trình khi chạy, và khi tương tác với user sẽ như sau.

Scanner scanner = new Scanner(System.in); // Nhập số lượng hàng System.out.print("Please enter number of row: "); int row = scanner.nextInt(); // Nhập số lượng cột System.out.print("Please enter number of column: "); int column = scanner.nextInt(); int[][] myMatrix = new int[row][column]; // Kêu user nhập vào từng phần tử của Ma Trận for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { System.out.print("Matrix[" + i + "][" + j + "] = "); myMatrix[i][j] = scanner.nextInt(); } } // In ra ma trận user mới nhập System.out.println("Your Matix here"); for (int i = 0; i < row; i++) { for (int j = 0; j < column; j++) { System.out.print(myMatrix[i][j] + " "); } System.out.println(); // Đơn giản là xuống dòng } // Tìm dòng lớn nhất int[] sumRow = new int[row]; // Mảng chứa tổng từng dòng for (int ro = 0; ro < row; ro++) { for (int co = 0; co < column; co++) { sumRow[ro] += myMatrix[ro][co]; } } int maxIndexRow = 0; int maxSumRow = sumRow[maxIndexRow]; // Giả sử dòng 0 là dòng lớn nhất for (int i = 1; i < row; i++) { if (maxSumRow < sumRow[i]) { maxSumRow = sumRow[i]; maxIndexRow = i; // Lưu lại chỉ số dòng của số lớn nhất } } System.out.println("Max row in Matrix is row: " + maxIndexRow); // Tìm cột lớn nhất int[] sumColumn = new int[column]; // Mảng chứa tổng từng cột for (int ro = 0; ro < row; ro++) { for (int co = 0; co < column; co++) { sumColumn[co] += myMatrix[ro][co]; } } int maxIndexColumn = 0; int maxSumColumn = sumColumn[maxIndexColumn]; // Giả sử cột 0 là dòng lớn nhất for (int i = 1; i < column; i++) { if (maxSumColumn < sumColumn[i]) { maxSumColumn = sumColumn[i]; maxIndexColumn = i; // Lưu lại chỉ số cột của số lớn nhất } } System.out.println("Max column in Matrix is column: " + maxIndexColumn);
Có Còn Thể Loại Mảng Nào Nữa?!!
Phần râu ria còn lại của bài học hôm nay mình xin gom hết vào đây, mình chỉ nói qua một lượt mà không có thực hành, cũng không cần các bạn phải hiểu rõ, vì phần này nói về các thể loại Mảng còn lại trong Java mà hầu như chúng ta sẽ không dùng đến nó. Sự thật là mình chưa bao giờ dùng đến các thể loại này, nhưng biết đâu được ở đâu đó bạn sẽ chạm trán với nó, vậy thì hãy thử xem qua nó là gì nhé.
Mảng Ba Chiều
Vâng Mảng hai chiều đã đủ làm bạn chóng mặt, nay còn có cái thể loại Mảng ba chiều, thậm chí Mảng bốn chiều,… nhưng khoan khoan… bạn không cần phải dùng đến Mảng nhiều chiều quá vậy đâu, hãy thử xem với Mảng ba chiều thì thao tác trên mảng sẽ như sau, đủ để bạn nản lòng rồi đấy.
int[][][] array3D = new int[4][5][3]; for (int row = 0; row < 4; row++) { for (int col = 0; col < 5; col++) { for (int ver = 0; ver < 3; ver++) { array3D[row][col][ver] = row + col + ver; } } }
Mảng Răng Cưa
Ặc cái thể loại mảng này, mình cũng tránh xa. Cơ bản là mảng này được biểu diễn không “đều”, chẳng hạn như bạn có một Ma trận có m dòng, mà mỗi dòng lại có n cột khác nhau.
int[][] myJaggedArr = { { 3, 4, 5 }, { 77, 50 } }; for (int i = 0; i < myJaggedArr.length; i++) { for (int j = 0; j < myJaggedArr[i].length; j++) { System.out.print(myJaggedArr[i][j] + " "); } System.out.println(); }
Kết Luận
Cuối cùng thì các kiến thức liên quan đến Mảng cũng đã xong, hi vọng các bạn có được một kiến thức vững và tốt để ứng dụng vào các bài học sau của Java, hoặc thực hiện xây dựng một ứng dụng Android của mình dựa trên nền tảng Java này.
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
Bài tiếp theo có kiến thức cũng liên quan đến Mảng, nhưng là Mảng các ký tự, người ta gọi là Chuỗi. Chuỗi có cấu tạo từ Mảng nhưng sẽ được Java ưu ái xây dựng cho Chuỗi các tính năng hấp dẫn, chúng ta cùng xem qua kiến thức về Chuỗi ở bài sau nhé.
Bài Thực Hành Số 2 array [][] hình như code a sai sai cho này
sumRow[r] += myMatrix[r][c]; // 34//
sumColumn[c] += myMatrix[r][c];//51
Wow code mình sai chắc! Thông thường thì mình code và kiểm tra qua trước rồi mới copy/paste vào bài học, nên không hiểu sao vẫn có sai sót chỗ này. Cảm ơn bạn đã chỉ ra chỗ sai nhé, mình sẽ sửa lại code của bài học.
Mình hiểu rồi, do plugin của WordPress không chịu hiển thị nội dung “[c]“, nên những nơi có hiển thị kiểu đó sẽ bị xóa. Nên mình đã thay thế các biến r và c thành ro và co hết rồi. Hehe, dù sao cũng nhờ bạn phát hiện kịp thời, phải tìm plugin khác thôi.
Cảm ơn những bài giảng của anh. Rất là bổ ích cho con đường tự học của em.
Em có thắc mắc chổ này, cho em hỏi phần mảng 2 chiều bài thực hành số 2.
Chổ ” sumColumn[co] += myMatrix[ro][co]; “. Nếu tính tổng cột tại sao lại là myMatrix[ro][co] (giống với tính tổng hàng) mà không phải là myMatrix[co][ro].
Ví dụ : row = 3, columns = 2. myMatrix[3][2]
1 3
2 6
0 5
Nếu tính theo công thức ” sumColumn[co] += myMatrix[ro][co] ” thì em nghĩ nó ra thế này.
sumColum[0] = myMatrix[0][0] + myMatrix[0][1] = 1 + 3
Nhưng mà nếu nhập lên máy thì code theo bài thực hành số 2 của anh là đúng. Vì sao lại như vậy ạ ???
Chào bạn, có thể cách viết của mình gây hiểu lầm. Nếu bạn có cách nào khác tìm ra kết quả đúng mà dễ hiểu hơn thì mình hoan nghênh chia sẻ nhé. Sau đây là ý nghĩa của 2 cách tính sum như sau.
Bạn thấy với chỗ tìm dòng lớn nhất, code sẽ là: sumRow[ro] += myMatrix[ro][co];
Còn chỗ tìm cột lớn nhất, code sẽ là: sumColumn[co] += myMatrix[ro][co];
Vấn đề không phải ở chỗ matrix nên là myMatrix[ro][co] hay myMatrix[co][ro]. Mình luôn cho 2 vòng for chạy để lấy ra từng phần tử của matrix như nhau, chúng luôn là myMatrix[ro][co]. Vậy vấn đề còn lại là ở chỗ dòng cộng dồn vào mảng sumRow hay sumColumn.
Với sumRow, mình dùng biến index để chạy là [ro]. Như vậy việc cộng dồn vào sumRow[ro] sẽ được cộng theo hàng ngang. Còn sumColumn sẽ dùng index [co] nên được cộng dồn theo hàng dọc của matrix. Hãy thử lấy lại ví dụ của bạn.
1 3
2 6
0 5
sumRow[0] = matrix[0][0] + matrix[0][1]
sumColumn[0] = matrix[0][0] + matrix[1][0] + matrix[2][0]
sumRow[1] = matrix[1][0] + matrix[1][1]
sumColumn[1] = matrix[0][1] + matrix[1][1] + matrix[2][1]
mình thực sự chưa tìm được nhiều trang nói về mảng kiểu đối tượng thực sự mình rất muốn biết nhiều về vấn đề này