openplanning

Hướng dẫn sử dụng nền tảng tập hợp trong Java (Java Collection Framework)

  1. Giới thiệu
  2. Ví dụ bắt đầu
  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 đề.
  4. Tổng quan về Java Collections Framework
  5. Nhóm Collection
  6. Nhóm Map

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ữ lập trình.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 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 vị trí đầu tiên của danh sách.
		list.addFirst("A");

		// Trèn một phần tử vào ví trí có chỉ số 1.
		list.add(1, "A2");

		// Ghi ra tất cả các phần tử của danh sách:
		System.out.println("Original contents of list: " + list);

		// Loại bỏ một phần tử khỏi danh sách
		list.remove("F");

		// Loại bỏ 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);

		// Loại bỏ 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);

		// Lấy ra phần tử tại chỉ số 2.
		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ụ:
Original contents of list: [A, A2, F, B, D, E, C, Z]
Contents of list after deletion: [A, A2, D, E, C, Z]
List after deleting first and last: [A2, D, E, C]
List after change: [A2, D, E Changed, C]
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ữ các cặp, 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);
		
		// Cập nhập 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ụ:
Salary of employee E01 = 1000.0
Salary of employee E05 = 400.0

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 đề.

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 .
Xóa phần tử ra khỏi mảng
Các phần tử của một mảng được đặt 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, nhưng đ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ũ sang 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 .
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ề package 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.
Các interface trong nền tảng tập hợp Java (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:
** Hashtable **
public class HashMap<K,V> extends AbstractMap<K,V>
                           implements Map<K,V>, Cloneable, Serializable
** Vector **
public class Vector<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, Serializable
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' vào Map m.
// Nếu 'key' đã tồn tại, 'value' sẽ được thay bởi giá trị mới.
m.put(key,value);

// In ra giá trị ứng với 'key' (khóa).
System.out.println(m.get(new Integer(123));
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ụ lớp java.util.Vector thực hiện 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 phương thức 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().
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 **
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 phương thức 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

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 chúng ta không đề cập đế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.
java.util.Collection Interface
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();
}
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 rỗng.
		// 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 (collection) này.
		System.out.println("Size:" + coll.size());

		// Lấy ra đối tượng Iterator để truy cập vào các phần tử của tập hợp.
		// Đối tượng Iterator này chỉ chứa các String.
		Iterator<String> ite = coll.iterator();

		// Kiểm tra xem Iteractor còn phần tử tiếp theo hay không?
		while (ite.hasNext()) {
			// Lấy ra phần tử tại vị trí con trỏ đang đứng
			// Sau đó di chuyển con trỏ thêm 1 bước.
			String s = ite.next();
			System.out.println("Element:" + s);
		}
	}

}
Kết quả chạy ví dụ:
Size:4
Element:Collection
Element:Queue
Element:List
Element:Map
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ó.
List
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.
Queue
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 phía 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
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ạ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ự.
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ỏ.
// Trả về đối tượng ListIterator, để duyệt các phần tử của danh sách.
public ListIterator<E> listIterator()  
 
// Trả về đối tượng ListIterator, 
// để duyệt các phần tử từ vị trí có chỉ số 'index' đến cuối danh sách.
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 các phần tử của danh sách.
		// (Theo đúng trình tự).
		// Returns a list iterator over the elements in this list
		// (in proper sequence)
		ListIterator<String> listIterator = list.listIterator();

		// Hiện tại con trỏ đang đứng tại ví trí đầu tiên của Iterator.
		// Đứng tại vị trí có chỉ số 0.
		// Lấy ra phần tử đầu tiên trong Iterator, con trỏ tiến thêm 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í có 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 trở lại 1 vị trí hay không.
		if (listIterator.hasPrevious()) {
			// Nhẩy trở lại 1 bước.
			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ụ:
first:One
second:Two
value:Two
 -----
value:Two
value:Three
value:Four
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 (capacity) 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 sẽ đứng ở phía trước.
		Set<String> set = new HashSet<String>(10, (float) 0.8);

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

		// Khi trùng lặp xẩy ra.
		// Với HashSet: Nó sẽ thêm vào phần tử mới và loại bỏ 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ụ:
One
Two
Three
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) được sét đặt 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ử 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ử 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ó kích thước giới hạn, 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 (queue).
		// Với hàng đợi LinkedList phần tử sẽ được trèn vào cuối hàng đợi.
		// Trả về true nếu trèn 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ụ:
Name=E
Name=A
Name=M
Name=G
Name=B
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 sét đặt 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 (queue) 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 (queue).
		// 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 một phần tử vào hàng đợi (queue).
		// Trả về true nếu thành công.
		// Ném ra một Exception nếu hàng đợi đã đầy.
		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ụ:
Name=A
Name=B
Name=E
Name=G
Name=M
Quan hệ thừa kế các lớp 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
Interfaces
List
ArrayList
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ử có kiểu Integer.
		ArrayList<Integer> list = new ArrayList<Integer>(10);

		// Thêm vào các phần tử.
		list.add(123);
		list.add(245);
		list.add(new Integer(345));

		// ArrayList cho phép thêm vào phần tử null .
		// (Đặc tính của List)
		list.add(null);

		// In ra số phần tử trong ArrayList.
		System.out.println("Size:" + list.size());// =4

		// Truy cập ngẫu nhiên vào phần tử tại chỉ số 1.
		Integer i = list.get(1);
		System.out.println("Element index 1 =" + i);// =245
		Integer newInt = 1000;

		// Thay thế phần tử tại vị trí có chỉ số 1.
		// Phương thức 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ụ:
Size:4
Element index 1 =245
Old value:245
New value:1000
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.
		// Với sức chứa (capacity) ban đầu là 10 phần tử.
		// Tự động tăng sức chứa thêm 5 nếu số phần tử nhiều hơn
		// 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 số phần tử thực sự có trong Vecter (Không phải là sức chứa)
		System.out.println("Size:" + v.size());// =4

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

		// Thay thế phần tử tại chỉ số 1.
		// Replace element at index 1.
		v.setElementAt(1000, 1);
		// 
		System.out.println("New value:" + v.get(1));// =1000 .
	}
}
Kết quả chạy ví dụ:
Size:4
v.elementAt(1)=245
New value:1000
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ệ.
Một trong các 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 giá trị trả về > 0 nghĩa là Player này > Player other
	// Nếu giá trị 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 lớp 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 các phần tử.
		for (Player player : players) {
			System.out.println("Player: " + player);
		}
	}

}
Kết quả chạy class SortedSetDemo:
Player: [Tom, Gold: 1, Silver: 3, Bronze: 5]
Player: [Donal, Gold: 2, Silver: 10, Bronze: 0]
Player: [Jerry, Gold: 3, Silver: 1, Bronze: 3]

6. Nhóm Map

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.
Các class trong nhóm Map
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 phương thức này, một ngoại lệ sẽ được 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 một tập hợp chứa các khóa (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ụ:
Phone: 01000004 : Donald
Phone: 01000003 : Tom
Phone: 01000005 : Tom
Phone: 01000002 : Jerry
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 một tập hợp của các entry.
		// Các entry này có thể không được sắp xếp theo khóa (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ụ:
Phone: 01000004 : Donald
Phone: 01000003 : Tom
Phone: 01000005 : Tom
Phone: 01000002 : Jerry
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 đã được 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ụ:
Phone: 01000002
Phone: 01000003
Phone: 01000004
Phone: 01000005
-----
Phone: 01000002
Phone: 01000003
Phone: 01000004
Phone: 01000005

Các hướng dẫn Java Collections Framework

Show More