Java: ArrayList trong Java

Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực

Video hướng dẫn:

Tạo ArrayList

Một trong những nhược điểm lớn của mảng thông thường là kích thước của nó là cố định trong quá trình tạo mảng, rồi sau đó kích thước rất khó được thay đổi trong quá trình thực thi chương trình. Tuy nhiên, đôi khi ta không thể biết chính xác là có bao nhiêu phần tử sẽ được lưu trong mảng. Ví dụ, khi một người đang mua sắm trực tuyến, số lượng các sản phẩm mà sẽ được đưa vào giỏ hàng là không cố định từ đầu. Trong trường hợp này, ta có thể phải tạo một mảng với kích thước lớn nhất có thể để lưu tất cả các sản phẩm mà người dùng muốn mua. Tuy nhiên, nếu người dùng chỉ thêm vào giỏ hàng một vài sản phẩm thì coi như phần còn lại của bộ nhớ sẽ trở thành dư thừa, tức là gây lãng phí, ảnh hưởng đến hiệu năng của chương trình. Tương tự như vậy, nếu người dùng cố gắng thêm thật nhiều sản phẩm vào giỏ hàng dẫn đến vượt quá kích thước mảng thì sẽ phát sinh lỗi. Ngoài ra, việc thêm và bớt phần tử đối với mảng thông thường là một tác vụ khó. Một nhược điểm nữa của mảng là nó chỉ lưa trữ được một kiểu dữ liệu mà thôi.

Để giải quyết những vấn đề trên, thì ta cần phải có một cấu trúc vùng nhớ mà có thể được cấp phát tùy vào yêu cầu thực tế. Ngoài ra, việc thêm và bớt các giá trị cũng cần phải được giải quyết một cách dễ dàng. Java cung cấp khái niệm tập hợp để giải quyết vần đề này.

Một tập hợp là một đối tượng đơn trong đó nhóm nhiều phần tử vào trong một đơn vị. Các tập hợp được dùng để lưu, truy xuất, và thao tác dữ liệu một cách tổng hợp. Thông thường thì các tập hợp sẽ đại diện cho các thành phần dữ liệu tạo thành một nhóm mang tính thực tế tự nhiên, chẳng hạn như tập hợp các thẻ, tập hợp các ký tự, một danh sách các số điện thoại, một danh sách sinh viên.

Java cung cấp các giao diện (interface) tập hợp để tạo ra các loại tập hợp khác nhau. Giao diện cơ bản là là Collection trong đó cho phép thao tác với các loại tập hợp khác nhau như thể hiện ở hình dưới đây.

Core Collection Interfaces
Các giao diện tập hợp cơ bản

Mục đích chính của việc sử dụng từng giao diện tập hợp được thể hiện như bảng dưới đây.

Giao diện Hash table Resizable array Tree Linked list Hash table + Linked list
Set HashSet - TreeSet - LinkedHashSet
List - ArrayList - LinkedList -
Queue - - - - -
Map HashMap - TreeMap - LinkedHashMap

Các khả năng thực thi khác nhau của các loại tập hợp khác nhau có thể được sử dụng trong những tình huống khác nhau. Tuy nhiên, ArrayList, HashSet, và HashMap được sử dụng thường xuyên nhất trong các ứng dụng. Ngoài ra, các giao diện gồm SortedSet và SortedMap không được đưa ra trong bảng liệt kê ở trên vì mỗi loại này có một sự thực thi TreeSet và TreeMap tương ứng được liệt kê trong các hàng Set và Map. Hàng đợi có hai sự thực thi là LinkedList dùng để thực thi List và PriorityQueue không được thể hiện trong bảng. Hai loại thực thi này cung cấp những ý nghĩa rất khác nhau. LinkedList sử dụng thứ tự First In First Out (FIFO), trong khi PriorityQueue lại sắp xếp các phần tử theo giá trị mà chúng chứa.

Mỗi một sự thực thi cung cấp tất cả các hoạt động tùy chọn thể hiện trong giao diện của nó. Tất cả các loại thực thực thi đều chấp nhận các phần tử, khóa và giá trị null. Để sử dụng giao diện thì người dùng phải khai báo gói java.util trong lớp.

Lưu ý: Một gói là một tập hợp các lớp có liên quan. Gói java.util bao gồm một tập hợp tất cả các giao diện và các lớp.

Lớp ArrayList là tập hợp được sử dụng thường xuyên nhất, nó có những đặc điểm sau đây:

- Rất linh hoạt trong việc tăng hoặc giảm kích thước khi cần.

- Cung cấp một số phương thức hữu dụng để thao tác với tập hợp.

- Chèn và xóa dữ liệu dễ dàng.

- Có thể truy xuất bằng cách sử dụng vòng lặp for, vòng lặp for cải tiến, hoặc các loại vòng lặp khác.

ArrayList cung cấp các phương thức để thao tác với kích thước của mảng, nó thừa kế từ AbstractList và thực thi các giao diện như List, Cloneable, và Serializable. Capacity của một ArrayList tăng lên hoặc giảm đi một cách tự động. Nó lưu tất cả các phần tử với các kiểu khác nhau, bao gồm cả null.

Bảng dưới đây trình bày các hàm tạo của ArrayList.

Hàm tạo Mô tả
ArrayList() Tạo một ArrayList rỗng với capacity khởi tạo là 10.
ArrayList(Collection c) Tạo một ArrayList bao gồm các phần tử của tập hợp c
ArrayList(int capacity) Tạo một ArrayList với capacity cho trước. Capacity là kích thước của ArrayList, nó chỉ ra số lượng tối đa mà ArrayList có thể lưu, nhưng nếu kích thước tăng lên vượt quá capacity thì capacity của ArrayList sẽ tự động tăng lên.

ArrayList bao gồm một số phương thức dùng để thêm phần tử. Những phương thức này có thể chia thành các nhóm như sau:

- Các phương thức thêm một hoặc nhiều phần tử vào cuối danh sách.

- Các phương thức chèn một hoặc nhiều phần tử vào mọt vị trí mong muốn trong danh sách.

Các phương thức cơ bản của ArrayList được thể hiện như bảng dưới đây.

Phương thức Mô tả
void add(int index, Object element) Chèn phần tử element vào ArrayList tại vị trí có chỉ số index. Nếu index>=size() hoặc <0 thì phương thức này ném ra ngoại lệ IndexOutOfBoundsException.
boolean add(Object o) Thêm một phần tử vào cuối danh sách.
boolean addAll(Collection c) Thêm tất cả các phần tử của tập hợp c vào cuối danh sách. Nếu c null thì phương thức này sẽ ném ra ngoại lệ NullPointerException.
boolean addAll(int index, Collection c) Chèn tất cả các phần tử của tập hợp c vào vị trí có chỉ số index trong danh sách. Nếu c null thì phương thức ném ra ngoại lệ NullPointerException.
void clear() Xóa tất cả các phần tử khỏi danh sách.
Object clone() Trả về một bản copy của ArrayList hiện thời.
boolean contains(Object o) Trả về true nếu danh sách có chứa phần tử o.
void ensureCapacity(int minCapacity) Thay đổi capacity của ArrayList nếu cần để đảm bảo nó có thể lưu tất cả các phần tử hiện có trong danh sách với capacity nhỏ nhất.
Object get(int index) Trả về phần tử có chỉ số index. Nếu index>=size() hoặc index<0 thì phương thức sẽ ném ngoại lệ
IndexOutOfBoundsException.
int indexOf(Object o) Trả về chỉ số của phần tử o. Nếu không tìm thấy phần tử o thì trả về -1.
int lastIndexOf(Object o) Trả về chỉ số của phần tử o cuối cùng trong danh sách. Nếu không tìm thấy thì trả về -1.
Object remove(int index) Xóa phần tử có chỉ số index. Nếu index >= size() hoặc index < 0 thì ném ra ngoại lệ throws IndexOutOfBoundsException.
protected void removeRange(int fromIndex, int toIndex) Xóa tất cả các phần tử mà có chỉ số nằm trong đoạn [fromIndex,toIndex].
Object set(int index, Object element) Thay phần tử có chỉ số index bằng phần tử element. Nếu index >= size() hoặc index<0 thì ném ra ngoại lệ throws IndexOutOfBoundsException.
int size() Trả về số lượng phần tử có trong danh sách.
Object[] toArray() Xuất ra tất cả các phần tử có trong danh sách. Nếu danh sách null thì ném ngoại lệ NullPointerException.
Object[] toArray(Object[] a) Xuất ra tất cả các phần tử có trong danh sách ra mảng a.
void trimToSize() Đặt capacity bằng với kích thước hiện thời của mảng.

Để truy xuất một ArrayList thì ta có thể sử dụng các cách như sau:

- Vòng lặp for

- Vòng lặp for cải tiến

- Iterator

- ListIterator

Giao diện Iterator cung cấp các phương thức truy xuất một tập dữ liệu. Nó có thể được sử dụng với mảng cũng như lớp của framework Collection. Iterator cung cấp những phương thức truy xuất tập hợp như sau:

- next(): Trả về phần tử tiếp theo của tập hợp.

- hasNext(): Trả về true nếu còn phần tử trong tập hợp.

- remove(): Xóa phần tử tương ứng của tập hợp.

Không có phương thức đặc biệt nào dùng để sắp xếp đối với ArrayList. Tuy nhiên, ta có thể sử dụng phương thức sort() của lớp Collections để sắp xếp. Cú pháp sử dụng phương thức sort() như sau:

Cú pháp:

Collections.sort(<list-name>);

Đoạn mã 1 dưới đây thể hiện việc tạo thể hiện và khởi tạo một ArrayList.

ArrayList marks = new ArrayList(); // Tạo một thể của ArrayList
marks.add(67); // Khởi tạo ArrayList
marks.add(50);

Thao tác với ArrayList

Mỗi ArrayList có thể được truy xuất bằng cách sử dụng vòng lặp for hoặc bằng cách sử dụng giao diện Iterator. Đoạn mã 2 thể hiện việc sử dụng ArrayList có tên marks để thêm và hiển thị điểm của sinh viên.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
public class ArrayLists {
  //tạo một thể hiện của ArrayList
  ArrayList marks = new ArrayList(); // line 1
  //phương thức lưu trữ điểm số vào ArrayList marks
  public void storeMarks() {
    System.out.println("Storing marks. Please wait...");
    marks.add(67); // line 2
    marks.add(50);
    marks.add(45);
    marks.add(75);
  }
  //phương thức hiển thị điểm số
  public void displayMarks() {
    System.out.println("Marks are:");
    //dùng vòng lặp for để truy xuất các phần tử
    System.out.println("Iterating ArrayList using for loop:");
    for (int i = 0; i < marks.size(); i++) {
      System.out.println(marks.get(i));
    }
    System.out.println("-------------------------------------");
    //dùng giao diện Iterator để truy xuất ArrayList
    Iterator imarks = marks.iterator(); // line 3
    System.out.println("Iterating ArrayList using Iterator:");
    while (imarks.hasNext()) { // line 4
      System.out.println(imarks.next()); // line 5
    }
    System.out.println("-------------------------------------");
    //sắp xếp danh sách bằng cách dùng phương thức sort() của lớp Collections
    Collections.sort(marks); // line 6
    System.out.println("Sorted list is: " + marks);
  }
  public static void main(String[] args) {
    ArrayLists obj = new ArrayLists(); // line 7    
    obj.storeMarks();
    obj.displayMarks();
  }
}

Phân tích đoạn mã:

ArrayList có tên marks được tạo ở line 1. Phương thức storeMarks() được dùng để thêm các phần tử vào tập hợp bằng cách sử dụng phương thức barks.add() như line 2.

Trong phương thức displayMarks() co một vòng lặp for được sử dụng để truy xuất ArrayList marks từ phần tử có chỉ số 0 đến marks.size(). Phương thức get() được dùng để truy xuất phần tử có chỉ số i.

Tương tự như vậy, đối tượng có kiểu Iterator là imarks được tạo ra ở line 3 và gắn với marks thông qua việc sử dụng phưng thức marks.iterator(). Nó được sử dụng để lấy các phần tử của tập hợp. Giao diện Iterator cung cấp phương thức hasNext() để kiểm tra xem có còn phần tử nào trong tâp hợp nữa không thông qua line 4. Phương thức next() được dùng để truy xuất phần tử tiếp theo trong tập hợp. Phần tử đã được truy xuất sẽ được hiển thị ra console tại line 5.

Phương thức tĩnh sort() của lớp Collections được dùng để sắp xếp ArrayList marks như ở line 6 và in các giá trị ra màn hình. Trong phương thức main() thì đối tượng của lớp ArrayLists được tạo tại line 7 và các phương thức storeMarks() và displayMarks() được gọi.

Output của đoạn mã trên như sau:

output-demo-tuong-tac-voi-arraylist

Các giá trị của một ArrayList cũng có thể được in ra bằng cách đơn giản là viết System.out.println("Marks are:"+ marks). Trong trường hợp ví dụ trên thì output sẽ là: Marks are:[67, 50, 45, 75].

Xem thêm:

» Tiếp: Quản lý bộ nhớ trong Java
« Trước: Hàm (Function)
Các khóa học qua video:
Python SQL Server PHP C# Lập trình C Java HTML5-CSS3-JavaScript
Học trên YouTube <76K/tháng. Đăng ký Hội viên
Viết nhanh hơn - Học tốt hơn
Giải phóng thời gian, khai phóng năng lực
Copied !!!