Hướng dẫn sử dụng nền tảng tập hợp trong Java (Java Collection Framework)
Công ty Vĩnh Cửu tuyển dụng lập trình viên Java

1- Giới thiệu

Tập hợp chính là một ý tưởng cơ bản của chương trình và của ngôn ngữ .Một ứng dụng thường xuyên phải làm việc với tập hợp ví dụ như việc lưu trữ thông tin các nhân viên ,tập hợp các ảnh ,...Java cũng như các ngôn ngữ khác hỗ trợ mảng (array) như một tập hợp cơ bản nhất ,xong việc làm việc với mảng là không thuận tiện trong nhiều trường hợp bởi vì trong thời gian sống của mảng việc tăng thêm phần tử hoặc xóa các phần tử của mảng rất khó khăn và phải trả giá đắt về hiệu năng chương trình nếu cố tình làm điều đó .
Hình minh họa một mảng:

2- Ví dụ bắt đầu

Trước hết chúng ta làm một ví dụ với LinkedList, nó là một danh sách mà số phần tử có thể thay đổi, không bị giới hạn như mảng.
HelloLinkedList.java
package org.o7planning.tutorial.javacollection.helloworld;

import java.util.LinkedList;

public class HelloLinkedList {

   public static void main(String[] args) {

       // Tạo một đối tượng tập hợp - LinkedList
       LinkedList<String> list = new LinkedList<String>();

       // Thêm một số phần tử vào danh sách
       list.add("F");
       list.add("B");
       list.add("D");
       list.add("E");
       list.add("C");
       // Thêm phần tử vào cuối danh sách.
       list.addLast("Z");
       // Thêm phần tử vào đầu danh sách
       list.addFirst("A");
       // Thêm phần tử vào ví trí có chỉ số 1.
       list.add(1, "A2");
       
       // Ghi ra danh sách:
       System.out.println("Original contents of list: " + list);


       // Xóa phần tử khỏi danh sách
       list.remove("F");
       // Xóa phần tử tại vị trí có chỉ số 2.
       list.remove(2);
       
       // In ra danh sách sau khi đã xóa 2 phần tử.
       System.out.println("Contents of list after deletion: " + list);


       // Xóa phần tử đầu tiên và cuối cùng trong danh sách.
       list.removeFirst();
       list.removeLast();
       
       // In ra danh sách sau khi đã xóa
       System.out.println("List after deleting first and last: " + list);

   
       Object val = list.get(2);
       // Sét đặt lại phần tử tại vị trí có chỉ số 2.
       list.set(2, (String) val + " Changed");
       System.out.println("List after change: " + list);
   }

}
Kết quả chạy ví dụ:
Ví dụ với HashMap. Đây là một đối tượng chứa các cặp khóa và giá trị (Key-Value). Chẳng hạn như một danh bạ điện thoại, trong đó số điện thoại là khóa, còn thông tin chủ thuê bao là giá trị. Các khóa thì không được trùng nhau.
HelloHashMap.java
package org.o7planning.tutorial.javacollection.helloworld;

import java.util.HashMap;

public class HelloHashMap {

   public static void main(String[] args) {

       // Tạo một đối tượng HashMap lữu trữ mã số nhân viên và tiền lương.
       // String key: Mã số nhân viên
       // Float value: Tiền lương.
       HashMap<String, Float> salaryMap = new HashMap<String, Float>();
   

       salaryMap.put("E01", 1000f);
       salaryMap.put("E02", 12000f);
       salaryMap.put("E03", 12300f);
       salaryMap.put("E04", 1000f);
       salaryMap.put("E05", 300.5f);
       
       // Lấy ra tiền lương của nhân viên 'E02'
       Float salary= salaryMap.get("E01");
       System.out.println("Salary of employee E01 = "+ salary);
       
       // Thay đổi tiền lương cho nhân viên 'E05'
       salaryMap.put("E05", 400f);
       
       System.out.println("Salary of employee E05 = "+ salaryMap.get("E05"));
       
   }

}
Kết quả chạy ví dụ:

3- Các giới hạn của việc sử dụng mảng - Một gợi ý giải quyết vấn đề.

3.1- Mảng - một kiểu tập hợp cơ bản.

  • Mảng rất cơ bản và quen thuộc .
    • lưu trữ các kiểu tham chiếu , các kiểu nguyên thủy
    • int[] myArray=new int[]{1,4,3};
    • Object[] myArrayObj =new Object[]{"Object",new Integer(100)};
  • Mảng có kích cỡ và số chiều cố định.
    • Khó khăn cho việc mở rộng mảng
  • Các phần tử được đặt và tham chiếu một cách liên tiếp nhau trong bộ nhớ.
    • Khó khăn cho việc xóa một phần tử ra khỏi mảng .

3.2- Xóa phần tử ra khỏi mảng

Các phần tử của một mảng là được đặt và tham chiếu liên tiếp nhau trong bộ nhớ điều đó là khó khăn khi bạn cố tình bỏ đi một phần tử nào đó trong mảng, nó mất tính liên tiếp .Thông thường một kỹ thuật mà thường sử dụng là tạo một mảng mới lưu trữ các đối tượng của mảng ban đầu và bỏ đi các phần tử không cần thiết điều này làm giảm hiệu năng của chương trình. Với trường hợp mở rộng mảng cũng với kỹ thuật tương tự là khởi tạo một mảng mới với kích cỡ lớn hơn sau đó thì copy các phần tử mảng cũ cho mảng mới .
Rõ ràng mảng không phải là một cách tốt cho nhiều trường hợp của ứng dụng .

3.3- Danh sách có kết nối

Danh sách được kết nối (Linked List) là một trong các cách quản lý danh sách dữ liệu khắc phục được các nhược điểm của mảng. Tất nhiên để quản lý danh sách trong Java có nhiều cách khác ví dụ ArrayList.

Hãy xem các đặc điểm của LinkedList:
  • Các phần tử trong danh sách này có thể nằm cách ly nhau (không liên tục) trong bộ nhớ .
  • Nó thực sự là một liên kết có tính hai chiều giữa các phần tử.
    • Mỗi phần tử trong danh sách cầm giữ một tham chiếu đến đối phần tử đằng trước nó và tham chiếu đến phần tử ngay sau nó.
LinkedList thực sự là một liên kết 2 chiều.
Phần tử Link là một đối tượng nó chứa dữ liệu bạn cần quản lý (data), và nó có 2 tham chiếu tới phần tử Link phía trước và phần tử Link phía sau nó. 

Cũng giống như một nhóm người xếp hàng, mỗi người chỉ cần nhớ người đứng trước họ là ai, và người đứng sau họ là ai.

Xóa một phần tử ra khỏi LinkedList

Xóa một phần tử ra khỏi LinkedList cũng giống bỏ một người ra khỏi hàng đang sắp xếp, hai người đứng gần người này phải cập nhập lại thông tin người đứng trước, đứng sau họ là ai.

Thêm phần tử vào linkedList (Thêm vào cuối hoặc trèn vào giữa danh sách)
Như vậy mặc dù ta chỉ đưa ra một ví dụ về danh sách được liên kết xong nó cũng làm chúng ta hiểu hơn về bó java.util.

Chú ý: LinkedList là một trong các giải pháp giải quyết hạn chế của mảng, ArrayList cũng là cách quản lý tập hợp dữ liệu, giải quyết được các hạn chế của mảng, nhưng cách thức quản lý dữ liệu của nó khác.

4- Tổng quan về Java Collections Framework

Thấy được các giới hạn của mảng ngay từ phiên bản 1.0 java đã đưa vào class java.util.Vector một class lưu trữ danh sách động của các đối tượng .Và java.util.Hashtable là class lưu trữ các cặp key/value (khóa/giá trị) .Sau đó Java2 platform tiếp tục giới thiệu các cách tiếp cận các tập hợp , được gọi là Collections Framework (Nền tảng các tập hợp) . java.util.Vector, java.util.Hashtable vẫn tồn tại và bây giờ là một phần trong nền tảng lớn đó.Các kiểu tập hợp này được xây dựng trên cơ sở một số interface trong bó java.util .Và được phân chia ra làm 2 hệ thống phân cấp dẫn đầu bởi 2 interface java.util.Collection chứa danh sách các đối tượng và java.util.Map chứa các cặp key/value.

4.1- Các interface nền tảng cho các kiểu tập hợp (Java Collections Framework)

Hình trên là các interface quan trọng của Java Collections Framework.Chúng ta sẽ nói về mục đích sử dụng của các interface đó và phân chia chúng theo mục đích và cách sử dụng.Trong bó java.util các class thi hành một hoặc nhiều interface này. Chính vì vậy một class nào đó trong java.util có thể có nhiều tính năng khác nhau .Ví dụ java.util.HashMap:
  • Class Hashtable:

public class HashMap<K,V> extends AbstractMap<K,V>
                           implements Map<K,V>, Cloneable, Serializable
  • Class Vector:
public class Vector<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, Serializable

4.2- Hai hệ thống phân cấp dẫn đầu bởi 2 interface Collection và Map - Cách thức chứa dữ liệu

  • Nhóm Collection lưu trữ các đối tượng. 
    • Có 3 nhánh con trong nhóm Collection: Queue, List, Set .
    • Các phần tử có thể giống nhau hoặc không phụ thuộc vào thuộc nhánh nào trong 3 nhánh kể trên. (Sẽ được nói đến sau) .
  • Nhóm Map lưu trữ các cặp key/value
    • Các cặp key/value chứa trong Map (bản đồ) là luôn có key khác nhau giữa các cặp
    • Nếu biết key có thể lấy ra giá trị value trong Map ứng với key này .
Nhóm Collection lưu trữ các dữ liệu là các kiểu tham chiếu, nhóm Map lưu trữ các cặp key/value.
Collection<String> c=new ArrayList<String>();
// Thêm phần tử vào tập hợp
c.add("One");


Map<Integer,String> m=new LinkedHashMap<Integer,String>();
Integer key=new Integer(123);
String value="One two three";
// Thêm một cặp key/value vao Map m
// Nếu key đã có, value sẽ được thay bởi giá trị mới.
m.put(key,value);

// In ra giá trị ứng với khóa
System.out.println(m.get(new Integer(123));

4.3- Interface Iterator và interface RandomAccess - Cách thức lấy dữ liệu

  • java.util.Iterator
    • Giống như một máy lặp để lấy dữ liệu,cách truy cập lần lượt từ phần tử này đến phần tử khác.
  • java.util.RandomAccess
    • Cách truy cập ngẫu nhiên, ví dụ cho vị trí phần tử và lấy ra phần tử đó trong tập hợp
    •  Ví dụ java.util.Vector thi hành interface này có thể lấy phần tử ngẫu nhiên vector.get(int index).
  • Nhóm Collection cũng có thể truy cập theo kiểu lần lượt bằng cách gọi method iterator() để lấy được đối tượng Iterator .
    • java.util.Collection mở rộng từ interface java.lang.Iterable (có thể lặp được) do đó nó thừa kế phương thức public Iterator<E> iterator(), bộ lặp Iterator chứa các phần tử của Collection .
Trên hình minh họa trên có 2 Interface Iterator & RandomAccess, nó đại diện cho 2 cách truy cập vào các phần tử trong một tập hợp.
Xem class Vector:
Vector class
public class Vector<E> extends AbstractList<E>
               implements List<E>, RandomAccess, Cloneable, Serializable
 
Theo trên Vector thuộc nhóm Collection, bạn có thể truy cập các phần tử của nó thông qua Iterator và cũng có thể truy cập ngẫu nhiên thông qua method get(index).

Chú ý: Đối với các đối tượng trong nhóm List bạn cũng có thể lấy ra đối tượng ListIterator, bộ lặp này cho phép bạn lùi và tiến vị trí con trỏ trên tập hợp thay vì chỉ có thể tiến như của Iterator.

5- Nhóm Collection

5.1- Các interface trong nhóm Collection

3 interface con trực tiếp của CollectionQueue, List, Set trong đó Queue được đưa vào từ phiên bản 1.5 nó có ý nghĩa như một hàng đợi. Queue cũng có interface con là BlockingQueue xong interface này nằm trong bó java.util.concurrent , trong bài này ta không nói đến. Queue là một interface có nhiều khái niệm và cách thức tổ chức các phần tử đáng phải quan tâm nhiều nhất. Ba interface Queue , List , Set có thể coi là 3 nhánh trong nhóm Collection , trước khi đi vào chi tiết từng nhóm bạn hãy xem tổng quan về interface Collection.

5.2- Interface java.util.Collection

Quan hệ thừa kế:
  • java.util.Collection
public interface Collection<E> extends java.lang.Iterable<E> {

   //
   // Thêm một phần tử vào Collection trả về true nếu Collection thay đổi sau
   // khi gọi method và trả về false nếu Collection này không cho phép trùng
   // lặp và E o đã có trong Collection rồi (optional operation).
   //
   boolean add(E o);

   //
   // Thêm tập hợp vào Collection ,trả về true nếu thực sự Collection thay đổi
   // sau khi gọi method (optional operation).
   //
   boolean addAll(Collection<? extends E> c);

   // Xóa tất cả các phần tử ra khỏi Collection .(optional operation).
   void clear();

   // Kiểm tra xem Collection có chứa Object o không
   boolean contains(Object o);

   // Kiểm tra xem Collection có chứa tất cả các phần tử trong Collection c
   // không.
   boolean containsAll(Collection<?> c);

   // So sánh Collection này với Object o
   boolean equals(Object o);

   int hashCode();

   // Trả về true nếu Collection này không chứa phần tử nào
   boolean isEmpty();

   //
   // Xóa đối tượng o ra khỏi Collection trả về true nếu thực sự có một phần tử
   // bị xóa khỏi (optional operation).
   //
   boolean remove(Object o);

   //
   // Xóa các phần tử trong Collection này giống với các phần tử của Collection c
   //
   boolean removeAll(Collection<?> c);

   //
   // Kiểm tra xem Collection này chứa mọi phần tử mà Collection c chứa
   // (optional operation).
   ///
   boolean retainAll(Collection<?> c);

   // Trả về số phần tử trong Collection.
   int size();

   // Chuyển Collection thành mảng các đối tượng
   Object[] toArray();

   <T> T[] toArray(T[] a);

   // Trả về một bộ lặp để duyệt trên các phần tử của tập hợp.
   Iterator<E> iterator();
}

5.3- Duyệt các phần tử của tập hợp

Iterator là cách để bạn duyệt trên các phần tử của tập hợp
 
Ví dụ sử dụng Iterator để truy cập các phẩn tử của Collection.
 
CollectionAndIterator.java
package org.o7planning.tutorial.javacollection.collection;

import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

public class CollectionAndIterator {

   public static void main(String[] args) {

       // Tạo một đối tượng Collection không phần tử
       // Một tập hợp chỉ chứa các String.
       Collection<String> coll = new Vector<String>();
       coll.add("Collection");
       coll.add("Queue");
       coll.add("List");
       coll.add("Map");

       // In ra số phần tử của tập hợp.
       System.out.println("Size:" + coll.size());

       // Lấy ra bộ lặp Iterator để truy cập các phần tử của tập hợp
       // Rõ ràng bộ lặp này chỉ chứa các String.
       Iterator<String> ite = coll.iterator();


       // Kiểm tra xem Iteractor còn phẩn tử không.
       while (ite.hasNext()) {
           // Lấy ra phần tử tại vị trí con trỏ đang đứng
           // Đồng thời con trỏ nhẩy vị trí thêm 1 bước.
           String s = ite.next();
           System.out.println("Element:" + s);
       }
   }

}
Kết quả chạy ví dụ:

5.4- Các nhánh con của Collection

Như trên đã đề cập Collection có 3 interface con là Queue , ListSet. Và điểm khác nhau giữa chúng là cách thức lưu trữ dữ liệu
java.util.Queue java.util.List java.util.Set
Cho phép chứa các phần tử trùng lặp Cho phép chứa các phần tử trùng lặp Không cho phép chứa các phần tử trùng lặp
Không cho phép chứa các phần tử null Cho phép chứa nhiều phần tử null Tùy theo class thi hành Set hỗ trợ chứa phần tử null hay không .Nếu có hỗ trợ thì chỉ chứa nhiều nhất 1 phần tử null nếu có.
Một danh sách ( List) là một danh sách tuần tự các đối tượng, nơi mà các đối tượng giống nhau có thể xuất hiện một hoặc nhiều lần. Ví dụ: [1, 7, 1, 3, 1, 1, 1, 5]. Và bạn có thể nói về phần tứ "thứ N" trong danh sách. Bạn có thể thêm một phần tử vào bất kỳ một vị trí nào trong danh sách, thay đổi một phần tử nào tại một vị trí nào đó trong danh sách, hoặc xóa một phần tử tại một vị trí bất kỳ trong danh sách.

Hàng đợi ( Queue) cũng là một tập hợp tuần tự, nhưng bạn chỉ có thể chạm vào phần tử đứng ở đầu hàng đợi. Tất cả các phần tử được trèn vào cuối của hàng đợi và xóa phần tử đầu tiên của hàng đợi. Bạn có thể biết được có bao nhiêu phần tử trong hàng đợi, nhưng bạn không thể tìm ra hoặc nói về phần tử thứ N, bạn chỉ có thể thấy nó khi nó đứng lên đầu tiên của hàng đợi.

Set là một tập hợp không tuần tự, và nó không cho phép trùng lặp. Bất cứ một phần tử nào hoặc nằm trong tập hợp hoặc không nằm trong tập hợp. {7, 5, 3, 1} chính xác là giống với {1, 7, 1, 3, 1, 1, 1, 5}. Bạn không thể nói về phần tử thứ N thậm chí là phần tử đầu tiên, vì nó không có sự tuần tự. Bạn có thể thêm hoặc xóa các phần tử, và có thể tìm ra nếu thực sự nó tồn tại (Ví dụ "7 có nằm trong tập hợp này không?"). Chú ý: SortedSet là một interface con của Set nó có thể chứa các phần tử có thứ tự.

5.5- java.util.List Interface

List là một interface con của Collection nó có đầy đủ các tính năng của Collection đồng thời có thêm một số tính chất đặc biệt:
  • Cho phép phần tử trùng lặp
  • Cho phép 0 hoặc nhiều phần tử null.
  • Là một tập hợp có tuần tự.
Đồng thời ngoài cách truy cập bằng Iterator có thể truy cập bằng cách sử dụng ListIterator. ListIterator cho phép tiến hoặc lùi vị trí con trỏ.
// Lấy ra bộ lặp tất cả các phần tử      
public ListIterator<E> listIterator() của list .

// Lấy ra bộ lặp chứa các phần tử từ chỉ số thứ index trở đi .
public ListIterator<E> listIterator(int index) :
ListAndListIterator.java
package org.o7planning.tutorial.javacollection.list;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class ListAndListIterator {

   public static void main(String[] args) {

       // Tạo một đối tượng List (Chỉ chứa các String)
       List<String> list = new ArrayList<String>();
       list.add("One");
       list.add("Two");
       list.add("Three");
       list.add("Four");

       // Lấy ra đối tượng ListIterator để duyệt danh sách.
       ListIterator<String> listIterator = list.listIterator();

       // Hiện tại con trỏ đang đứng tại ví trí đầu danh sách.
       // Đứng tại chỉ số 0.
       // Lấy ra phần tử đầu tiên trong danh sách, con trỏ tiến một bước.
       String first = listIterator.next();
       System.out.println("first:" + first);// -->"One"

       // Hiện tại con trỏ đang đứng tại vị trí chỉ số 1
       // Lấy ra phần tử tiếp theo.
       String second = listIterator.next();
       System.out.println("second:" + second);// -->"Two"

       // Kiểm tra xem con trỏ có thể nhẩy lùi 1 vị trí không
       if (listIterator.hasPrevious()) {
           // Lùi con trỏ 1 trị trí.
           String value = listIterator.previous();
           System.out.println("value:" + value);// -->"Two"
       }

       System.out.println(" ----- ");

       while (listIterator.hasNext()) {
           String value = listIterator.next();
           System.out.println("value:" + value);
       }
   }

}
Kết quả chạy ví dụ:

5.6- java.util.Set Interface

Set là một Interface con của Collection, nó có đầy đủ các tính năng của Collection, và có thêm một số tính năng:
  • Mô tả một tập hợp không cho phép chứa các phần tử trùng lặp
  • Có cho phép phần tử null, nếu có phần tử null thì chỉ có 1.
HashSetExample.java
package org.o7planning.tutorial.javacollection.set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class HashSetExample {

   public static void main(String[] args) {

       // Tạo một đối tượng Set có sức chứa ban đầu 10 phần tử.
       // Nếu số lượng phần tử thêm vào vượt quá sức chứa hiện tại.
       // Nó sẽ tự tăng sức chứa lên 80%.
       // Đặc điểm của HashSet là phần tử thêm vào sau đứng trước.
       Set<String> set = new HashSet<String>(10, (float) 0.8);

       set.add("One");
       set.add("Two");

       // Trùng lặp xẩy ra.
       // Với HastSet: Nó sẽ ghi phần tử mới vào và remove phần tử cũ.
       set.add("One");
       set.add("Three");

       Iterator<String> it = set.iterator();
       while (it.hasNext()) {
           System.out.println(it.next());
       }
   }

}
Kết quả chạy ví dụ:

5.7- java.util.Queue Interface

Queue (hàng đợi) là một Interface con của Collection, nó có đầy đủ các tính năng của Collection, nó khá giống với List, tuy nhiên mục đích sử dụng hơi khác nhau. Queue được thiết kế để bạn chỉ có thể truy cập phần tử ở đầu hàng đợi, và khi loại bỏ phần tử nó loại phần tử đứng đầu hàng đợi. Nó giống như hàng người xếp hàng ở siêu thị, chỉ người đứng đầu hàng đợi mới được phục vụ, người mới đến sẽ được trèn vào hàng đợi, vị trí được trèn vào có thể không phải là cuối hàng. Vị trí phần từ được trèn vào phụ thuộc vào loại hàng đợi và độ ưu tiên của phần tử.
  • Là tập hợp cho phép các phần tử trùng lặp.
  • Không cho phép phần tử null.
Có hai class thi hành interface Queue.
  • java.util.LinkedList
  • java.util.PriorityQueue
LinkedList là một hàng đợi khá chuẩn. Nhưng nhớ rằng LinkedList thi hành cả 2 interface ListQueue.

PriorityQueue lưu trữ các phần tử trong nội bộ theo trật tự tự nhiên của các phần tử (nếu các phần tử này là kiểu Comparable), hoặc theo một Comparator (bộ so sánh) truyền cho PriorityQueue.
Chú ý rằng, một class có thể thi hành cả 2 interface ListQueue, chính vì vậy bạn không cần quan tâm tới các phần tử sắp xếp thế nào trong nội bộ của đối tượng class trên, nếu bạn coi nó như một hàng đợi, hãy xem cách thức truy cập vào phần tử của hàng đợi. Hãy xem các phương thức đặc trưng của Queue, nó mô phỏng hàng đợi giống hàng người xếp hàng ở siêu thị.
  Ném ra ngoại lệ Trả về giá trị cụ thể
Trèn add(e) offer(e)
Loại bỏ remove() poll()
Xem xét element() peek()

boolean add(E)

Trèn một phần tử chỉ định vào hàng đợi nếu có thể làm điều này ngay lập tức mà không bị giới hạn bởi kích thước hàng đợi, trả về true nếu thành công, ngược lại nó sẽ ném ra ngoại lệ IllegalStateException khi hàng đợi không còn chỗ.

boolean offer(E)

Trèn phần tử chỉ định vào hàng đợi nếu có thể làm điều đó ngay lập tức nếu không bị giới hạn bởi kích thước hàng đợi. Khi sử dụng hàng đợi có giới hạn kích thước, phương thức này khá giống với add(E), tuy nhiên phương thức này không ném ra ngoại lệ khi không trèn được phần tử vào hàng đợi, mà nó trả về false trong tình huống đó.

E remove()

Lấy ra và loại bỏ luôn phần tử đầu tiên của hàng đợi. Phương thức này chỉ khác với poll() ở chỗ nếu hàng đợi không có phần tử ngoại lệ sẽ bị ném ra.

E poll()

Lấy ra và loại bỏ phần tử đầu tiên trong hàng đợi, hoặc trả về null nếu hàng đợi không có phần tử nào.

E element()

    Lấy ra nhưng không loại bỏ phần tử đứng đầu của hàng đợi. Phương thức này chỉ khác với peek() là nó ném ra ngoại lệ nếu hàng đợi không có phần tử.

E peek()

Lấy ra, nhưng không loại bỏ phần tử đầu tiên trong hàng đợi, hoặc trả về null nếu hàng đợi không có phần tử nào.

Nhận xét:

Các phương thức hàng đợi ở trên không có phương thức nào cho phép bạn truy cập các phần tử khác trong hàng đợi ngoài phần tử đầu tiên, bạn cũng không thể chỉ định vị trí phần tử sẽ được trèn vào.
QueueDemo.java
package org.o7planning.tutorial.javacollection.queue;

import java.util.LinkedList;
import java.util.Queue;

public class QueueDemo {

   public static void main(String[] args) {

       Queue<String> names = new LinkedList<String>();

       // offer(E): Trèn thêm phần tử vào hàng đợi.
       // Với hàng đợi LinkedList phần tử sẽ trèn vào cuối hàng đợi.
       // Trả về true nếu thêm thành công.
       // Trả về false nếu hàng đợi không còn chỗ.
       names.offer("E");
       names.offer("A");
       names.offer("M");

       // add(E): Trèn thêm phần tử vào hàng đợi.
       // Với hàng đợi LinkedList phần tử sẽ trèn vào cuối hàng đợi.
       // Trả về true nếu thêm thành công
       // Ném ra ngoại lệ nếu hàng đợi không còn chỗ.
       names.add("G");
       names.add("B");

       while (true) {
           // Lấy ra và loại bỏ phần tử đầu tiên ra khỏi hàng đợi.
           // Trả về null nếu không còn phần tử nào trong hàng đợi.
           String name = names.poll();
           if (name == null) {
               break;
           }
           System.out.println("Name=" + name);
       }

   }

}
Kết quả chạy ví dụ:
Ví dụ với một hàng đợi có ưu tiên PriorityQueue. Hàng đợi này lưu trữ các phần tử trong nội bộ theo trật tự tự nhiên của phần tử (nếu các phần tử đó so sánh được với nhau - thi hành Comparable) hoặc một bộ so sánh Comparator được truyền cho  PriorityQueue.
String là một class thi hành interface Comparable, chúng có thể so sánh được với nhau, và sắp xếp theo thứ tự alphabet.
PriorityQueueDemo.java
package org.o7planning.tutorial.javacollection.queue;

import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueDemo {

    public static void main(String[] args) {

        // Với hàng đợi PriorityQueue phần tử sẽ được sắp xếp vị trí
        // theo trật tự tự nhiên của chúng.
        Queue<String> names = new PriorityQueue<String>();

        // offer(E): Trèn thêm phần tử vào hàng đợi.
        // Trả về true nếu thêm thành công.
        // Trả về false nếu hàng đợi không còn chỗ.
        names.offer("E");
        names.offer("A");
        names.offer("M");

        // add(E): Trèn thêm phần tử vào hàng đợi.
        // Trả về true nếu thêm thành công
        // Ném ra ngoại lệ nếu hàng đợi không còn chỗ.
        names.add("G");
        names.add("B");

        while (true) {
            // poll(): Lấy ra và loại bỏ phần tử đầu tiên ra khỏi hàng đợi.
            // Trả về null nếu không còn phần tử nào trong hàng đợi.
            String name = names.poll();
            if (name == null) {
                break;
            }
            System.out.println("Name=" + name);
        }

    }

}
Kết quả chạy ví dụ:

5.8- Quan hệ thừa kế các class trong nhóm Collection

Một số class thông dụng:
 
Implementations
Hash Table Resizable Array Balanced Tree Linked List Hash Table + Linked List
Interfaces Set HashSet   TreeSet   LinkedHashSet
List   ArrayList      

5.9- java.util.ArrayList

ArrayList có đầy đủ tính năng của interface List. Đồng thời nó có khả năng truy cập phần tử ngẫu nhiên (Do thừa kế từ interface RandomAccess)

Về cơ bản nó giống với class Vector, khác biệt là các method của Vector được đồng bộ, còn ArrayList thì không. ArrayList phù hợp cho các ứng dụng 1 luồng (1 Thread).

ArrayListDemo.java
package org.o7planning.tutorial.javacollection.list;

import java.util.ArrayList;

public class ArrayListDemo {

   public static void main(String[] args) {
       
       // Khai báo một đối tượng ArrayList chứa các phần tử Integer.
       ArrayList<Integer> list = new ArrayList<Integer>(10);
       
       // Thêm vào 1 phần tử
       list.add(123);
       list.add(245);
       list.add(new Integer(345));
       // ArrayList cho phép add phan tu null .
       // (Đặc tính của List)
       list.add(null);
       
       // In ra so phan tu trong ArrayList
       System.out.println("Size:" + list.size());// =4
       // Truy cập ngẫu nhiên vào phần tử có chỉ số 1.
       
       Integer i = list.get(1);
       System.out.println("Element index 1 =" + i);// =245
       Integer newInt = 1000;
       
       // Sét đặt lại phần tử tại chỉ số 1
       // Method này trả về phần tử cũ.
       Integer old = list.set(1, newInt);
       //
       System.out.println("Old value:" +old);// =245 .
       System.out.println("New value:" + list.get(1));// =1000 .
   }

}
Kết quả chạy ví dụ:

5.10- java.util.Vector

Là một class có tính năng tương tự ArrayList. Khác biệt là các method của Vector được đồng bộ hóa, còn ArrayList thì không.

Các method của Vector được đồng bộ hóa, vì vậy sử dụng tốt trong các ứng dụng đa luồng (Multiple Thread)

Vector có thêm một số method các method này vốn là di sản từ phiên bản 1.0. Trước khi có khái niệm về nền tảng tập hợp trong Java.
// Method di sản từ 1.0 , lấy ra phần tử tại vị trí index
// elementAt(int) giống với method get(int)
public E elementAt(int index)

// Method thừa kế từ interface List, lấy ra phần tử tại vị trí index.
public E get(int index)

// Thay thế phần tử tại vị trí index bởi phần tử mới, và trả về phần tử cũ.
// setElementAt(int,E) giống với set(int,E)
public void setElementAt(int index, E element);

// Thay thế phần tử tại vị trí index bởi phần tử mới, và trả về phần tử cũ.
public E set(int index, E element)
VectorDemo.java
package org.o7planning.tutorial.javacollection.list;

import java.util.Vector;

public class VectorDemo {

   public static void main(String[] args) {
       // Khởi tạo một đối tượng Vector
       // Sức chứa ban đầu 10.
       // Tự động tăng sức chứa thêm 5 nếu số phần tử vượt qua sức chứa hiện
       // tại.

       Vector<Integer> v = new Vector<Integer>(10, 5);

       v.add(123);
       v.add(245);
       v.add(new Integer(345));
       v.add(null);
       // In ra so phan tu co trong Vector (Khong phai la dung luong)
       System.out.println("Size:" + v.size());// =4

       // Lấy ra phần tử tại chỉ số 1.
       // Giống với method get(int)
       Integer i = v.elementAt(1);
       System.out.println("v.elementAt(1)=" + i);// 245

       // Sét đặt lại phần tử tại chỉ số 1
       // Method này trả về phần tử cũ.
       v.setElementAt(1, 1000);
       //
       System.out.println("New value:" + v.get(1));// =1000 .
   }
}
Kết quả chạy ví dụ:

5.11- java.util.SortedSet

SortedSet là interface con của interface Set, nó có đầy đủ tính năng của Set. SortedSet là một tập hợp có sắp xếp, các phần tử được thêm mới vào tập hợp tự động được đứng tại một vị trí phù hợp để đảm bảo tập hợp vẫn được sắp xếp (tăng dần hoặc giảm dần).

Chính vì vậy các phần tử của tập hợp phải so sánh được với nhau, chúng phải là đối tượng của java.lang.Comparable (Có thể so sánh được), Nếu bạn thêm vào tập hợp một phần tử không phải đối tượng của Comparable, bạn sẽ nhận một ngoại lệ.
Class thi hành Interface SortedSetTreeSet.
Hãy xem class Player (Người chơi), bao gồm các thông tin: họ tên, số huy chương vàng, số huy chương bạc, số huy chương đồng.

Các Player có thể so sánh với nhau theo nguyên tắc:
  1. Ai nhiều huy chương vàng hơn thứ hạng cao hơn.
  2. Nếu hai người cùng số huy chương vàng, thì ai nhiều huy chương bạc hơn sẽ xếp thứ hạng cao hơn.
  3. Nếu hai người cùng số huy chương vàng, bạc, thì ai nhiều huy chương đồng hơn sẽ xếp thứ hạng cao hơn.
  4. Còn lại coi là cùng thứ hạng.
Class Player sẽ thi hành interface java.lang.Comparable.
Player.java
package org.o7planning.tutorial.javacollection.sortedset;

public class Player implements Comparable<Player> {

   private String name;

   private int goldMedal;
   private int silverMedal;
   private int bronzeMedal;

   public Player(String name, int goldMedal, int silverMedal, int bronzeMedal) {
       this.name = name;
       this.goldMedal = goldMedal;
       this.silverMedal = silverMedal;
       this.bronzeMedal = bronzeMedal;
   }

   // So sánh Player này với Player khác (other).
   // Giá trị trả về < 0 nghĩa là Player này < Player other.
   // Nếu trả về > 0 nghĩa là Player này > Player other
   // Nếu trả về 0 nghĩa là Player này = Player other.
   @Override
   public int compareTo(Player other) {
       // So sánh số huy chương vàng.
       int value = this.goldMedal - other.goldMedal;
       if (value != 0) {
           return value;
       }
       // So sánh số huy chương bạc.
       value = this.silverMedal - other.silverMedal;
       if (value != 0) {
           return value;
       }
       // So sánh số huy chương đồng.
       value = this.bronzeMedal - other.bronzeMedal;
       return value;
   }

   @Override
   public String toString() {
       return "[" + this.name + ", Gold: " + this.goldMedal + ", Silver: " + this.silverMedal + ", Bronze: "
               + this.bronzeMedal + "]";
   }

}
SortedSetDemo.java
package org.o7planning.tutorial.javacollection.sortedset;

import java.util.SortedSet;
import java.util.TreeSet;

public class SortedSetDemo {

   public static void main(String[] args) {

       // Tạo một đối tượng SortedSet thông qua class con TreeSet
       SortedSet<Player> players = new TreeSet<Player>();

       Player tom = new Player("Tom", 1, 3, 5);
       Player jerry = new Player("Jerry", 3, 1, 3);
       Player donald = new Player("Donal", 2, 10, 0);
       
       // Thêm các phần tử vào tập hợp
       // Chúng sẽ tự động được sắp xếp (Tăng dần).
       players.add(tom);
       players.add(jerry);
       players.add(donald);
       
       // In ra thông tin các phần tử.
       for(Player player : players) {
           System.out.println("Player: "+ player);
       }
   }

}
Kết quả chạy class SortedSetDemo:

6- Nhóm Map

6.1- Các Interface trong nhóm Map

Nhóm Map dẫn đầu bởi interface java.util. Map. Interface này có 2 interface con là java.util. SortedMap và java.util.concurrent. ConcurrentMap . ConcurrentMap không thuộc bó java.util nó được đưa vào từ phiên bản java1.5, chúng ta không đề cập tới nó trong tài liệu này. Nhóm Map đặc trưng bởi việc lưu trữ dữ liệu qua các cặp key/value.

6.2- Các class trong nhóm Map

6.3- java.util.Map Interface

TT Phương thức và mô tả
1 void clear( )

Loại bỏ tất cả các cặp key/value ra khỏi map.(optional operation).

2 boolean containsKey(Object k)

Trả về true nếu trong map có chứa khóa cho bởi tham số, ngược lại trả về false.

3 boolean containsValue(Object v)

Trả về true nếu map chứa giá trị cho bởi tham số, ngược lại trả về false.

4 Set<Map.Entry<K,V>> entrySet( )

Trả về đối tượng Set chứa các entry của map. Nó là tập hợp các đối tượng có kiểu Map.Entry.

5 boolean equals(Object obj)

Trả về true nếu obj là một Map và chứa cùng các entry, ngược lại trả về false.

6 Object get(K k)

Trả về giá trị tương ứng với khóa.

7 int hashCode( )

Trả về hashCode

8 boolean isEmpty( )

Trả về true nếu map không có phần tử, ngược lại trả về false.

9 Set<K> keySet( )

Trả về đối tượng Set chứa các khóa của map.

10 Object put(K k, V v)

Đặt một cặp key/value vào map, nó sẽ ghi đè giá trị mới nếu khóa đã tồn tại trong map. Nếu khóa đã tồn tại trong map, phương thức trả về giá trị cũ ứng với khóa, ngược lại trả về null.(optional operation).

11 void putAll(Map<? extends K,? extends V> m)

Đặt hết tất cả các cặp key/value trong m vào map này.(optional operation).

12 Object remove(Object k)

Loại bỏ cặp key/value ứng với khóa cho bởi tham số. (optional operation).

13 int size( )

Trả về số lượng các cặp key/value trong map.

14 Collection values( )

Trả về một tập hợp chứa các giá trị trong map.

Các phương thức tùy chọn (Optional operation) có thể được hỗ trợ trên class thi hành nó hoặc không, trong trường hợp không hỗ trợ nó có thể ném ra ngoại lệ UnsupportedOperationException:
import java.util.Collection;
import java.util.Map;
import java.util.Set;

public class MyMap<K,V> implements Map<K,V>{

   .....

     // Nếu bạn gọi method này, một ngoại lệ sẽ ném ra vô điều kiện.
    @Override
    public void clear() {
        throw new java.lang.UnsupportedOperationException();        
    }   

}
Như vậy là class MyMap không hỗ trợ ý nghĩa thực tế của method clear(). Người dùng cố tình sử dụng method này của MyMap sẽ nhận một ngoại lệ .
MapDemo.java
package org.o7planning.tutorial.javacollection.map;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MapDemo {
    
    public static void main(String[] args) {

        Map<String, String> map = new HashMap<String, String>();

        map.put("01000005", "Tom");
        map.put("01000002", "Jerry");
        map.put("01000003", "Tom");
        map.put("01000004", "Donald");

        // Lấy ra tập hợp các key.
        // Tập hợp này không được sắp xếp
        Set<String> phones = map.keySet();

        for (String phone : phones) {
            System.out.println("Phone: " + phone + " : " + map.get(phone));
        }

    }

}
Kết quả chạy ví dụ:
Bạn có thể truy cập dữ liệu của Map thông qua Map.Entry, xem hình minh họa dưới đây:
MapEntryDemo.java
package org.o7planning.tutorial.javacollection.map;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

public class MapEntryDemo {


    public static void main(String[] args) {

        Map<String, String> map = new HashMap<String, String>();

        map.put("01000005", "Tom");
        map.put("01000002", "Jerry");
        map.put("01000003", "Tom");
        map.put("01000004", "Donald");

        // Lấy ra tập hợp các entry.
        // Các entry này có thể không sắp xếp theo key.
        Set<Entry<String, String>> entries = map.entrySet();

        for (Entry<String, String> entry : entries) {
            System.out.println("Phone: " + entry.getKey() + " : " + entry.getValue());
        }

    }
}
Kết quả chạy ví dụ:

6.4- java.util.SortedMap Interface

Interface SortedMap là interface con của Map. Nó đảm bảo rằng các cặp key/value được sắp xếp theo thứ tự tăng dần theo key.
Chỉ có một class trong bó java.util thi hành interface SortedMap, đó là TreeMap.
Các phương thức của SortedMap:
TT Phương thức và mô tả
1 Comparator comparator( )

Trả về bộ so sánh (Comparator) sử dụng để sắp xếp. Nếu thứ tự tự nhiên được sử dụng cho map (key implements Comparable), null sẽ được trả về.

2 Object firstKey( )

Trả về key đầu tiên trong map.

3 SortedMap headMap(Object end)

Trả về một SortedMap con, với các cặp key/valuekey được đánh giá nhỏ hơn hoặc bằng end.

4 Object lastKey( )

Trả về key cuối cùng.

5 SortedMap subMap(Object start, Object end)

Trả về một SortedMap con, chứa các cặp key/value mà key được đánh giá lớn hơn hoặc bằng start và nhỏ hơn hoặc bằng end.

6 SortedMap tailMap(Object start)

Trả về một SortedMap con, chứa các cặp key/value mà key của nó được đánh giá lớn hơn hoặc bằng start.

SortedMapDemo.java
package org.o7planning.tutorial.javacollection.sortedmap;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class SortedMapDemo {

   public static void main(String[] args) {

       Map<String, String> map = new TreeMap<String, String>();

       map.put("01000005", "Tom");
       map.put("01000002", "Jerry");
       map.put("01000003", "Tom");
       map.put("01000004", "Donald");

       // Tập hợp này đã sắp xếp tăng dần
       Set<String> keys = map.keySet();
       for (String key : keys) {
           System.out.println("Phone: " + key);
       }
       
       System.out.println("-----");

       // Tập hợp này cũng đã được sắp xếp theo key.
       Set<Map.Entry<String, String>> entries = map.entrySet();
       for (Map.Entry<String, String> entry : entries) {
           System.out.println("Phone: " + entry.getKey());
       }
   }

}
Kết quả chạy ví dụ: