Mảng trong Java

Trong phần này của seri hướng lập trình Java Core, chúng ta sẽ cover mảng. Mảng là một đối tượng container chứa một số cố định các giá trị của cùng 1 kiểu dữ liệu. Chiều dài của một mảng được thiết lập khi mảng được tạo ra. Sau khi mảng được khai báo, chiều dài của nó là cố định.

Một biến chỉ giữ một 1 giá trị tại 1 thời điểm. Trong khi đó, mảng có thể chứa giá trị tại cùng 1 thời điểm. Các mục này được gọi là các phần tử của mảng. Mảng lưu trữ dữ liệu của cùng một loại dữ liệu. Mỗi phần tử có thể được chỉ dẫn bởi một chỉ mục. Chỉ số của phần tử đầu tiên bằng 0.

Khai báo mảng trong Java

Mảng được sử dụng để lưu trữ dữ liệu của các ứng dụng. Chúng ta khai báo mảng với 1 kiểu dữ liệu nhất định và chỉ định kích thước cho mảng và khởi tạo mảng với dữ liệu. Chúng ta có một số phương thức để làm việc với mảng như: sửa đổi các phần tử, sắp xếp chúng, sao chép chúng hoặc tìm kiếm.

int[] ages;
String[] names;
float[] weights;

Chúng ta có ba khai báo mảng. Khai báo bao gồm hai phần: kiểu dữ liệu và tên mảng. Kiểu dữ liệu mảng là kiểu dữ liệu nguyên thủy (int, float, long) hoặc các object và một cặp dấu ngoặc vuông []. Dấu ngoặc chỉ ra rằng chúng ta có một mảng.

Collection có chức năng tương tự như mảng. Nhưng có powerfull hơn mảng. Chúng ta sẽ thảo luận ở chương sau.

Khởi tạo mảng trong Java

Có một số cách để chúng ta có thể khởi tạo một mảng trong Java. Trong ví dụ đầu tiên, một mảng được tạo ra và khởi tạo theo hai bước.

InitArray.java

package net.vncoding;

import java.util.Arrays;

public class InitArray {

    public static void main(String[] args) {
        
        int[] a = new int[5];

        a[0] = 1;
        a[1] = 2;
        a[2] = 3;
        a[3] = 4;
        a[4] = 5;

        System.out.println(Arrays.toString(a));        
    }
}

Chúng ta tạo và khởi tạo một mảng số. Nội dung của mảng được in màn hình console.

int[] a = new int[5];

Ở đây chúng ta tạo ra một mảng có thể chứa năm phần tử. Câu lệnh cấp phát memory cho năm số nguyên. Dấu ngoặc vuông được sử dụng để khai báo một mảng, kiểu dữ liệu(int) cho chúng ta biết loại giá trị mảng sẽ lưu giữ. Một mảng là một đối tượng và do đó nó được tạo bằng toán tử new.

a[0] = 1;
a[1] = 2;
a[2] = 3;
a[3] = 4;
a[4] = 5;

Khởi tạo mảng với một số dữ liệu bằng phép gán. Các chỉ mục nằm trong dấu ngoặc vuông. 1 sẽ là phần tử đầu tiên của mảng, số 2 là phần tử thứ 2 …

System.out.println(Arrays.toString(a));  

Class Array có nhiều phương thức để thao tác xử lí các mảng. Phương thức toString() trả về một biểu diễn chuỗi nội dung của mảng được chỉ định. Phương pháp này hữu ích khi debug.

Kết quả:
[1, 2, 3, 4, 5]

Tiếp theo là ví dụ, khởi tạo mảng trong 1 dòng code.
InitArray2.java

package net.vncoding;

import java.util.Arrays;

public class InitArray2 {

    public static void main(String[] args) {

        int[] a = new int[] { 2, 4, 5, 6, 7, 3, 2 };

        System.out.println(Arrays.toString(a));
    }
}
int[] array = new int[] { 2, 4, 5, 6, 7, 3, 2 };

Một mảng được tạo ra và khởi tạo trong một bước. Giá trị khởi tạo được đặt trong ngoặc nhọn, không cần chỉ định chiều dài của mảng vì trình biên dịch sẽ làm điều đó cho chúng ta.

Tiếp theo, cách khởi tạo mảng trong 1 bước đơn giản hơn cách trên.
InitArray3.java

package net.vncoding;

import java.util.Arrays;

public class InitArray3 {

    public static void main(String[] args) {

        int[] a = { 2, 4, 5, 6, 7, 3, 2 };

        System.out.println(Arrays.toString(a));
    }
}

Đây là cách đơn giản nhất khai báo và khởi tạo mảng trong Java.

int[] a = { 2, 4, 5, 6, 7, 3, 2 };

Câu lệnh khởi tạo new int[] có thể được bỏ qua. Bên phải phép gán là các giá trị khởi tạo. Nó gần giống với style khởi tạo mảng trong C/C++. Thậm chị chúng ta bỏ từ khóa new, mảng được tạo tương tự như trong 2 ví dụ trước.

Truy cập tới phần tử của mảng

Sau khi mảng được tạo, các phần tử của nó có thể được truy cập bằng chỉ mục của chúng. Chỉ mục là một số được đặt bên trong dấu ngoặc vuông đi theo tên mảng.

AccessingElements.java

package net.vncoding;

public class AccessingElements {

    public static void main(String[] args) {
        
        String[] names = {"C/C++", "Java", "C#", "Python"};
        
        System.out.println(names[0]);
        System.out.println(names[1]);
        System.out.println(names[2]);
        System.out.println(names[3]);    
    }
}

Trong ví dụ, chúng ta tạo một mảng các chuỗi. Truy cập vào từng chuỗi bằng chỉ mục và in chuỗi ra màn hình console.

String[] names = {"C/C++", "Java", "C#", "Python"};

Mảng các chuỗi được khai báo và khởi tạo.

System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);  

In các chuỗi ra màn hinh console.

Kết quả:
C/C++
Java
C#
Python

Chúng ta có thể thay đổi giá trị của các phần tử trong mảng.

AccessingElements2.java

package net.vncoding;

import java.util.Arrays;

public class AccessingElements2 {

    public static void main(String[] args) {
        
        int[] vals = { 1, 2, 3 };
        
        vals[0] *= 2;
        vals[1] *= 2;
        vals[2] *= 2;
        
        System.out.println(Arrays.toString(vals));    
    }
}

Chúng ta có một mảng ba số nguyên. Mỗi giá trị sẽ được nhân với hai.

int[] vals = { 1, 2, 3 };

Khai báo và khởi tạo mảng số nguyên 3 phần tử.

vals[0] *= 2;
vals[1] *= 2;
vals[2] *= 2;

Truy cập vào các phần tử và nhân mỗi phần tử với 2.

Kết quả:
[2, 4, 6]

Duyệt mảng trong Java

Trong mục này, giới thiệu các bạn cách duyệt mảng trong Java

TraversingArrays.java

package net.vncoding;

public class TraversingArrays {

    public static void main(String[] args) {
        
        String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter", 
            "Saturn", "Uranus", "Neptune", "Pluto" };
        
        for (int i=0; i < planets.length; i++) {
            
            System.out.println(planets[i]);
        }
        
        for (String planet : planets) {
            
            System.out.println(planet);
        }
    }
}

Mảng chứa tên các hành tinh được khởi tạo. Sử dụng vòng lặp for để duyệt mảng và in chuỗi kí tự ra màn hình console.

for (int i=0; i < planets.length; i++) {
    
    System.out.println(planets[i]);
}

Sử dụng thuộc tính length để lấy kích thước của mảng. In phần tử của mảng theo chỉ số.

for (String planet : planets) {
    
    System.out.println(planet);
}

Vòng lặp for được cải tiến, giúp làm đơn giản cách viết. Tại mỗi lần của vòng lặp, biến planet chứa giá trị của chuỗi trong mảng.

Truyền mảng cho phương thức

Ví dụ sau minh họa việc truyền mảng cho phương thức.
PassingArrays.java

package net.vncoding;

import java.util.Arrays;

public class PassingArray {

    public static void main(String[] args) {
        
        int[] a = { 3, 4, 5, 6, 7 };
        int[] r = reverseArray(a);
        
        System.out.println(Arrays.toString(a));
        System.out.println(Arrays.toString(r));
    }
    
    private static int[] reverseArray(int[] b) {
        
        int[] c = new int[b.length];
        
        for (int i=b.length-1, j=0; i>=0; i--, j++) {
            
            c[j] = b[i];
        }
        
        return c;
    }
}

Đoạn code tạo ra mảng với các phần tử đảo ngược bằng việc gọi phương thức reverseArray().

private static int[] reverseArray(int[] b) {

Phương thức nhận mảng b làm tham số đầu vào và trả về mảng số nguyên. Phương thức lấy bản copy của mảng truyền vào. Nghĩa là phương thức reverseArray() không thay đổi được giá trị của mảng truyền vào.

int[] c = new int[b.length];

Trong body của phương thức reverseArray(), 1 mảng mới được tạo với kích thước bằng kích thước mảng đầu vào.

for (int i=b.length-1, j=0; i>=0; i--, j++) {
    
    c[j] = b[i];
}

Trong thân vòng lặp for, gán giá trị mảng đầu vào b cho mảng mới tạo c theo chiều đảo ngược.

return c;

Trả về mảng mới với các phần tử được sắp xếp đảo ngược so sanh với mảng đầu vào.

System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(r));

In ra màn hình console mảng đầu vào a và mảng đảo ngược c.

Kết quả:
[3, 4, 5, 6, 7] [7, 6, 5, 4, 3]

Mảng nhiều chiều

Chúng ta đã tìm hiểu mảng một chiều. Trong Java, chúng ta có thể tạo các mảng nhiều chiều. Một mảng nhiều chiều là mảng của các mảng. Trong mảng nhiều chiều đó, các phần tử là các mảng. Trong mảng nhiều chiều, chúng ta sử dụng hai hoặc nhiều tập ngoặc đơn.

TwoDimensions.java

package net.vncoding;

public class TwoDimensions {

    public static void main(String[] args) {
        
        int[][] twodim = new int[][] { {1, 2, 3}, {1, 2, 3} };

        int d1 = twodim.length;
        int d2 = twodim[1].length;

        for (int i = 0; i < d1; i++) {
            
            for (int j = 0; j < d2; j++) {
                
                System.out.println(twodim[i][j]);
            }
        }
    }
}

Trong ví dụ, chúng ta tạo mảng 2 chiều số nguyên.

int[][] twodim = new int[][] { {1, 2, 3}, {1, 2, 3} };

Khai báo mảng 2 chiều sử dụng 2 dấu ngoặc vuông [], tương ứng phần giá trị khởi tạo có 2 phần nằm trong dấu ngoặc {}

int d1 = twodim.length;
int d2 = twodim[1].length;

Dòng lệnh thứ 1 xác định kích thước hàng của mảng.
Dòng lệnh thứ 2 xác định kích thước mảng con

for (int i = 0; i < d1; i++) {
    
    for (int j = 0; j < d2; j++) {
        
        System.out.println(twodim[i][j]);
    }
}

2 vòng lặp in toàn bộ 6 phần tử của mảng. i là chỉ số dòng, j chỉ số cột. Mảng 2 chiều gồm có 2 dòng và 3 cột.

Kết quả:
1
2
3
1
2
3

Tiếp theo, chúng ta đến với ví dụ minh họa khai báo và sử dụng mảng 3 chiều.

ThreeDimensions.java

package net.vncoding;

public class ThreeDimensions {

    public static void main(String[] args) {
        
        int[][][] n3 = {
            {{12, 2, 8}, {0, 2, 1}},
            {{14, 5, 2}, {0, 5, 4}},
            {{3, 26, 9}, {8, 7, 1}},
            {{4, 11, 2}, {0, 9, 6}}
        };

        int d1 = n3.length;
        int d2 = n3[0].length;
        int d3 = n3[0][0].length;

        for (int i = 0; i < d1; i++) {
            
            for (int j = 0; j < d2; j++) {
                
                for (int k = 0; k < d3; k++) {
                    
                    System.out.print(n3[i][j][k] + " ");
                }
            }
        }

        System.out.print('\n');
    }
}

Mảng 3 chiều được khai báo với 3 dấu ngoặc vuông [], tương ứng giá trị khởi tạo được đặt trong 3 cặp dấu {}

int[][][] n3 = {
    {{12, 2, 8}, {0, 2, 1}},
    {{14, 5, 2}, {0, 5, 4}},
    {{3, 26, 9}, {8, 7, 1}},
    {{4, 11, 2}, {0, 9, 6}}
};

Mảng 3 chiều n3 được khai báo và khởi tạo.

int d1 = n3.length;
int d2 = n3[0].length;
int d3 = n3[0][0].length;

Lấy 3 kích thước của mảng

for (int i = 0; i < d1; i++) {
    
    for (int j = 0; j < d2; j++) {
        
        for (int k = 0; k < d3; k++) {
            
            System.out.print(n3[i][j][k] + " ");
        }
    }
}

Dùng vòng lặp for duyệt mảng, in phần tử ra màn hình console.

Kết quả:
12 2 8 0 2 1 14 5 2 0 5 4 3 26 9 8 7 1 4 11 2 0 9 6

Mảng bất thường trong Java

Mảng nhiều chiều có đầy đủ các phần tử được gọi làm mảng hình chữ nhật. Chúng ta có thể tạo mảng nhiều chiều có kích thước khác nhau được gọi là mảng bất thường. Trong C# gọi là mảng rách (jagged array).

IrregularArrays.java

package net.vncoding;

public class IrregularArrays {

    public static void main(String[] args) {
        
        int[][] ir = new int[][] {
            {1, 2},
            {1, 2, 3},
            {1, 2, 3, 4}
        };

        for (int[] a : ir) {
            for (int e : a) {
                System.out.print(e + " ");
            }
        }

        System.out.print('\n');
    }
}

Đây là ví dụ mảng bất thường.

int[][] ir = new int[][] {
    {1, 2},
    {1, 2, 3},
    {1, 2, 3, 4}
};

Đây là khai báo và khởi tạo một mảng bất thường. Ba mảng bên trong có 2, 3 và 4 phần tử.

for (int[] a : ir) {
    for (int e : a) {
        System.out.print(e + " ");
    }
}

Duyệt mảng bằng vòng for cải tiến.

Kết quả:
1 2 1 2 3 1 2 3 4

Phương thức xử lý mảng

Class Array có sẵn trong gói java.util có các phương thức để làm việc với mảng. Các phương pháp này có thể được sử dụng để sửa đổi, phân loại, sao chép hoặc tìm kiếm dữ liệu. Những phương pháp mà chúng ta sử dụng là các phương thức tĩnh của class Array. (Các phương thức tĩnh là các phương thức có thể được gọi mà không cần tạo ra một object)

ArrayMethods.java

package net.vncoding;

import java.util.Arrays;

public class ArrayMethods {

    public static void main(String[] args) {
        
        int[] a = {5, 2, 4, 3, 1};
        
        Arrays.sort(a);
        
        System.out.println(Arrays.toString(a));
        
        Arrays.fill(a, 8);
        System.out.println(Arrays.toString(a));
        
        int[] b = Arrays.copyOf(a, 5);
        
        if (Arrays.equals(a, b)) {

            System.out.println("Arrays a, b are equal");
        } else {

            System.out.println("Arrays a, b are not equal");
        }                    
    }
}

Ví dụ minh họa 5 phương thức xử lí mảng trong class Array.

import java.util.Arrays;

Chúng ta sẽ sử dụng kí hiệu viết tắt cho lớp Array.

int[] a = {5, 2, 4, 3, 1};

Khai báo mảng 5 số nguyên.

Arrays.sort(a);

Phương thức sort() sắp xếp mảng theo thứ tự tăng dần.

System.out.println(Arrays.toString(a));

Phương thức toString() trả về chuỗi chứa các phần tử của mảng.

Arrays.fill(a, 8);

Phương thức fill () gán giá trị số nguyên cho mỗi phần tử của mảng.

int[] b = Arrays.copyOf(a, 5);

Phương thức copyOf() sao chép số lượng các phần tử được chỉ định vào một mảng mới.

if (Arrays.equals(a, b)) {

    System.out.println("Arrays a, b are equal");
} else {

    System.out.println("Arrays a, b are not equal");
} 

Phương thức equals() so sánh hai mảng. Hai mảng bằng nhau nếu chúng chứa các phần tử giống nhau theo cùng một thứ tự.

Kết quả:
[1, 2, 3, 4, 5] [8, 8, 8, 8, 8] Arrays a, b are equal

So sánh mảng

Có hai phương pháp để so sánh các mảng. Phương thức equals() và phương thức deepEquals(). Phương thức deepEquals() cũng so sánh tham chiếu tới mảng bên trong mảng.

ComparingArrays.java

package net.vncoding;
import java.util.Arrays;

public class ComparingArrays {

    public static void main(String[] args) {
        
        int[] a = {1, 1, 2, 1, 1};
        int[] b = {0, 0, 3, 0, 0};
        
        int[][] c = {
            {1, 1, 2, 1, 1},
            {0, 0, 3, 0, 0}
        };
        
        int[][] d = {
            a,
            b
        };       
        
        System.out.print("equals() method: ");
        
        if (Arrays.equals(c, d)) {

            System.out.println("Arrays c, d are equal");
        } else {

            System.out.println("Arrays c, d are not equal");
        }      
        
        System.out.print("deepEquals() method: ");
        
        if (Arrays.deepEquals(c, d)) {

            System.out.println("Arrays c, d are equal");
        } else {

            System.out.println("Arrays c, d are not equal");
        }            
    }
}

Ví dụ sẽ chỉ ra sự khách nhau giữa 2 phương thức equals() và deepEquals().

int[] a = {1, 1, 2, 1, 1};
int[] b = {0, 0, 3, 0, 0};

Khai báo và khởi tạo 2 mảng 1 chiều số nguyên.

int[][] c = {
    {1, 1, 2, 1, 1},
    {0, 0, 3, 0, 0}
};

Khai báo mảng 2 chiều số nguyên. Số lượng phần tử trong mảng con (inner array) của mảng c bằng số lượng phần tử mảng a và b.

int[][] d = {
    a,
    b
};

Mảng 2 chiều số nguyên d chứa tham chiếu tới mảng 1 chiều a và b.

System.out.print("equals() method: ");

if (Arrays.equals(c, d)) {

    System.out.println("Arrays c, d are equal");
} else {

    System.out.println("Arrays c, d are not equal");
}      

System.out.print("deepEquals() method: ");

if (Arrays.deepEquals(c, d)) {

    System.out.println("Arrays c, d are equal");
} else {

    System.out.println("Arrays c, d are not equal");
} 

Mảng c và d được so sánh bằng cả hai phương pháp. Đối với phương thức equals(), 2 mảng không bằng nhau. Phương thức deepEquals() đi sâu hơn vào các mảng tham chiếu và lấy ra các phần tử của chúng để so sánh. Đối với phương pháp này, các mảng c và d đều bằng nhau.

Kết quả:
equals() method: Arrays c, d are not equal
deepEquals() method: Arrays c, d are equal

Tìm kiếm phần tử trong mảng

Lớp Arrays có một phương thức đơn giản để tìm kiếm các phần tử trong một mảng. Nó được gọi là binarySearch(). Phương thức tìm kiếm các phần tử sử dụng thuật toán tìm kiếm nhị phân. Phương thức binarySearch() chỉ hoạt động trên các mảng được sắp xếp.

Searching.java

package net.vncoding;
import java.util.Arrays;


public class Searching {

    public static void main(String[] args) {
        
        String[] planets = { "Mercury", "Venus", "Mars", "Earth", "Jupiter", 
            "Saturn", "Uranus", "Neptune", "Pluto" };
        
        Arrays.sort(planets);
        
        String p = "Earth";
               
        int r = Arrays.binarySearch(planets, p);
        
        String msg;
        
        if (r >= 0) {
            msg = String.format("%s was found at position %d of the "
                    + "sorted array", p, r);            
        } else {
            msg = p + " was not found";
        }              
        
        System.out.println(msg);    
    }
}

Trong ví dụ, tìm kiếm chuỗi “Earth” trong mảng các chuỗi.

Arrays.sort(planets);

Vì phương thức tìm kiếm nhị phân chỉ hoạt động trên mảng đã được sắp xếp. Do vậy, trước tiên chúng ta phải sắp xếp mảng.

String p = "Earth";

Khai báo chuỗi “Earth” cần tìm kiếm.

int r = Arrays.binarySearch(planets, p);

Phương thức binarySearch() được gọi. Tham số đầu tiên là tên mảng, thứ hai là phần tử chúng ta cần tìm kiếm. Nếu phần tử được tìm thấy, giá trị trả về lớn hơn hoặc bằng không. Đó là chỉ mục của phần tử trong mảng được sắp xếp.

if (r >= 0) {
    msg = String.format("%s was found at position %d of the "
            + "sorted array", p, r);            
} else {
    msg = p + " was not found";
}  

Kiểm tra giá trị trả về, để quyết định in ra màn hình console message tương ứng.

Kết quả:
Earth was found at position 0 of the sorted array

Trong phần này của hướng dẫn Java, chúng ta đã thảo luận về mảng, mô tả cách khởi tạo các mảng, truy cập các phần tử mảng, duyệt mảng, làm việc với mảng nhiều chiều, so sánh mảng và tìm kiếm các phần tử mảng.

Be the first to comment

Leave a Reply