Java Utility API, các Collections trong Java
- 05-11-2023
- Toanngo92
- 0 Comments
Khung (framework) Collections bao gồm các lớp, giao diện và loại dữ liệu chính là cách chính để thao tác với các bộ sưu tập dữ liệu. Khung cũng bao gồm các triển khai gói bọc (wrapper) và mục đích chung (general purpose). Triển khai dạng Adapter giúp thích nghi một bộ sưu tập với bộ sưu tập khác. Bên cạnh đó, còn có các triển khai tiện ích và triển khai kế thừa.
Mục lục
Gói java.util
Gói java.util chứa định nghĩa của một số lớp hữu ích cung cấp một loạt các chức năng. Gói chủ yếu chứa các lớp bộ sưu tập (collection) hữu ích để làm việc với các nhóm các đối tượng. Gói cũng chứa định nghĩa của các lớp cung cấp các cơ sở thời gian và ngày tháng cũng như nhiều tiện ích khác, chẳng hạn như lịch (calendar) và từ điển (dictionary). Nó cũng chứa danh sách các lớp và giao diện để quản lý một tập hợp dữ liệu trong bộ nhớ.
Hình dưới hiển thị một số lớp và interface có trong gói java.util.
Lớp Date
Lớp Date biểu diễn ngày và thời gian và cung cấp các phương thức để thao tác với các thực thể ngày tháng. Lớp Date được biểu diễn dưới dạng một kiểu Long đếm số mili giây kể từ ngày 1 tháng 1 năm 1970, 0:00:00 GMT. Một đối tượng Date không thể được in ra mà không chuyển đổi nó thành kiểu chuỗi. Định dạng nên tuân theo địa phương của người dùng cuối, ví dụ, 12.2.95 hoặc 02/12/95.
Lớp “Date” trong Java cung cấp hai hàm khởi tạo:
- Date(): Hàm tạo này tạo một đối tượng Date bằng cách sử dụng ngày và giờ hiện tại.
- Date(long dt): Hàm tạo này tạo một đối tượng Date bằng cách sử dụng số mili giây cụ thể kể từ ngày 1 tháng 1 năm 1970, 00:00:00 GMT (còn được gọi là thời điểm Unix epoch). Điều này cho phép bạn tạo một đối tượng Date biểu thị một điểm thời gian cụ thể dựa trên số mili giây kể từ epoch.
Dưới đây là ví dụ về cách sử dụng hàm tạo Date(long dt):
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.mycompany;
import java.util.Date;
/**
*
* @author toan1
*/
public class ExampleDateClass {
public static void main(String[] args) {
long milliSecondSinceEpoch = 1635820800000L;
Date specificDate = new Date(milliSecondSinceEpoch);
System.out.println(specificDate);
}
}
Trong ví dụ này, đối tượng specificDate biểu thị ngày và giờ tương ứng với số mili giây được cung cấp kể từ epoch.
Lớp Calendar
Dựa trên một đối tượng Date đã cho, lớp Calendar có thể trích xuất thông tin dưới dạng số nguyên như NĂM, THÁNG và NGÀY. Đây là một lớp trừu tượng và do đó, không thể tạo đối tượng trực tiếp giống như lớp Date. Một đối tượng Calendar cung cấp tất cả các giá trị trường thời gian cần thiết để thực hiện định dạng ngày-giờ cho một ngôn ngữ cụ thể và kiểu lịch cụ thể (ví dụ: lịch Gregorian tiêu chuẩn, lịch truyền thống Đức).
Lưu ý: Lớp GregorianCalendar là một lớp con của lớp Calendar và thực hiện phiên bản lịch Gregorian.
Ví dụ:
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.mycompany;
/**
*
* @author toan1
*/
import java.util.Calendar;
public class MyCalendar {
private Calendar calendar;
public MyCalendar() {
calendar = Calendar.getInstance();
}
public void displayCurrentDate() {
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // Month is 0-based, so we add 1.
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println("Current Date: " + year + "-" + month + "-" + day);
}
public void addDays(int days) {
calendar.add(Calendar.DAY_OF_MONTH, days);
}
public void subtractDays(int days) {
calendar.add(Calendar.DAY_OF_MONTH, -days);
}
public static void main(String[] args) {
MyCalendar myCalendar = new MyCalendar();
myCalendar.displayCurrentDate();
myCalendar.addDays(7); // Add 7 days
myCalendar.displayCurrentDate();
myCalendar.subtractDays(3); // Subtract 3 days
myCalendar.displayCurrentDate();
}
}
Lớp Random
Lớp Random được sử dụng để tạo các số ngẫu nhiên. Nó được sử dụng mỗi khi cần tạo các số theo cách tùy ý hoặc không có hệ thống. Ví dụ, trong trò chơi xúc xắc, kết quả của lần tung xúc xắc là không thể đoán trước. Trò chơi có thể được mô phỏng bằng một đối tượng Random.
Lớp này cung cấp hai khởi hàm tạo, một hàm tạo nhận giá trị khởi đầu (seed – một số được sử dụng để bắt đầu quá trình tạo số ngẫu nhiên) làm tham số và hàm tạo khác không nhận tham số và sử dụng thời gian hiện tại làm giá trị khởi đầu.
Khung bộ Sưu Tập (Collections Framework)
Một bộ sưu tập (collection) là một thùng chứa giúp gom nhóm nhiều phần tử thành một đơn vị duy nhất. Các bộ sưu tập giúp lưu trữ, truy xuất, thao tác và truyền dữ liệu.
Khung Sưu Tập (Collections Framework) đại diện và thao tác trên các bộ sưu tập. Nó bao gồm các yếu tố sau:
Thuật toán: Đây là các phương thức được sử dụng để thực hiện các tính toán, chẳng hạn như sắp xếp, trên các đối tượng thực hiện các giao diện bộ sưu tập.
Lưu ý: Cùng một phương thức có thể được áp dụng trên các triển khai khác nhau của giao diện bộ sưu tập thích hợp.
Triển khai: Đây là các cấu trúc dữ liệu có thể sử dụng lại.
Giao diện: Đây là các kiểu dữ liệu trừu tượng và đại diện cho các bộ sưu tập. Chúng giúp thao tác độc lập với các bộ sưu tập mà không cần biết chi tiết về cách chúng được biểu diễn.
Trong Java, Khung Sưu Tập cung cấp một tập hợp các giao diện và lớp để lưu trữ và thao tác trên các nhóm đối tượng một cách chuẩn.
Khung Sưu Tập (Collections Framework) được phát triển với những mục tiêu sau đây:
- Nó nên có hiệu suất cao.
- Các loại bộ sưu tập khác nhau nên hoạt động cùng nhau và cần phải tương tác được với nhau.
- Nên dễ dàng mở rộng một bộ sưu tập.
- Phải tối ưu hóa sự nỗ lực để học và sử dụng các API mới.
- Phải tối ưu hóa sự nỗ lực để thiết kế các API mới.
- Nên giảm bớt công sức lập trình.
- Nên tăng cường tốc độ và chất lượng chương trình.
- Nên thúc đẩy việc tái sử dụng phần mềm.
Giao diện bộ sưu tập (Collection Interface)
Khung Sưu Tập (Collections Framework) bao gồm các giao diện và lớp để làm việc với các nhóm đối tượng. Ở đỉnh của phân cấp là giao diện Collection.
Giao diện Collection giúp chuyển đổi kiểu của bộ sưu tập. Điều này được thực hiện bằng cách sử dụng hàm khởi tạo chuyển đổi, cho phép khởi tạo bộ sưu tập mới chứa các phần tử có trong bộ sưu tập cụ thể, không phụ thuộc vào giao diện con của bộ sưu tập đó.
Lưu ý: Có các bộ sưu tập có thứ tự và không có thứ tự. Một số bộ sưu tập cho phép các phần tử trùng lặp.
JDK cung cấp việc triển khai của các giao diện con cụ thể như Set và List, được sử dụng để truyền bộ sưu tập và thao tác với chúng mọi khi cần.
Giao diện Collection được mở rộng bởi các giao diện con sau:
- Set
- List
- Queue
Các lớp sưu tập (Collection classes) là các lớp tiêu chuẩn triển khai các giao diện Collection. Một số lớp cung cấp triển khai đầy đủ của các giao diện, trong khi một số lớp cung cấp triển khai khung và là lớp trừu tượng. Một số lớp Collection cơ bản bao gồm:
- HashSet
- LinkedHashSet
- TreeSet
Hình dưới mô tả cấu trúc phân tầng của Collection Interface:
Các phương thức trong Collection Interface
Giao diện Collection giúp truyền bộ sưu tập các đối tượng với tính chất tổng quát cao. Một lớp sưu tập chứa một số mục trong cấu trúc dữ liệu và cung cấp các hoạt động khác nhau để thao tác với nội dung của bộ sưu tập, chẳng hạn như thêm mục, xóa mục và tìm số lượng phần tử.
Giao diện này bao gồm các phương thức sau:
- size(), isEmpty(): Sử dụng để biết về số phần tử có trong bộ sưu tập.
- contains(): Sử dụng để kiểm tra xem đối tượng cụ thể có trong bộ sưu tập hay không.
- add(), remove(): Sử dụng để thêm và loại bỏ một phần tử khỏi bộ sưu tập.
- iterator(): Sử dụng để cung cấp một bộ lặp (iterator) trên bộ sưu tập.
Các phương thức quan trọng trong giao diện Collection bao gồm:
add(Object obj) Phương thức trả về true nếu phần tử cụ thể đã được thêm vào bộ sưu tập.
Cú pháp:
public boolean add(Object obj)
contains(Object obj) Phương thức trả về true nếu bộ sưu tập này chứa phần tử cụ thể.
Cú pháp
public boolean contains(Object obj)
isEmpty() Phương thức trả về true nếu bộ sưu tập này không chứa bất kỳ phần tử nào.
Cú pháp:
public boolean isEmpty()
size() Phương thức trả về số lượng phần tử trong bộ sưu tập.
Cú pháp:
public int size()
clear() : Phương thức xóa hoặc loại bỏ tất cả nội dung khỏi bộ sưu tập.
toArray() : Phương thức trả về một mảng chứa tất cả các phần tử của bộ sưu tập này.
Duyệt bộ sưu tập (Traversing Collections)
Phần sau mô tả hai cách để duyệt các bộ sưu tập:
Sử dụng cấu trúc for-each
Điều này giúp duyệt một bộ sưu tập hoặc mảng bằng cách sử dụng vòng lặp for. Đoạn mã dưới minh họa cách sử dụng cấu trúc for-each để in ra từng phần tử của một bộ sưu tập trên mỗi dòng riêng biệt.
Ví dụ:
for (Object obj : collection)
System.out.print(obj);
Ở đây, trong đoạn mã này, collection được cho là một đối tượng kiểu Collection, chẳng hạn như một đối tượng Vector hoặc đối tượng ArrayList.
Cấu trúc for-each không cho phép loại bỏ phần tử hiện tại bằng cách gọi phương thức remove() vì nó che giấu Iterator.
Sử dụng Iterator
Điều này giúp đi qua một bộ sưu tập. Nó cũng giúp loại bỏ các phần tử khỏi bộ sưu tập một cách lựa chọn.
Phương thức iterator() được gọi để lấy một Iterator cho một bộ sưu tập. Giao diện Iterator bao gồm các phương thức sau:
public interface Iterator<E> {
boolean hasNext();
E next();
void remove(); // tùy chọn
}
Giao diện Iterator được mô tả như sau:
- Phương thức hasNext() trả về true nếu việc duyệt còn nhiều phần tử.
- Phương thức next() trả về phần tử tiếp theo trong quá trình duyệt.
- Phương thức remove() loại bỏ phần tử cuối cùng được trả về bởi phương thức next() khỏi Collection. Phương thức remove() chỉ có thể được gọi một lần cho mỗi lần gọi phương thức next(). Nếu không tuân theo điều này, phương thức remove() sẽ ném ra một ngoại lệ.
Lưu ý: Chỉ có phương thức Iterator.remove() làm thay đổi một Collection một cách an toàn trong quá trình duyệt.
Ví dụ:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListIteratorExample {
public static void main(String[] args) {
// Create a list (ArrayList in this example)
List<String> myList = new ArrayList<>();
// Add some elements to the list
myList.add("Apple");
myList.add("Banana");
myList.add("Cherry");
myList.add("Date");
// Create an Iterator for the list
Iterator<String> iterator = myList.iterator();
// Iterate through the list using the Iterator
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}
}
}
Các hoạt động hàng loạt
Các hoạt động hàng loạt thực hiện các hoạt động tắt trên toàn bộ Collection bằng cách sử dụng các hoạt động cơ bản.
Bảng dưới mô tả các phương thức cho các hoạt động hàng loạt:
- containsAll() Phương thức này sẽ trả về true nếu Collection mục tiêu chứa tất cả các phần tử có trong Collection cụ thể.
- addAll() Phương thức này sẽ thêm tất cả các phần tử của Collection cụ thể vào Collection mục tiêu.
- removeAll() Phương thức này sẽ loại bỏ tất cả các phần tử từ Collection mục tiêu có trong Collection cụ thể.
- retainAll() Phương thức này sẽ loại bỏ các phần tử từ Collection mục tiêu mà không tồn tại trong Collection cụ thể.
Các phương thức addAll(), removeAll() và retainAll() trả về true nếu Collection mục tiêu bị sửa đổi trong quá trình thực hiện hoạt động.
Các phương thức tiện ích cho bộ sưu tập (Collections)
Trước phiên bản JDK8, Java đã nhận được rất nhiều chỉ trích về tính lặp đi lặp lại của nó. Việc tạo một bộ sưu tập nhỏ không thể sửa đổi (như một set) đòi hỏi viết mã dài. Từ JDK 9 trở đi và các phiên bản cao hơn đã tích hợp Các Phương thức Tiện Ích Bộ Sưu Tập để tạo các phiên bản bộ sưu tập nhỏ không thể sửa đổi, hiệu quả với một dòng mã duy nhất. Chúng giúp tạo ra một giao diện bộ sưu tập nhỏ, hiệu suất cao. API đã được thiết kế giữ lại mức tối giúp người dùng có thể tạo bộ sưu tập với rất ít trường hợp.
Cấu trúc chung của API
Để tạo Map và collections, người dùng có thể sử dụng các phương thức tĩnh trên các giao diện Collection (List, Set và Map). Các phương thức này được gọi là of(). Phương thức of() có 11 phiên bản được nạp chồng, mỗi phiên bản có thể lấy từ không đến mười phần tử. Một phương thức được nạp chồng lấy một biến đối số để xây dựng một bộ sưu tập không thể thay đổi từ một số phần tử bất kỳ. Người dùng có thể truyền một số lượng phần tử tùy ý của một loại cụ thể vào một phương thức. Bên trong, phương thức sẽ gói các phần tử vào một mảng của loại cụ thể đó và truyền nó đi. Vì mục tiêu chính của các phương thức tiện ích mới là cung cấp API hiệu suất cao để xây dựng các bộ sưu tập không thể thay đổi, việc sao chép các phần tử vào một mảng sẽ ảnh hưởng đến hiệu suất. Do đó, để hỗ trợ việc xây dựng một bộ sưu tập hoặc một Map có nhiều hơn 10 phần tử, JDK 9 trở đi đã cung cấp mười một phương thức of() (lấy từ 0 đến 10 phần tử) để tránh việc cấp phát, khởi tạo mảng và gây ra hiệu suất thu gom rác. Nếu người dùng phải xây dựng một bộ sưu tập với nhiều hơn 10 phần tử, phương thức dùng var-args phải được sử dụng.
Xét các phương thức tiện ích tĩnh được thêm vào từ phiên bản Java 9 trở đi cho các giao diện Collection.
List.of()
Phương thức of() đã được thêm vào giao diện List.
List<String> emptyList = List.of();
Điều này tạo ra một danh sách trống. Trong phương pháp trước đó, sử dụng Collections.emptyList(), nó trả về một danh sách trống không thể thay đổi.
List<String> singleElementList = List.of("a");
Điều này tạo ra một danh sách có một phần tử. Trong phiên bản trước đó, sử dụng Collections.singletonList(“a”) để xây dựng một danh sách có một phần tử.
Tuy nhiên, trước đó không có cách nào để tạo một danh sách với nhiều hơn một phần tử trong một dòng lệnh duy nhất. Phương thức List.of() đã được nạp chồng để phát triển một danh sách không thể thay đổi hiệu quả với tối đa 10 phần tử. Bây giờ, việc tạo danh sách bằng phương thức of() trở nên dễ dàng. Mã nguồn trông sạch sẽ và lịch lãm.
List<String> list = List.of("a", "b", "c");
Nếu truyền hơn 10 phần tử, phương thức of() sẽ được gọi với sự nạp chồng var-args (như được hiển thị).
List<String> bigList = List.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k");
Set.of()
Set.of() tương tự như List.of(), ngoại trừ rằng nó trả về một Set.
Set<String> emptySet = Set.of();
Điều này tạo ra một tập hợp trống (tương đương với Collections.emptySet().
Set<String> singleElementSet = Set.of("a");
Lời gọi này đến of() truyền một phần tử để tạo ra một tập hợp với một phần tử. Trước đây, trước Java 9, điều này đã được thực hiện bằng Collections.singleton(“a”).
Set<String> set = Set.of("a", "b", "c");
Lời gọi cuối cùng tạo ra một tập hợp có ba phần tử.
Tương tự nếu muốn tạo nhiều hơn, truyền số lượng tham số tương ứng thông qua phương thức nạp chồng của of.
Map.of()
Một Map có một tập hợp các mục dưới dạng cặp khóa-giá trị. API phải giúp người dùng tạo cả hai.
Phương thức Map.of() có 11 phiên bản nạp chồng bắt đầu với:
- Một phiên bản để tạo ra một Map trống.
- Một phiên bản để tạo ra một Map với một cặp khóa-giá trị trong đó, và cứ thế cho đến phiên bản tạo ra một Map với 5 cặp khóa-giá trị trong đó.
Phương thức of() chấp nhận các cặp khóa và giá trị một sau một.
Map<String, Integer> emptyMap = Map.of();
Người dùng có thể tạo một Map bất biến trống bằng cách gọi phương thức of().
Map<String, Integer> singleEntryMap = Map.of("a", 1);
Mã này tạo ra một Map bất biến với một mục trong đó (“a=1”).
Map<String, Integer> map = Map.of("a", 1, "b", 2, "c", 3);
Lệnh này tạo ra một Map bất biến có ba mục (phần tử). Khóa của mục đầu tiên là “a” và giá trị là 1. Khóa của mục thứ hai là “b” và giá trị là 2, và cuối cùng, khóa của mục thứ ba là “c” và giá trị là 3.
map = Map.of("a", 1, "b", 2, "c", 3, "d", 4, "e", 5, "f", 6, "g", 7, "h", 8, "i", 9, "j", 10);
System.out.println(map); // {a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10}
Trong câu lệnh này, phương thức of() bị nạp chồng bằng cách truyền 10 cặp khóa-giá trị. Người dùng sẽ không thể thêm một mục khác (ví dụ: “k”, 11) vào Map vì chỉ có 11 phiên bản nạp chồng của phương thức of().
Khác với Sets và Lists, người dùng không thể thêm một var-arg vì kiểu của khóa và giá trị luôn luân phiên trong phương thức of(). Kiểu của các phần tử tùy ý truyền dưới dạng var-args phải cùng kiểu. Để khắc phục vấn đề tạo một map có nhiều hơn năm mục, người dùng có thể sử dụng phương thức ofEntries(). Điều này gọi đến các phiên bản nạp chồng của phương thức of() truyền 10 cặp khóa-giá trị. Mục khác (ví dụ: “k”, 11) không thể được thêm vào vì chỉ có 11 phiên bản nạp chồng của phương thức of().
Map.ofEntries() và Map.entry()
Phương thức Map.ofEntries() chấp nhận một đối số var-args kiểu Map.Entry. Map.Entry là một giao diện lồng (nested) của giao diện Map. Vì vậy, người dùng có thể tạo nhiều mục bằng cách tạo nhiều thể hiện của Map.Entry và chuyển chúng cho phương thức ofEntries().
Giao diện Map đã thêm một phương thức, entry(), để tạo một thể hiện kiểu Map.Entry. Nó trả về một mục không thể sửa đổi (unmodifiable) sử dụng khóa và giá trị được chuyển. Vì mục không thể sửa đổi, việc gọi setValue() trên Entry trả về sẽ ném ra một ngoại lệ UnsupportedOperationException.
Ví dụ:
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.mycompany;
import java.util.Map;
/**
*
* @author toan1
*/
public class ExampleMapEntries {
public static void main(String[] args) {
Map<String, Integer> map = Map.ofEntries(
Map.entry("a", 1),
Map.entry("b", 2),
Map.entry("c", 3)
);
for(Map.Entry<String, Integer> item : map.entrySet() ){
System.out.println(item.getKey() + " -- " + item.getValue());
}
}
}
Trong ví dụ này, Map.ofEntries() được sử dụng để tạo một Map bất biến với các mục được tạo bằng phương thức Map.entry().
Lưu ý giá trị null
Cần cẩn thận với việc sử dụng giá trị null. Không phải tất cả các phương thức đã được đề cập phía trên đều cho phép giá trị null. Điều này là một điều tốt để tránh ngoại lệ tại thời gian chạy và phát hiện lỗi sớm. Việc tránh sử dụng null cải thiện hiệu suất thời gian chạy của Collection trả về. Người dùng không thể truyền giá trị null cho các phương thức sau: Set.of(), Map.of(), List.of(). Điều này cũng đúng cho Map.entry() và Map.ofEntries().
Các lớp cụ thể của các Factory Method
Các lớp cụ thể (Concrete class) là các kiểu của bộ sưu tập và MAp được trả về bởi factory method.
Các Factory Method này trả về một đối tượng nội bộ trong JDK. Chúng không phải là bất kỳ một trong các cài đặt bộ sưu tập công khai. Không có đảm bảo về kiểu dữ liệu được trả về và nó có thể thay đổi trong tương lai. Người dùng phải lập trình theo giao diện và coi đối tượng trả về như một List, Set, hoặc Map, không thể trả về dữ liệu các lớp cụ thể như ArrayList hoặc LinkedList hay HashSet, HashMap hoặc TreeMap.
Một lớp đặc biệt được sử dụng để thiết lập từ một đến hai phần tử và ánh xạ từ một mục. Nó trả về một thể hiện khác cho các bộ sưu tập với hơn hai phần tử (một Map với nhiều hơn một mục).
Chuyển đổi từ Collection sang mảng
Một trong các cấu trúc dữ liệu cơ bản trong Java là mảng. Mảng là một cấu trúc dữ liệu tuyến tính chứa các phần tử, và kích thước của nó được xác định khi nó được tạo. Mảng có thể chứa các đối tượng hoặc dữ liệu nguyên thủy có cùng loại dữ liệu. Collection là một lớp được định nghĩa sẵn trong Java, giữ chứa các đối tượng đa dạng mà không cùng loại dữ liệu, bao gồm cả đối tượng và dữ liệu nguyên thủy. Người lập trình có thể sử dụng phương thức List.add() hoặc List.toArray() để chuyển đổi một Collection thành mảng.
Sử dụng phương thức List.add()
Chèn một phần tử element
vào vị trí được chỉ định index
trong danh sách sử dụng phương thức List.add().
Cú pháp:
public void add(int index, E element);
Trong đó:
index
là vị trí mà phần tử sẽ được chèn vào.E
là phần tử sẽ được chèn vào.
Phương thức có thể gây ra ngoại lệ IndexOutOfBoundsException
khi vị trí index
không nằm trong phạm vi hợp lệ.
Ví dụ:
import java.util.ArrayList;
import java.util.List;
public class CollectionToArrayExample {
public static void main(String[] args) {
// Tạo một ArrayList và thêm các phần tử vào nó
List<String> list = new ArrayList<>();
list.add("Lets");
list.add("start");
list.add("Power");
list.add("programming");
list.add("With");
list.add("Java");
// Chuyển đổi danh sách thành mảng
String[] array = list.toArray(new String[list.size()]);
// In từng phần tử của mảng
for (String element : array) {
System.out.println(element);
}
}
}
Kết quả của chương trình sẽ in ra các phần tử của mảng theo thứ tự.
Ví dụ 2:
/*
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
*/
package com.mycompany;
/**
*
* @author toan1
*/
import java.util.*;
import java.io.*;
public class ExampleListToArrayInput {
public static void main(String[] args) {
// Creating ArrayList to store user input
List<String> list = new ArrayList<String>();
// Creating object of Scanner class
Scanner sc = new Scanner(System.in);
// Taking input from the user and adding elements to the List
while (sc.hasNext()) {
String input = sc.nextLine();
if(input.equals("exit")){
break;
}
list.add(input);
}
// Converting list to an array
String[] str = list.toArray(new String[0]);
// Iterating over the array
for (int i = 0; i < str.length; i++) {
String data = str[i];
// Printing the elements
System.out.print(data + " ");
}
}
}
Bộ sưu tập không thay đổi (UnModifiable Collections)
Phương thức unmodifiableCollection() trong lớp java.util.collections trả về một chế độ xem bất biến của Collection đã được chỉ định. Nó cho phép các module khác cung cấp quyền truy cập chỉ đọc vào các bộ sưu tập nội bộ. Các thao tác truy vấn và bất kỳ cố gắng sửa đổi Collection đã trả về, bất kể thông qua trình lặp của nó hoặc trực tiếp, sẽ gây ra ngoại lệ UnsupportedOperationException.
Collection đước trả về không chuyển các phép toán hashCode và equals thông qua Collection gốc mà phụ thuộc vào các phương thức equals() và hashCode() của Object. Để duy trì các hợp đồng nếu Collection gốc là một tập hợp hoặc danh sách, Collection đã trả về sẽ không chuyển các phép toán hashC
ode
hoặc equals. Nó sẽ hoàn toàn phụ thuộc vào các phương thức hashCode() và equals() của Object.
Collection đã trả về có thể được serializable nếu Collection đã chỉ định là serializable.
Cú pháp:
public static <T> Collection<T> unmodifiableCollection(Collection<? extends T> c)
Phương thức này nhận một Collection làm tham số, từ đó trả về một chế độ xem không thay đổi của Collection đã chỉ định.
Ví dụ:
import java.util.*;
public class UnmodifiableCollectionDemo {
public static void main(String[] argv) {
try {
// Creating an ArrayList of characters
List<Character> list = new ArrayList<Character>();
// Populate the list
list.add('x');
list.add('y');
// Printing the initial list
System.out.println("Initial list: " + list);
// Creating an unmodifiable list using unmodifiableCollection() method
Collection<Character> immutableList = Collections.unmodifiableCollection(list);
// Attempt to modify the unmodifiable list - this should throw an exception
immutableList.add('z');
// This line will never be reached due to the exception
System.out.println("This will not be printed.");
} catch (UnsupportedOperationException e) {
System.out.println("Exception thrown: " + e);
}
}
}
Danh sách (List)
Giao diện (interface) List là một phần mở rộng của giao diện Collection. Nó xác định một bộ sưu tập có thứ tự của dữ liệu và cho phép thêm các đối tượng trùng lặp vào danh sách. Ưu điểm của nó là nó cung cấp các phép toán liên quan đến vị trí, cho phép các lập trình viên làm việc với một phần của danh sách.
Giao diện List sử dụng một chỉ mục để sắp xếp các phần tử khi lưu trữ chúng trong danh sách. List có các phương thức cho phép truy cập các phần tử dựa trên vị trí của chúng, tìm kiếm một phần tử cụ thể và trả về vị trí của nó, cũng như thực hiện các phép toán trên một phạm vi bất kỳ. Nó cũng cung cấp List Iterator để tận dụng tính tuần tự của nó.
Các phương thức của giao diện List
Các phương thức được hỗ trợ bởi giao diện List như sau:
Phương thức add()
add(int index, E element)
Phương thức này thêm phần tử đã chỉ định tại vị trí cụ thể bởi chỉ số trong danh sách.
Cú pháp
public void add(int index, E element)
Phương thức addAll()
addAll(int index, Collection c)
Phương thức này thêm tất cả các phần tử của bộ sưu tập đã chỉ định, c
, vào danh sách, bắt đầu từ chỉ mục đã cho.
Cú pháp
public boolean addAll(int index, Collection<? extends E> c)
Phương thức get(int index)
Phương thức này truy xuất phần tử từ vị trí chỉ định.
Cú pháp
public E get(int index)
Phương thức set(int index, E element)
Phương thức này thay thế phần tử có sẵn tại vị trí đã chỉ định bởi chỉ số trong danh sách bằng phần tử đã chỉ định.
Cú pháp
public E set(int index, E element)
Phương thức remove(int index)
Phương thức này loại bỏ phần tử ở vị trí chỉ định từ danh sách.
Cú pháp
public E remove(int index)
Phương thức subList(int start, int end)
Phương thức này trả về một danh sách chứa các phần tử từ vị trí bắt đầu đến vị trí kết thúc (trừ 1) của danh sách gọi.
Cú pháp
public List<E> subList(int start, int end)
Một số phương thức khác:
indexOf(Object o) Phương thức này trả về chỉ số của lần xuất hiện đầu tiên của phần tử đã chỉ định trong danh sách hoặc trả về -1 nếu danh sách không chứa phần tử đã cho.
lastIndexOf(Object o) Phương thức này trả về chỉ số của lần xuất hiện cuối cùng của phần tử đã chỉ định trong danh sách hoặc trả về -1 nếu danh sách không chứa phần tử đã cho.
Lớp ArrayList
Lớp ArrayList tạo ra một mảng có chiều dài biến đổi cho các tham chiếu đối tượng. Danh sách không thể lưu trữ các giá trị nguyên thủy như double. Trong Java, mảng tiêu chuẩn có độ dài cố định và chúng không thể tăng hoặc giảm kích thước của mình một cách động. Mảng danh sách được tạo với kích thước ban đầu. Sau này khi các phần tử được thêm vào, kích thước tăng lên và mảng sẽ mở rộng khi cần.
Lớp ArrayList bao gồm tất cả các phần tử, bao gồm cả giá trị null. Ngoài việc triển khai các phương thức của giao diện List, lớp này cung cấp các phương thức để thay đổi kích thước của mảng được sử dụng bên trong để lưu trữ danh sách.
Mỗi thể hiện ArrayList bao gồm một dung lượng biểu thị kích thước của mảng. Dung lượng này lưu trữ các phần tử trong danh sách và tự động tăng khi các phần tử được thêm vào một ArrayList.
Lớp ArrayList thích hợp nhất cho việc truy cập ngẫu nhiên mà không cần chèn hoặc loại bỏ các phần tử từ bất kỳ vị trí nào ngoài cuối danh sách.
Một thể hiện của ArrayList có thể được tạo bằng cách sử dụng bất kỳ một trong các hàm khởi tạo sau:
- ArrayList(): Hàm tạo này tạo ra một danh sách rỗng với sức chứa ban đầu là 10.
- ArrayList(Collection<? extends E> c): Hàm tạo này tạo ra một danh sách mảng chứa các phần tử của bộ sưu tập được chỉ định. Các phần tử được lưu trữ trong mảng theo thứ tự chúng được trả về bởi bộ sưu tập.
- ArrayList(int initialCapacity): Hàm tạo này tạo ra một danh sách mảng rỗng với sức chứa được chỉ định ban đầu. Kích thước sẽ tự động tăng khi các phần tử được thêm vào danh sách.
Ví dụ:
import java.util.ArrayList;
import java.util.List;
public class ArrayListExample {
public static void main(String[] args) {
// Creating an ArrayList using the default constructor
ArrayList<String> fruits = new ArrayList<>();
// Adding elements to the ArrayList
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
fruits.add("Date");
fruits.add("Fig");
// Display the ArrayList
System.out.println("Fruits ArrayList: " + fruits);
// Creating an ArrayList with an initial capacity
ArrayList<Integer> numbers = new ArrayList<>(10);
// Adding elements to the numbers ArrayList
for (int i = 1; i <= 10; i++) {
numbers.add(i);
}
// Display the numbers ArrayList
System.out.println("Numbers ArrayList: " + numbers);
// Creating an ArrayList from another collection
List<String> moreFruits = new ArrayList<>();
moreFruits.add("Grape");
moreFruits.add("Kiwi");
ArrayList<String> combinedList = new ArrayList<>(fruits);
combinedList.addAll(moreFruits);
// Display the combined ArrayList
System.out.println("Combined ArrayList: " + combinedList);
// Accessing elements in an ArrayList
String fruit = fruits.get(2); // Retrieve the element at index 2 (Cherry)
System.out.println("Fruit at index 2: " + fruit);
// Removing an element from the ArrayList
combinedList.remove("Banana");
// Display the modified combined ArrayList
System.out.println("Combined ArrayList after removing Banana: " + combinedList);
// Checking if an element exists in the ArrayList
boolean containsDate = fruits.contains("Date");
System.out.println("Does the fruits ArrayList contain Date? " + containsDate);
// Getting the size of the ArrayList
int sizeOfNumbers = numbers.size();
System.out.println("Size of the numbers ArrayList: " + sizeOfNumbers);
// Iterating through the ArrayList
System.out.println("Iterating through the fruits ArrayList:");
for (String f : fruits) {
System.out.println(f);
}
}
}
Các phương thức lớp ArrayList
Lớp ArrayList kế thừa tất cả các phương thức của giao diện List.
Các phương thức quan trọng trong lớp ArrayList bao gồm:
- add(Object obj): Phương thức này thêm một phần tử được chỉ định vào cuối danh sách.
- trimToSize(): Phương thức này giảm kích thước của ArrayList xuống bằng kích thước hiện tại của danh sách.
- ensureCapacity(int minCap): Phương thức này được sử dụng để tăng sức chứa của ArrayList và đảm bảo rằng nó có thể chứa ít nhất số phần tử được chỉ định.
- clear(): Phương thức này xóa tất cả các phần tử khỏi danh sách.
- contains(Object obj): Phương thức này trả về true nếu danh sách này chứa phần tử cụ thể.
- size(): Phương thức này trả về số lượng phần tử trong danh sách.
Ví dụ:
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
System.out.println("Fruits after adding: " + fruits);
ArrayList<String> cities = new ArrayList<>(20);
cities.add("New York");
cities.add("Los Angeles");
cities.trimToSize(); // Reduces the capacity to match the size
ArrayList<Integer> numbers = new ArrayList<>();
numbers.ensureCapacity(10); // Ensure that it can hold at least 10 elements
ArrayList<String> colors = new ArrayList<>();
colors.add("Red");
colors.add("Green");
colors.add("Blue");
colors.clear(); // Removes all elements
ArrayList<String> animals = new ArrayList<>();
animals.add("Lion");
animals.add("Tiger");
animals.add("Bear");
boolean containsTiger = animals.contains("Tiger"); // true
ArrayList<Integer> data = new ArrayList<>();
data.add(1);
data.add(2);
data.add(3);
int size = data.size(); // Returns 3
Lớp Vector
Lớp Vector tương tự như ArrayList, bởi vì cả hai đều triển khai mảng động. Lớp Vector lưu trữ một mảng các đối tượng và kích thước của mảng có thể tăng hoặc giảm. Các phần tử trong Vector có thể được truy cập bằng một chỉ số nguyên.
Mỗi Vector duy trì một khả năng (capacity) và một capacityIncrement để tối ưu hóa quản lý lưu trữ. Lưu trữ của Vector tăng theo cách mà được xác định bởi capacityIncrement khi các thành phần được thêm vào.
Lưu ý: Lượng dự phòng tăng cường có thể giảm bằng cách tăng khả năng của một Vector trước khi chèn một số lượng lớn các thành phần.
Sự khác biệt giữa lớp Vector và lớp ArrayList là các phương thức của Vector được đồng bộ hóa và an toàn đối với luồng (thread-safe). Điều này tăng chi phí quản lý luồng khi gọi các phương thức này. Không giống như ArrayList, lớp Vector cũng chứa các phương thức kế thừa (legacy methods) không phải là một phần của collections framework.
Các hàm khởi tạo (constructors) của lớp Vector bao gồm:
- Vector(): Hàm tạo này tạo một Vector trống với kích thước mảng ban đầu là 10.
- Vector(Collection<? extends E>): Hàm tạo này tạo một Vector chứa các phần tử của bộ sưu tập được chỉ định. Các phần tử được lưu trữ theo thứ tự mà chúng được trả về bởi trình lặp của bộ sưu tập.
- Vector(int initCapacity): Hàm tạo này tạo một Vector trống với khả năng ban đầu được chỉ định trong biến initCapacity.
- Vector(int initCapacity, int capIncrement): Hàm tạo này tạo một Vector với khả năng ban đầu và khả năng tăng dần được chỉ định trong các biến initCapacity và capIncrement.
Ví dụ:
import java.util.Vector;
public class VectorExample {
public static void main(String[] args) {
// Create a Vector of Strings
Vector<String> colors = new Vector<>();
// Adding elements to the Vector
colors.add("Red");
colors.add("Green");
colors.add("Blue");
colors.add("Yellow");
// Display the Vector
System.out.println("Colors Vector: " + colors);
// Accessing elements in a Vector
String color = colors.get(2); // Retrieve the element at index 2 (Blue)
System.out.println("Color at index 2: " + color);
// Removing an element from the Vector
colors.remove(1); // Remove the element at index 1 (Green)
// Display the modified Vector
System.out.println("Colors Vector after removing index 1: " + colors);
// Checking if an element exists in the Vector
boolean containsRed = colors.contains("Red");
System.out.println("Does the colors Vector contain Red? " + containsRed);
// Getting the size of the Vector
int size = colors.size();
System.out.println("Size of the colors Vector: " + size);
// Iterating through the Vector
System.out.println("Iterating through the colors Vector:");
for (String c : colors) {
System.out.println(c);
}
}
}
Các phương thức lớp Vector
Lớp Vector định nghĩa ba thành viên được bảo vệ (protected members) quan trọng:
- int capacityIncrement: Lưu trữ giá trị tăng dự phòng.
- int elementCount: Lưu trữ số thành phần hợp lệ hiện tại trong Vector.
- Object[] elementData: Là bộ đệm mảng trong đó lưu trữ các thành phần của Vector.
Các phương thức quan trọng trong lớp Vector bao gồm:
- addElement(Object obj): Phương thức này thêm một phần tử vào cuối của Vector và tăng kích thước của Vector lên 1. Khả năng của Vector tăng lên nếu kích thước vượt qua khả năng hiện tại.
- capacity(): Phương thức này trả về khả năng (capacity) hiện tại của Vector.
- toArray(): Phương thức này trả về một mảng chứa tất cả các phần tử hiện có trong Vector theo thứ tự đúng.
- elementAt(int pos): Phương thức này lấy ra đối tượng được lưu trữ tại vị trí cụ thể.
- removeElement(Object obj): Phương thức này loại bỏ sự xuất hiện đầu tiên của đối tượng được chỉ định khỏi Vector.
- clear(): Phương thức này loại bỏ tất cả các phần tử của Vector.
List Interface và Lớp LinkedList
Một tập hợp có thứ tự được gọi là danh sách (List). Nó còn được gọi là một chuỗi tuần tự (sequence).
Dưới đây là các tính năng của một danh sách (List):
- Người dùng có quyền kiểm soát từng phần tử trong danh sách.
- Người dùng có thể truy cập và tìm kiếm các phần tử trong danh sách bằng chỉ số nguyên.
- Các phần tử trùng lặp có thể tồn tại trong danh sách.
- Có thể tồn tại nhiều phần tử null.
- Chỉ số nguyên có thể được sử dụng để truy cập và tìm kiếm phần tử trong danh sách.
- Tương tự như mảng trong Java, danh sách được đánh số từ 0.
Giao diện List bao gồm bốn phương thức cho việc truy cập theo chỉ số vào các phần tử của danh sách.
Giao diện List bao gồm các khai báo bổ sung sử dụng iterator(), remove(), add(), hashCode() và phương thức equals(). Phương thức equals() giúp kiểm tra tính logic của hai đối tượng danh sách (List). Hai đối tượng List được xem là bằng nhau nếu chúng chứa cùng các phần tử trong cùng thứ tự. Nó có thể bao gồm các khai báo cho các phương thức kế thừa khác.
Giao diện List cung cấp ListIterator, một loại iterator đặc biệt. Đây được sử dụng để chèn và thay thế một phần tử và cũng dùng để truy cập theo hai chiều cùng với các thao tác bình thường. Một phương thức được sử dụng để có một trình duyệt danh sách (list iterator) bắt đầu từ một vị trí cụ thể trong danh sách.
Có hai phương thức trong giao diện List để tìm kiếm một đối tượng cụ thể. Tuy nhiên, các phương thức này có thể thực hiện tìm kiếm tuyến tính tốn kém.
Giao diện List cũng bao gồm hai phương thức để chèn và loại bỏ nhiều phần tử tại một vị trí tùy ý trong danh sách.
Lớp LinkedList triển khai từ giao diện List. Mảng lưu trữ các đối tượng trong các vị trí bộ nhớ liên tiếp, trong khi danh sách liên kết lưu trữ các đối tượng dưới dạng các liên kết riêng biệt. Nó cung cấp một cấu trúc dữ liệu danh sách liên kết. Danh sách liên kết (linked list) là một danh sách các đối tượng có liên kết đến đối tượng tiếp theo. Thông thường, mỗi mục như vậy gọi là một nút (node).
Danh sách liên kết cho phép chèn và loại bỏ nút ở bất kỳ vị trí nào trong danh sách, nhưng không cho phép truy cập ngẫu nhiên. Có nhiều loại danh sách liên kết khác nhau – danh sách liên kết đơn (singly-linked list), danh sách liên kết đôi (doubly-linked list), và danh sách liên kết vòng (circularly-linked list).
Java cung cấp lớp LinkedList trong gói java.util để triển khai danh sách liên kết.
- Lớp LinkedList() constructor tạo một danh sách liên kết trống.
- Lớp LinkedList(Collection c) constructor tạo một danh sách liên kết chứa các phần tử từ một bộ sưu tập cụ thể, theo thứ tự chúng được trả về bởi trình lặp của bộ sưu tập.
Ví dụ:
import java.util.LinkedList;
public class LinkedListExample {
public static void main(String[] args) {
// Create a LinkedList of Strings
LinkedList<String> names = new LinkedList<>();
// Adding elements to the LinkedList
names.add("Alice");
names.add("Bob");
names.add("Charlie");
// Display the LinkedList
System.out.println("Names LinkedList: " + names);
// Adding elements at the beginning and end of the LinkedList
names.addFirst("David");
names.addLast("Eve");
// Display the modified LinkedList
System.out.println("Names LinkedList after adding first and last: " + names);
// Accessing elements in a LinkedList
String firstElement = names.getFirst();
String lastElement = names.getLast();
System.out.println("First element: " + firstElement);
System.out.println("Last element: " + lastElement);
// Removing elements from the LinkedList
names.remove(2); // Remove the element at index 2 (Charlie)
names.removeFirst(); // Remove the first element (David)
names.removeLast(); // Remove the last element (Eve)
// Display the modified LinkedList
System.out.println("Names LinkedList after removing elements: " + names);
// Checking if an element exists in the LinkedList
boolean containsAlice = names.contains("Alice");
System.out.println("Does the names LinkedList contain Alice? " + containsAlice);
// Getting the size of the LinkedList
int size = names.size();
System.out.println("Size of the names LinkedList: " + size);
// Iterating through the LinkedList
System.out.println("Iterating through the names LinkedList:");
for (String name : names) {
System.out.println(name);
}
}
}
Các phương thức của lớp LinkedList
Bên cạnh các phương thức được định nghĩa bởi giao diện List, các phương thức khác của lớp LinkedList bao gồm:
- addFirst(E obj): Phương thức này thêm đối tượng đã cho vào đầu danh sách (list).
- Cú pháp: public void addFirst(E obj)
- addLast(E obj): Phương thức này thêm đối tượng đã cho vào cuối danh sách (list).
- Cú pháp: public void addLast(E obj)
- getFirst(): Phương thức này lấy ra phần tử đầu tiên từ danh sách.
- Cú pháp: public E getFirst()
- getLast(): Phương thức này lấy ra phần tử cuối cùng từ danh sách.
- Cú pháp: public E getLast()
- removeFirst(): Phương thức này loại bỏ và trả về phần tử đầu tiên từ danh sách.
- Cú pháp: public E removeFirst()
- removeLast(): Phương thức này loại bỏ và trả về phần tử cuối cùng từ danh sách.
- Cú pháp: public E removeLast()
Autoboxing và Unboxing
Tính năng autoboxing và unboxing trong Java tự động hóa quá trình sử dụng các giá trị nguyên thuỷ trong một collection. Lưu ý rằng các collection chỉ chứa các tham chiếu đối tượng. Vì vậy, giá trị nguyên thuỷ, chẳng hạn như int, phải được đóng gói vào lớp bọc (wrapper class) tương ứng. Nếu cần một giá trị int, giá trị Integer phải được unbox bằng cách sử dụng phương thức intValue(). Tính năng autoboxing và unboxing giúp giảm bớt sự lộn xộn trong mã nguồn.
Khái niệm Sets
Giao diện Set được sử dụng để tạo một tập hợp các đối tượng không có thứ tự và không cho phép sự xuất hiện trùng lặp của các tham chiếu đối tượng.
Interface Set
Giao diện Set kế thừa tất cả các phương thức từ giao diện Collection ngoại trừ các phương thức cho phép các phần tử trùng lặp.
Nền tảng Java bao gồm ba cài đặt Set tổng quan. Chúng là:
- HashSet: HashSet lưu trữ các phần tử của nó trong một Hashtable và không đảm bảo thứ tự duyệt.
- TreeSet: TreeSet lưu trữ các phần tử của nó trong một cây và sắp xếp chúng dựa trên giá trị. Nó chậm hơn so với HashSet.
- LinkedHashSet: LinkedHashSet thực hiện Hashtable và một cài đặt danh sách liên kết của giao diện Set. Nó có một danh sách liên kết kép chạy qua tất cả các phần tử của nó và do đó khác với HashSet. Danh sách liên kết duyệt qua các phần tử theo thứ tự chúng được chèn vào tập hợp (thứ tự chèn).
So sánh giữa Set và List:
Giao diện Set là một phần mở rộng của giao diện Collection và xác định một tập hợp các phần tử. Sự khác biệt giữa List và Set là Set không cho phép các phần tử trùng lặp. Set được sử dụng để tạo một danh sách các tham chiếu đối tượng không trùng lặp. Do đó, phương thức add sẽ trả về giá trị false nếu thêm các phần tử trùng lặp.
Giao diện Set thích hợp nhất để thực hiện các hoạt động hàng loạt. Các phương thức hoạt động hàng loạt được hỗ trợ bởi giao diện Set bao gồm:
- containsAll(Collection obj): Phương thức này trả về true nếu đối tượng set gọi chứa tất cả các phần tử của bộ sưu tập được chỉ định. Cú pháp: public boolean containsAll(Collection<?> obj)
- addAll(Collection obj): Phương thức này thêm tất cả các phần tử của bộ sưu tập được chỉ định vào đối tượng set gọi. Cú pháp: public boolean addAll(Collection<? extends E> obj)
- retainAll(Collection obj): Phương thức này giữ lại trong đối tượng set gọi chỉ những phần tử có trong bộ sưu tập được chỉ định. Cú pháp: public boolean retainAll(Collection<?> obj)
- removeAll(Collection obj): Phương thức này loại bỏ tất cả các phần tử từ đối tượng set gọi mà có trong bộ sưu tập được chỉ định. Cú pháp: public boolean removeAll(Collection<?> obj)
Lưu ý: Hai đối tượng Set được xem là bằng nhau khi chúng chứa cùng các phần tử.
Interface SortSet
Giao diện SortedSet mở rộng giao diện Set và trình duyệt của nó đi qua các phần tử theo thứ tự tăng dần. Phần tử có thể được sắp xếp theo thứ tự tự nhiên hoặc bằng cách sử dụng một Comparator mà người dùng có thể cung cấp khi tạo một sorted set.
SortedSet được sử dụng để tạo danh sách sắp xếp của các tham chiếu đối tượng không trùng lặp. Thứ tự của một sorted set nên tuân theo phương thức equals(). Điều này vì giao diện Set được xác định dựa trên phép so sánh equals.
Một sorted set thực hiện tất cả các phép so sánh phần tử bằng cách sử dụng phương thức compareTo() hoặc compare(). Vì vậy, hai phần tử được coi là bằng nhau thông qua phương thức này có cùng trạng thái cho sorted set.
Lưu ý: Nếu thứ tự không tuân theo equals
, một sorted set sẽ cho kết quả là hành vi bình thường nhưng không tuân theo các hướng dẫn chung của giao diện set.
Thông thường, các lớp thực hiện sorted set cung cấp các constructor tiêu chuẩn sau:
- Constructor không tham số (void): Tạo một sorted set trống được sắp xếp theo thứ tự tự nhiên của các phần tử của nó.
- Constructor có một đối số là kiểu Comparator: Tạo một sorted set trống được sắp xếp theo Comparator được xác định.
- Constructor có một đối số là kiểu Collection: Tạo một sorted set mới với các phần tử tồn tại như là đối số của nó, được sắp xếp theo thứ tự tự nhiên của các phần tử.
- Constructor có một đối số là kiểu SortedSet: Tạo một sorted set mới với các phần tử và cùng thứ tự tồn tại trong sorted set đầu vào.
SortedSet định nghĩa một số phương thức bổ sung ngoài các phương thức được thừa kế từ giao diện set để làm cho việc xử lý set thuận tiện hơn.
Một số phương thức trong giao diện này bao gồm:
- first(): Phương thức này trả về phần tử đầu tiên hoặc thấp nhất trong sorted set.
- last(): Phương thức này trả về phần tử cuối cùng hoặc cao nhất trong sorted set.
- headSet(E endElement): Phương thức này trả về một sorted set chứa tất cả các phần tử từ đầu của set đến phần tử được chỉ định
endElement
, nhưng không bao gồmendElement
. - subSet(E startElement, E endElement): Phương thức này trả về một sorted set bao gồm các phần tử nằm giữa
startElement
vàendElement-1
. - tailSet(E fromElement): Phương thức này trả về một sorted set chứa các phần tử lớn hơn hoặc bằng
fromElement
và nằm trong sorted set gốc.
Cảnh báo: Một số phương thức sẽ ném ngoại lệ
NoSuchElementException
khi không có phần tử nào trong set. Khi một đối tượng không tương thích với các phần tử trong một set, nó sẽ ném ngoại lệClassCastException
, và nếu sử dụng một đối tượng null, nó sẽ ném ngoại lệNullPointerException
.
Lớp HashSet
Lớp HashSet triển khai giao diện Set. Một HashSet tạo một bộ sưu tập sử dụng bảng băm cho việc lưu trữ dữ liệu. Bảng băm là một cấu trúc dữ liệu lưu trữ thông tin bằng cách ánh xạ khóa của mỗi phần tử dữ liệu vào một vị trí hoặc chỉ số trong mảng. Một khóa là một bộ nhận dạng được sử dụng để tìm hoặc tra cứu một giá trị trong bảng băm. Ý nghĩa cụ thể của các khóa trong bất kỳ bảng băm nào hoàn toàn phụ thuộc vào cách bảng này được sử dụng và dữ liệu nó chứa. Việc biến đổi của một khóa thành mã băm của nó được thực hiện tự động. Mã nguồn của người dùng không thể truy cập trực tiếp vào bảng băm.
Lớp HashSet này cho phép tồn tại các phần tử không trùng lặp. Tuy nhiên, không có đảm bảo về thứ tự lặp qua của tập hợp và rằng thứ tự sẽ duy trì không thay đổi theo thời gian. Lớp HashSet cung cấp hiệu suất thời gian hằng số cho các hoạt động cơ bản.
Đối với việc lặp, thời gian nên tỷ lệ thuận với tổng kích thước của tập hợp HashSet và khả năng của bảng băm.
[Lưu ý: Để có hiệu suất lặp tốt, không nên đặt khả năng ban đầu quá cao hoặc hệ số tải quá thấp]
Các constructor của lớp HashSet bao gồm:
- HashSet(): Constructor tạo một hash set mặc định. Khả năng ban đầu và hệ số tải mặc định lần lượt là 16 và 0.75.
- HashSet(Collection<? extends E> c): Constructor tạo một hash set dựa trên các phần tử được cung cấp trong bộ sưu tập cụ thể.
- HashSet(int size): Constructor tạo một hash set với kích thước cụ thể và với hệ số tải mặc định là 0.75.
- HashSet(int size, float fillRatio): Constructor tạo một hash set với kích thước và hệ số điền cụ thể. Hệ số điền xác định mức độ lấp đầy của tập hợp trước khi nó được thay đổi kích thước lên trên.
Ví dụ:
Set<String> words = new HashSet<String>();
Lớp LinkedHashSet
Lớp LinkedHashSet tạo ra một danh sách các phần tử và duy trì thứ tự các phần tử được thêm vào Set. Nó bao gồm sự kết hợp của bảng băm và danh sách liên kết của giao diện Set. Nó khác với HashSet trong thứ tự lặp. Ở đây, một danh sách liên kết kép được duy trì chạy qua tất cả các mục. Danh sách liên kết này xác định thứ tự lặp, tức là thứ tự mà các phần tử được thêm vào tập hợp.
Lớp này bao gồm các tính năng sau:
- Cung cấp tất cả các hoạt động tùy chọn của tập hợp.
- Cho phép các phần tử null.
- Cung cấp hiệu suất thời gian hằng số cho các hoạt động cơ bản như thêm và loại bỏ.
Lưu ý: Hiệu suất của lớp LinkedHashSet có thể không tốt bằng HashSet do chi phí duy trì danh sách liên kết.
Đối với việc lặp qua LinkedHashSet, thời gian nên tỷ lệ thuận với kích thước tập hợp. Điều này không phụ thuộc vào khả năng lưu trữ của nó. Lặp qua HashSet có thể tốn thời gian hơn vì cần thời gian tỷ lệ thuận với khả năng của nó.
Khả năng ban đầu và hệ số tải ảnh hưởng đến hiệu suất của một tập hợp băm liên kết. Thời gian lặp qua LinkedHashSet không bị ảnh hưởng bởi khả năng lưu trữ. Lớp này không có các phương thức bổ sung và có các constructor nhận các tham số giống như lớp HashSet.
Các constructor của lớp này bao gồm:
- LinkedHashSet(): Constructor tạo một tập hợp băm liên kết mặc định. Khả năng ban đầu và hệ số tải mặc định lần lượt là 16 và 0.75.
- LinkedHashSet(Collection<? extends E> c): Constructor xây dựng một tập hợp băm liên kết mới với các phần tử giống với bộ sưu tập được chỉ định.
LinkedHashSet(int
initial capacity): Constructor xây dựng một tập hợp băm liên kết mới, rỗng với khả năng ban đầu được chỉ định.- LinkedHashSet(int initial capacity, float loadFactor): Constructor xây dựng một tập hợp băm liên kết mới, rỗng với khả năng ban đầu và hệ số tải được chỉ định.
Lớp TreeSet
Lớp TreeSet triển khai giao diện NavigableSet và sử dụng cấu trúc cây để lưu trữ dữ liệu. Các phần tử có thể được sắp xếp theo thứ tự tự nhiên hoặc sử dụng Comparator được cung cấp khi tạo tập hợp.
Các đối tượng được lưu trữ theo thứ tự tăng dần, do đó việc truy cập và trích xuất một đối tượng nhanh hơn nhiều. TreeSet sẽ được sử dụng khi các phần tử cần được trích xuất nhanh chóng từ bộ sưu tập theo cách đã sắp xếp.
Các constructor của lớp TreeSet bao gồm:
- TreeSet(): Constructor tạo một tập hợp cây trống với các phần tử được sắp xếp theo thứ tự tăng dần.
- TreeSet(Collection<? extends E> c): Constructor tạo một tập hợp cây mới chứa các phần tử của bộ sưu tập được chỉ định, được sắp xếp theo thứ tự của các phần tử.
- TreeSet(Comparator<? super E> c): Constructor tạo một tập hợp cây mới, rỗng và sẽ được sắp xếp theo Comparator được chỉ định.
- TreeSet(SortedSet<? extends E> s): Constructor tạo một tập hợp cây mới chứa các phần tử của SortedSet được chỉ định, theo thứ tự tương tự.
Ví dụ:
TreeSet tsObj = new TreeSet();
Khái niệm Maps
Một đối tượng Map lưu trữ dữ liệu dưới dạng mối quan hệ giữa các khóa (keys) và giá trị (values). Mỗi khóa sẽ ánh xạ ít nhất một giá trị. Nếu thông tin về khóa đã biết, giá trị có thể được truy xuất từ đối tượng Map. Các khóa nên là duy nhất, nhưng các giá trị có thể bị trùng lặp.
Interface Map
Giao diện Map không mở rộng giao diện Collection. Map có sự phân cấp riêng biệt để duy trì sự kết hợp giữa khóa và giá trị. Giao diện này mô tả một phép ánh xạ từ khóa sang giá trị, mà không có khóa trùng lặp.
API Collections cung cấp ba triển khai Map tổng quan cho mục đích sử dụng chung:
- HashMap
- TreeMap
- LinkedHashMap
HashMap được sử dụng để chèn, xóa và tìm kiếm các phần tử trong Map, trong khi TreeMap được sử dụng để sắp xếp các khóa theo thứ tự được sắp xếp. LinkedHashMap được sử dụng để xác định thứ tự lặp, thường là thứ tự mà các khóa được chèn vào Map.
Các phương thức quan trọng của giao diện Map bao gồm:
- put(K key, V value): Phương thức này liên kết giá trị đã cho với khóa đã cho trong đối tượng Map gọi. Nó ghi đè giá trị trước đó được liên kết với khóa và trả về giá trị trước đó hoặc null nếu không có liên kết nào với khóa đã cho.
- get(Object key): Phương thức này trả về giá trị được liên kết với khóa đã cho trong đối tượng Map gọi.
- containsKey(Object key): Phương thức này trả về true nếu đối tượng Map này chứa một ánh xạ cho khóa đã cho.
- containsValue(Object value): Phương thức này trả về true nếu đối tượng Map này ánh xạ một hoặc nhiều khóa tới giá trị đã cho.
- size(): Phương thức này trả về số cặp khóa-giá trị trong đối tượng Map.
- values(): Phương thức này trả về một tập hợp chứa tất cả các giá trị có trong đối tượng Map.
Làm việc với giao diện Map cho phép bạn thực hiện các thao tác quản lý dữ liệu phức tạp và tìm kiếm dữ liệu dựa trên khóa một cách hiệu quả.
Lớp HashMap
Lớp HashMap (HashMap class) triển khai giao diện Map và kế thừa tất cả các phương thức của nó. Một thể hiện của HashMap có hai tham số: khả năng ban đầu và hệ số tải (initial capacity và load factor). Khả năng ban đầu xác định số đối tượng có thể được thêm vào bảng băm tại thời điểm tạo bảng băm. Hệ số tải xác định mức độ tối đa mà bảng băm có thể trước khi dung lượng của nó tự động tăng lên.
HashMap rất giống với Hashtable với hai khác biệt chính:
- HashMap không được đồng bộ hóa, làm cho việc truy cập nhanh hơn.
- HashMap cho phép giá trị null được sử dụng làm giá trị hoặc khóa, trong khi Hashtable không cho phép việc này.
Lớp HashMap không đảm bảo thứ tự của bản đồ và không đảm bảo rằng thứ tự sẽ được duy trì không thay đổi theo thời gian.
Các hàm tạo (constructors) của lớp này bao gồm:
- HashMap(): Hàm tạo này tạo một HashMap trống với khả năng ban đầu mặc định và hệ số tải mặc định là 16 và 0.75.
- HashMap(int initialCapacity): Hàm tạo này tạo một HashMap trống với khả năng ban đầu cụ thể và hệ số tải mặc định là 0.75.
- HashMap(int initialCapacity, float loadFactor): Hàm tạo này tạo một HashMap trống với khả năng ban đầu và hệ số tải được chỉ định.
- HashMap(Map<? extends K,? extends V> m): Hàm tạo này tạo một HashMap tương tự với bản đồ được chỉ định.
Sử dụng lớp HashMap cho phép bạn lưu trữ dữ liệu trong một cặp khóa-giá trị, và dễ dàng truy cập giá trị dựa trên khóa tương ứng.
Ví dụ:
Tạo lớp EmployeeData
class EmployeeData {
String name;
int salary;
public EmployeeData(String nm) {
name = nm;
salary = 5600;
}
public String toString() {
return "[name=" + name + ", salary=" + salary + "]";
}
}
Tạo lớp ExamHashMap
import java.util.*;
public class TestObject {
public static void main(String[] args) {
Map<String, EmployeeData> staffObj = new HashMap<String, EmployeeData>();
staffObj.put("101", new EmployeeData("Anna John"));
staffObj.put("102", new EmployeeData("Harry Hacker"));
staffObj.put("103", new EmployeeData("Joby Martin"));
System.out.println(staffObj);
staffObj.remove("103");
staffObj.put("106", new EmployeeData("Joby Martin"));
System.out.println(staffObj.get("106"));
System.out.println(staffObj);
}
}
Lớp HashTable
Lớp Hashtable triển khai giao diện Map, nhưng lưu trữ các phần tử dưới dạng các cặp khóa/giá trị trong bảng băm (hash table). Trong Hashtable, một khóa (key) được chỉ định và gắn với một giá trị (value). Khóa sau đó được băm (hashed), và mã băm (hash code) được sử dụng như một chỉ số để lưu trữ giá trị tại vị trí tương ứng trong bảng băm. Lớp này kế thừa tất cả các phương thức của giao diện Map. Để lấy và lưu trữ đối tượng từ một bảng băm một cách thành công, các đối tượng được sử dụng làm khóa phải triển khai phương thức hashCode() và equals().
Các hàm tạo (constructors) của lớp này bao gồm:
- Hashtable(): Hàm tạo này tạo một bảng băm mới và trống.
- Hashtable(int initcap): Hàm tạo này tạo một bảng băm mới và trống với khả năng ban đầu được chỉ định.
- Hashtable(int initcap, float loadFactor): Hàm tạo này tạo một bảng băm mới và trống với khả năng ban đầu và hệ số tải được chỉ định.
- Hashtable(Map<? extends K, ? extends V> m): Hàm tạo này tạo một bảng băm mới chứa các cặp khóa/giá trị giống như một Map được chỉ định.
Lớp Hashtable cho phép bạn lưu trữ và truy xuất dữ liệu dưới dạng các cặp khóa/giá trị, và các khóa phải tuân thủ phương thức hashCode() và equals() để thực hiện việc lưu trữ và truy xuất dữ liệu.
Ví dụ:
import java.util.*;
public class HashtableDemo {
public static void main(String[] args) {
Hashtable<String, String> bookHash = new Hashtable<String, String>();
bookHash.put("115-355N", "A Guide to Advanced Java");
bookHash.put("116-455A", "Learn Java by Example");
bookHash.put("116-466B", "Introduction to Solaris");
String str = (String) bookHash.get("116-455A");
System.out.println("Detail of a book: " + str);
System.out.println("Is the table empty: " + bookHash.isEmpty());
System.out.println("Does the table contain the key '116-4665': " + bookHash.containsKey("116-4665"));
Enumeration<String> name = bookHash.keys();
while (name.hasMoreElements()) {
String bkCode = name.nextElement();
System.out.println(bkCode + ": " + bookHash.get(bkCode));
}
}
}
Lớp TreeMap
Lớp TreeMap triển khai giao diện NavigableMap và lưu trữ các phần tử trong một cấu trúc cây (tree structure). TreeMap trả về các khóa (keys) theo thứ tự được sắp xếp. Nếu không cần lấy các phần tử từ Map theo khóa đã được sắp xếp, thì lớp HashMap sẽ là một cấu trúc hiệu quả hơn để sử dụng.
Các hàm tạo (constructors) của lớp TreeMap bao gồm:
- TreeMap(): Hàm tạo này tạo một TreeMap trống.
- TreeMap(Comparator<? super K> c): Hàm tạo này tạo một TreeMap với keys được sắp xếp dựa trên Comparator đã cho.
- TreeMap(Map<? extends K, ? extends V> m): Hàm tạo này tạo một TreeMap mới chứa các cặp khóa/giá trị giống như một Map đã cho. TreeMap này sẽ sắp xếp các khóa theo thứ tự tự nhiên của chúng.
- TreeMap(SortedMap<K, ? extends V> m): Hàm tạo này tạo một TreeMap mới chứa các cặp khóa/giá trị giống như một SortedMap đã cho và sử dụng cùng Comparator của SortedMap đó.
Lớp TreeMap lưu trữ các phần tử trong cây và trả về các khóa theo thứ tự đã sắp xếp. Nó thích hợp khi cần truy xuất dữ liệu từ một Map theo thứ tự đã sắp xếp.
Ví dụ:
import java.util.*;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<String, EmployeeData> anotherStaffObj = new TreeMap<String, EmployeeData>();
anotherStaffObj.put("101", new EmployeeData("Anna John"));
anotherStaffObj.put("102", new EmployeeData("Harry Hacker"));
anotherStaffObj.put("103", new EmployeeData("Joby Martin"));
System.out.println(anotherStaffObj);
anotherStaffObj.remove("103");
anotherStaffObj.put("104", new EmployeeData("John Luther"));
System.out.println(anotherStaffObj.get("104"));
Object firstKey = anotherStaffObj.firstKey();
System.out.println(firstKey.toString());
System.out.println((String) anotherStaffObj.firstKey());
System.out.println((String) anotherStaffObj.lastKey());
}
}
Các phương thức của lớp TreeMap
Các phương thức quan trọng của lớp TreeMap bao gồm:
- firstKey(): Phương thức này trả về khóa đầu tiên trong sorted map.
- lastKey(): Phương thức này trả về khóa cuối cùng trong sorted map.
- headMap(K toKey): Phương thức này trả về một phần của map chứa các cặp khóa/giá trị có giá trị khóa nhỏ hơn giá trị được chỉ định bởi biến toKey.
- tailMap(K fromKey): Phương thức này trả về một phần của map chứa các cặp khóa/giá trị có khóa lớn hơn hoặc bằng giá trị được chỉ định bởi biến fromKey.
Các phương thức này cho phép bạn thực hiện các thao tác liên quan đến việc lấy các phần tử từ một TreeMap theo thứ tự đã sắp xếp hoặc theo các phần của map dựa trên giá trị của khóa.
Lớp LinkedHashMap
Lớp LinkedHashMap thực hiện cùng lúc cả khái niệm của bảng băm (hash table) và danh sách liên kết (linked list) trong giao diện Map. Một LinkedHashMap duy trì các giá trị theo thứ tự chúng được thêm vào, vì vậy các cặp khóa/giá trị sẽ được trả về theo cùng thứ tự chúng được thêm vào trong map này.
Các hàm tạo của lớp này bao gồm:
- LinkedHashMap(): Hàm tạo này tạo ra một LinkedHashMap trống với dung lượng mặc định và hệ số tải mặc định là 16 và 0.75, tương ứng.
- LinkedHashMap(int initialCapacity): Hàm tạo này tạo ra một LinkedHashMap trống với dung lượng ban đầu do người dùng xác định và hệ số tải mặc định là 0.75.
- LinkedHashMap(int initialCapacity, float loadFactor): Hàm tạo này tạo ra một LinkedHashMap trống với dung lượng ban đầu và hệ số tải do người dùng xác định.
- LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder): Hàm tạo này tạo ra một LinkedHashMap trống với dung lượng ban đầu, hệ số tải, và chế độ sắp xếp dựa trên lựa chọn của người dùng. Biến accessOrder xác định chế độ sắp xếp, giá trị boolean true chỉ định rằng chế độ sắp xếp dựa trên thứ tự truy cập (access-order) và false chỉ định rằng chế độ sắp xếp dựa trên thứ tự thêm vào (insertion-order).
- LinkedHashMap(Map<? extends K,? extends V> m): Hàm tạo này tạo ra một LinkedHashMap với các ánh xạ giống như ánh xạ của map đã xác định, và chế độ sắp xếp dựa trên thứ tự thêm vào (insertion-order).
Lớp LinkedHashMap cho phép bạn duy trì thứ tự của các cặp khóa/giá trị dựa trên cách chúng được thêm vào map.
Các phương thức lớp LinkedHashMap
Các phương thức quan trọng trong lớp LinkedHashMap bao gồm:
- clear(): Phương thức này xóa tất cả các ánh xạ khỏi map.
- containsValue(Object value): Phương thức này trả về true nếu map hiện hữu ánh xạ từ một hoặc nhiều khóa tới giá trị được chỉ định.
- get(Object key): Phương thức này trả về giá trị mà khóa được chỉ định được ánh xạ tới trong map.
- removeEldestEntry(Map.Entry<K,V> eldest): Phương thức này trả về true nếu map nên xóa khóa cũ nhất của nó. Phương thức này thường được gọi khi một cặp khóa/giá trị mới được thêm vào và map đã đạt đến giới hạn kích thước được xác định trước (có thể sử dụng để thực hiện chính sách LRU – Least Recently Used).
Các phương thức này cho phép bạn quản lý và tương tác với các ánh xạ trong một LinkedHashMap.
Lớp Stack, Queue và Arrays
Các lớp Stack, Queue và Arrays là một phần của Java Collections Framework và hỗ trợ các cấu trúc dữ liệu cơ bản để quản lý dữ liệu. Dưới đây là mô tả ngắn gọn về mỗi lớp:
- Stack: Lớp Stack trong Java thể hiện một ngăn xếp dựa trên nguyên tắc “Last-In-First-Out” (LIFO), nghĩa là phần tử cuối cùng được đưa vào ngăn xếp sẽ được lấy ra đầu tiên. Nó mở rộng lớp Vector để cung cấp các phương thức cơ bản của một ngăn xếp. Các phương thức quan trọng bao gồm: empty(), peek(), pop(), push(), và search().
- Queue: Lớp Queue là một giao diện đại diện cho cấu trúc dữ liệu hàng đợi. Java cung cấp một loạt lớp cài đặt giao diện Queue, chẳng hạn như LinkedList, PriorityQueue và nhiều lớp khác. Hàng đợi tuân theo nguyên tắc “First-In-First-Out” (FIFO), nghĩa là phần tử được thêm vào trước cùng sẽ được lấy ra trước cùng. Các phương thức thường gặp bao gồm add(), offer(), remove(), poll(), và element().
- Arrays: Lớp Arrays trong Java chứa một số phương thức tương tác với mảng. Điều này bao gồm phương thức để sao chép, so sánh, tìm kiếm và sắp xếp các mảng. Các phương thức này cho phép bạn thực hiện các hoạt động phổ biến với mảng, chẳng hạn như sao chép mảng, kiểm tra xem một mảng có chứa một giá trị cụ thể hay không, hoặc sắp xếp các phần tử trong mảng.
Mỗi lớp này đều cung cấp cơ chế tiện lợi để quản lý và thao tác dữ liệu theo cách cụ thể. Chọn lớp phù hợp với nhu cầu của bạn, ví dụ, sử dụng Stack khi bạn cần một cấu trúc dữ liệu ngăn xếp LIFO hoặc Queue khi bạn cần cấu trúc FIFO.
Giao diện Queue
Giao diện Queue đại diện cho một tập hợp các phần tử cần được xử lý. Trong Queue, các phần tử thường được sắp xếp theo nguyên tắc “Vào trước ra trước” (FIFO), nghĩa là phần tử nào được thêm vào trước sẽ được xử lý trước. Priority queue sắp xếp các phần tử dựa trên giá trị của chúng. Mỗi cài đặt của Queue có thể định nghĩa các thuộc tính về cách sắp xếp riêng.
Queue có thể được sắp xếp theo các nguyên tắc khác nhau. Trong Queue FIFO, phần tử mới được thêm vào cuối hàng đợi. Trong LIFO queue hoặc stack, các phần tử được xử lý theo nguyên tắc LIFO. Tuy nhiên, trong bất kỳ hình thức sắp xếp nào, việc gọi phương thức poll() sẽ loại bỏ phần tử đầu tiên.
Queue hỗ trợ các phương thức tiêu chuẩn của tập hợp và cung cấp các phương thức bổ sung để thêm, loại bỏ và xem xét các phần tử trong hàng đợi.
Queue hữu ích trong việc theo dõi các yêu cầu tin nhắn không đồng bộ trong khi stack giúp duyệt cây thư mục.
Ví dụ:
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
// Enqueue (add) elements to the queue
queue.offer("Apple");
queue.offer("Banana");
queue.offer("Cherry");
queue.offer("Date");
// Display the queue
System.out.println("Queue: " + queue);
// Dequeue (remove) elements from the queue
String first = queue.poll(); // Removes and returns the first element (Apple)
String second = queue.poll(); // Removes and returns the second element (Banana)
// Display the modified queue
System.out.println("Queue after dequeue: " + queue);
// Peek at the front of the queue without removing it
String front = queue.peek();
System.out.println("Front of the queue: " + front);
}
}
Giao diện Deque
Deque (Double Ended Queue) là một tập hợp tuyến tính hỗ trợ việc chèn và loại bỏ phần tử từ cả hai đầu.
Thường thì các cài đặt của Deque không có hạn chế về số lượng phần tử. Tuy nhiên, chúng hỗ trợ Deque có hạn chế về sức chứa.
Các phương thức được kế thừa từ Giao diện Queue. Một Deque khi được sử dụng như một hàng đợi sẽ hoạt động theo nguyên tắc FIFO. Các phần tử được thêm vào cuối Deque và loại bỏ từ đầu.
Khi Deque được sử dụng như một ngăn xếp LIFO, nên ưu tiên sử dụng với lớp Stack cổ điển. Khi sử dụng Deque như một ngăn xếp, các phần tử sẽ được đẩy và lấy ra từ đầu của Deque. Các phương thức của Stack tương đương với các phương thức của Deque.
Giao diện Deque và các cài đặt của nó khi sử dụng với lớp Stack cung cấp một tập hợp liên tục các hoạt động của ngăn xếp LIFO. Mã nguồn mẫu 13 mô tả điều này.
Ví dụ:
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeExample {
public static void main(String[] args) {
Deque<String> deque = new ArrayDeque<>();
// Add elements to the front and back of the deque
deque.addFirst("Apple");
deque.addLast("Banana");
deque.addFirst("Cherry");
deque.addLast("Date");
// Display the deque
System.out.println("Deque: " + deque);
// Remove elements from the front and back of the deque
String front = deque.pollFirst(); // Removes and returns the first element (Cherry)
String back = deque.pollLast(); // Removes and returns the last element (Date)
// Display the modified deque
System.out.println("Deque after removal: " + deque);
// Peek at the front and back of the deque without removing them
String frontElement = deque.peekFirst();
String backElement = deque.peekLast();
System.out.println("Front of the deque: " + frontElement);
System.out.println("Back of the deque: " + backElement);
}
}
Các phương thức lớp Queue
Các phương thức quan trọng được hỗ trợ bởi Queue và các cài đặt của nó bao gồm:
Phương thức poll()
Phương thức này trả về giá trị của phần tử đầu hàng đợi và loại bỏ phần tử đó khỏi hàng đợi. Phương thức này trả về giá trị null nếu hàng đợi trống.
Cú pháp:
E poll()
Phương thức peek()
Phương thức này trả về giá trị của phần tử đầu hàng đợi nhưng không loại bỏ phần tử đó khỏi hàng đợi. Phương thức này trả về giá trị null nếu hàng đợi trống.
Cú pháp:
E peek()
Phương thức remove()
Phương thức này trả về giá trị của phần tử đầu hàng đợi và loại bỏ phần tử đó khỏi hàng đợi. Nếu hàng đợi trống, phương thức này sẽ ném ra một ngoại lệ.
Cú pháp:
E remove()
Phương thức offer(E obj)
Phương thức này chèn phần tử được chỉ định vào hàng đợi và trả về true nếu có thể thêm phần tử, ngược lại trả về false.
Cú pháp:
public boolean offer(E obj)
Phương thức element()
Phương thức này trả về giá trị của phần tử đầu hàng đợi nhưng không loại bỏ phần tử đó khỏi hàng đợi. Nếu hàng đợi trống, phương thức này sẽ ném ra một ngoại lệ.
Cú pháp:
E element()
Mỗi trong số các phương thức mô tả trên có thể ném ra một ngoại lệ nếu thao tác thất bại hoặc trả về giá trị null hoặc false.
Lớp PriorityQueue
Hàng đợi ưu tiên (Priority queues) tương tự như hàng đợi (queues), nhưng các phần tử không được sắp xếp theo cấu trúc FIFO (First-In-First-Out). Chúng được sắp xếp theo cách được xác định bởi người dùng. Các phần tử được sắp xếp dựa trên thứ tự tự nhiên hoặc dựa trên một bộ so sánh (comparator). Hàng đợi ưu tiên không cho phép thêm các đối tượng không thể so sánh (non-comparable) và không cho phép phần tử null. Hàng đợi ưu tiên không bị giới hạn về kích thước và cho phép hàng đợi mở rộng theo nhu cầu.
Khi các phần tử được thêm vào hàng đợi ưu tiên, khả năng lưu trữ của nó sẽ tự động mở rộng.
Các constructor của lớp này bao gồm:
PriorityQueue()
Phương thức này tạo một PriorityQueue và sắp xếp các phần tử dựa trên thứ tự tự nhiên của chúng. Kích thước mặc định là 11.
PriorityQueue(Collection<? extends E> c)
Constructor này tạo một PriorityQueue chứa các phần tử từ bộ sưu tập được chỉ định, c. Khả năng ban đầu của hàng đợi là 110% kích thước của bộ sưu tập được chỉ định.
PriorityQueue(int initialCapacity)
Constructor này tạo một PriorityQueue với khả năng ban đầu được chỉ định và sắp xếp các phần tử dựa trên thứ tự tự nhiên của chúng.
PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
Constructor này tạo một PriorityQueue với khả năng ban đầu được chỉ định và sắp xếp các phần tử dựa trên bộ so sánh được chỉ định.
PriorityQueue(PriorityQueue<? extends E> c)
Constructor này tạo một PriorityQueue chứa các phần tử từ bộ sưu tập được chỉ định. Khả năng ban đầu của hàng đợi là 110% kích thước của bộ sưu tập được chỉ định.
PriorityQueue(SortedSet<? extends E> c)
Constructor này tạo một PriorityQueue chứa các phần tử từ bộ sưu tập được chỉ định. Khả năng ban đầu của hàng đợi là 110% kích thước của bộ sưu tập được chỉ định.
Ví dụ:
import java.util.PriorityQueue;
public class PriorityQueueExample {
public static void main(String[] args) {
// Create a PriorityQueue of integers
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
// Add elements to the PriorityQueue
priorityQueue.offer(5);
priorityQueue.offer(3);
priorityQueue.offer(8);
priorityQueue.offer(1);
// Display the PriorityQueue
System.out.println("PriorityQueue: " + priorityQueue);
// Peek at the element with the highest priority (minimum value)
int highestPriority = priorityQueue.peek();
System.out.println("Highest Priority Element: " + highestPriority);
// Dequeue (remove) elements in priority order
while (!priorityQueue.isEmpty()) {
int element = priorityQueue.poll();
System.out.println("Dequeued Element: " + element);
}
}
}
Các phương thức của lớp PriorityQueue
Lớp PriorityQueue
kế thừa các phương thức từ lớp Queue
.
Các phương thức khác được hỗ trợ bởi lớp PriorityQueue
bao gồm:
Phương thức add(E e)
Phương thức này thêm phần tử cụ thể vào hàng đợi ưu tiên và trả về một giá trị boolean.
Phương thức clear()
Phương thức này xóa tất cả các phần tử khỏi hàng đợi ưu tiên.
Phương thức comparator()
Phương thức này trả về bộ so sánh được sử dụng để sắp xếp bộ sưu tập này. Phương thức sẽ trả về null nếu bộ sưu tập này được sắp xếp theo thứ tự tự nhiên của các phần tử.
Phương thức contains(Object o)
Phương thức này trả về giá trị boolean true nếu hàng đợi chứa phần tử cụ thể.
Phương thức iterator()
Phương thức này trả về một trình lặp (iterator) qua các phần tử trong hàng đợi.
Phương thức toArray()
Phương thức này trả về một mảng các đối tượng chứa tất cả các phần tử trong hàng đợi.
Lớp Arrays
Lớp Arrays
cung cấp nhiều phương thức để làm việc với các mảng như tìm kiếm, sắp xếp và so sánh mảng. Lớp này có một phương thức tạo (static factory method) cho phép xem mảng như là danh sách (list). Các phương thức của lớp này sẽ ném ra một ngoại lệ NullPointerException
nếu tham chiếu đến mảng là null.
Dưới đây là một số phương thức quan trọng của lớp này:
equals(<type> arrObj1, <type> arrObj2)
Phương thức này so sánh hai mảng cụ thể cùng kiểu dữ liệu để xem xét tính bằng nhau. Phương thức trả về true
nếu mỗi mảng chứa cùng số lượng phần tử và mỗi phần tử trong mảng thứ nhất bằng với giá trị tương ứng trong mảng thứ hai. Có một phương thức loại này cho mỗi kiểu dữ liệu nguyên thủy và cho đối tượng.
fill(<type>[] array, <type> value)
Phương thức này khởi tạo một mảng bằng cách gán giá trị cụ thể cho tất cả các phần tử trong mảng. Có một phương thức loại này cho mỗi kiểu dữ liệu nguyên thủy và cho đối tượng.
fill(<type>[] array, int fromIndex, int toIndex, <type> value)
Phương thức này khởi tạo các phần tử trong mảng bằng cách gán giá trị cụ thể giữa các chỉ số đã cho.
sort(<type>[] array)
Phương thức này sắp xếp mảng theo thứ tự tăng dần. Có một phương thức loại này cho mỗi kiểu dữ liệu nguyên thủy, trừ kiểu boolean.
sort(<type>[] array, int startIndex, int endIndex)
Phương thức này sắp xếp các phần tử trong mảng giữa các chỉ số đã cho. Có một phương thức loại này cho mỗi kiểu dữ liệu nguyên thủy.
toString(<type>[] array)
Phương thức này trả về một chuỗi biểu diễn của nội dung của mảng. Có một phương thức loại này cho mỗi kiểu dữ liệu nguyên thủy.
Sắp xếp bộ sưu tập (Sorting Collection)
Collections API cung cấp hai giao diện chính để sắp xếp dữ liệu trong các tập hợp: Comparable và Comparator.
- Comparable:
- Giao diện
Comparable
đặt ra một sắp xếp toàn phần cho các đối tượng của mỗi lớp thực hiện nó. - Các đối tượng của các lớp triển khai
Comparable
có thể được sắp xếp tự động bằng cách sử dụng các phương thức như Collections.sort hoặcArrays.sort
. - Sắp xếp tự nhiên cho một lớp, được xác định bằng cách triển khai giao diện
Comparable
, thường được gọi là “thứ tự tự nhiên” của lớp. Điều kiện cho sắp xếp tự nhiên: - e1.compareTo(e2) == 0 nên có giá trị boolean giống với
e1.equals(e2)
đối với mọie1
vàe2
thuộc lớp C. - Null không phải là một phiên bản của bất kỳ lớp nào, vì vậy
e.compareTo(null)
nên némNullPointerException
ngay cả khie.equals(null)
trả vềfalse
. Đề xuất nên thực hiện thứ tự tự nhiên để đảm bảo tính nhất quán với phương thứcequals
.
- Comparator:
- Giao diện Comparator cung cấp nhiều tùy chọn sắp xếp và đặt ra một sắp xếp toàn phần đối với một số tập hợp các đối tượng.
- Các
Comparator
hữu ích khi bạn cần kiểm soát thứ tự sắp xếp của các phần tử trong một tập hợp, ví dụ, khi sử dụng Collections.sort. - Chúng cũng có thể được sử dụng để kiểm soát thứ tự của một số cấu trúc dữ liệu như bản đồ đã sắp xếp.
- Comparator đặc biệt hữu ích khi xử lý các tập hợp các đối tượng không có thứ tự tự nhiên. Điều kiện cho một
Comparator
: - Nếu c.compare(e1, e2) == 0 có giá trị boolean giống với
e1.equals(e2)
đối với mọie1
vàe2
trong một tập hợp các phần tửs
, thì sắp xếp bởi một Comparatorc
trên tậps
là nhất quán vớiequals
. Nếu sắp xếp bằng một Comparator không nhất quán vớiequals
, tập hợp hoặc bản đồ đã sắp xếp có thể hoạt động một cách bất thường. Ví dụ, khi thêm hai phần tửa
vàb
vào mộtTreeSet
rỗng với một Comparatorc
sao cho (a.equals(b) && c.compare(a, b) != 0), thao tác thêm thứ hai sẽ trả vềtrue
vìa
vàb
không tương đương choTreeSet
.
Ghi chú: Để tuần tự hóa một cấu trúc dữ liệu (ví dụ: TreeSet
, TreeMap
) sử dụng Comparator
, các Comparator
có thể triển khai giao diện java.io.Serializable
.
Các cải tiến trong các lớp Collections
Các cải tiến trong các lớp Collections
Là trong Java SE 6, các lớp Collections mới đã được giới thiệu lần đầu trong APIs Collections và chúng vẫn còn phù hợp trong phiên bản hiện tại của Java. Dưới đây là một số lớp quan trọng:
ArrayDeque
Lớp ArrayDeque triển khai giao diện Deque. Lớp này nhanh hơn so với Stack và LinkedList khi sử dụng như một hàng đợi. Nó không giới hạn về sức chứa và không cho phép giá trị null. Nó không an toàn đối với luồng. Nói cách khác, nó không cho phép truy cập đồng thời bởi nhiều luồng.
Lớp ArrayDeque cung cấp các phương thức addFirst(E e), addLast(E e), getFirst(), getLast(), removeFirst(), và removeLast() để thêm, truy xuất và xóa các phần tử từ vị trí đầu và cuối của hàng đợi. Các phần tử có thể được truy cập và duyệt theo cả hướng thuận và nghịch lược. Lớp ArrayDeque cũng cung cấp phương thức contains(), trả về true nếu deque chứa phần tử cụ thể.
Ví dụ:
import java.util.ArrayDeque;
import java.util.Deque;
public class ArrayDequeExample {
public static void main(String[] args) {
// Create an ArrayDeque of integers
Deque<Integer> deque = new ArrayDeque<>();
// Add elements to the front and back of the deque
deque.addFirst(1);
deque.addLast(2);
deque.addFirst(3);
deque.addLast(4);
// Display the deque
System.out.println("ArrayDeque: " + deque);
// Peek at the front and back of the deque without removing elements
int frontElement = deque.peekFirst();
int backElement = deque.peekLast();
System.out.println("Front of the deque: " + frontElement);
System.out.println("Back of the deque: " + backElement);
// Remove elements from the front and back of the deque
int front = deque.pollFirst();
int back = deque.pollLast();
// Display the modified deque
System.out.println("ArrayDeque after removal: " + deque);
// Iterate through the deque
System.out.println("Iterating through the ArrayDeque:");
for (int element : deque) {
System.out.println(element);
}
}
}
ConcurrentSkipListSet
ConcurrentSkipListSet
Lớp ConcurrentSkipListSet triển khai giao diện NavigableSet. Các phần tử được sắp xếp dựa trên thứ tự tự nhiên hoặc bằng một Comparator. Comparator là một giao diện sử dụng phương thức compare() để sắp xếp các đối tượng không có thứ tự tự nhiên. Trong quá trình tạo, Comparator được cung cấp. Lớp ConcurrentSkipListSet cung cấp các phương thức để trả về trình duyệt theo thứ tự tăng dần hoặc giảm dần. Nó cũng cung cấp các phương thức để trả về các phần tử gần nhất trong một tập hợp.
Cú pháp:
ConcurrentSkipListSet()
Constructor tạo một thể hiện với các phần tử được sắp xếp theo thứ tự tự nhiên.
Bảng dưới liệt kê và mô tả các phương thức khác nhau có sẵn trong lớp ConcurrentSkipListSet.
Lưu ý rằng đối số “e” là phần tử mà bạn muốn tìm trong danh sách.
- ceiling(E e): Trả về phần tử nhỏ nhất lớn hơn hoặc bằng e hoặc null nếu không có phần tử nào như vậy.
- floor(E e): Trả về phần tử lớn nhất nhỏ hơn hoặc bằng e hoặc null nếu không có phần tử nào như vậy.
- higher(E e): Trả về phần tử nhỏ nhất lớn hơn e hoặc null nếu không có phần tử nào như vậy.
- lower(E e): Trả về phần tử lớn nhất nhỏ hơn e hoặc null nếu không có phần tử nào như vậy.
Ví dụ:
import java.util.concurrent.ConcurrentSkipListSet;
public class ConcurrentSkipListSetExample {
public static void main(String[] args) {
// Create a ConcurrentSkipListSet of integers
ConcurrentSkipListSet<Integer> skipListSet = new ConcurrentSkipListSet<>();
// Add elements to the set
skipListSet.add(5);
skipListSet.add(2);
skipListSet.add(8);
skipListSet.add(1);
skipListSet.add(3);
// Display the sorted set
System.out.println("ConcurrentSkipListSet: " + skipListSet);
// Check if an element is in the set
boolean containsElement = skipListSet.contains(3);
System.out.println("Contains 3: " + containsElement);
// Remove an element from the set
boolean removed = skipListSet.remove(2);
System.out.println("Removed 2: " + removed);
// Display the modified set
System.out.println("ConcurrentSkipListSet after removal: " + skipListSet);
// Iterate through the set
System.out.println("Iterating through the ConcurrentSkipListSet:");
for (int element : skipListSet) {
System.out.println(element);
}
}
}
ConcurrentSkipListMap
Lớp ConcurrentSkipListMap triển khai giao diện ConcurrentNavigableMap. Nó thuộc gói java.util.concurrent. Giống như lớp ConcurrentHashMap, lớp ConcurrentSkipListMap cho phép sửa đổi mà không khóa toàn bộ Map.
Cú pháp:
- ConcurrentSkipListMap(): Constructor tạo một bản đồ mới trống, trong đó bản đồ được sắp xếp theo thứ tự tự nhiên của các khóa.
Bảng dưới liệt kê và mô tả các phương thức khác nhau có sẵn trong lớp ConcurrentSkipListMap.
- descendingMap(): Trả về một bản đồ con chứa các mục nhập được sắp xếp theo thứ tự giảm dần.
- firstEntry(): Trả về mục nhập có khóa thấp nhất trong bản đồ.
- ceilingEntry(K key): Trả về mục nhập gần nhất có giá trị lớn hơn hoặc bằng giá trị khóa đã chỉ định hoặc null nếu không có khóa nào như vậy.
- lastEntry(): Trả về mục nhập có khóa cao nhất trong bản đồ.
- put(K key, V value): Chèn giá trị được liên kết trước đó với khóa đã chỉ định hoặc null nếu không có giá trị nào tồn tại. Ở đây, key là khóa mà giá trị được chỉ định được liên kết với, và value là giá trị mà khóa được chỉ định được liên kết với.
Ví dụ:
import java.util.concurrent.ConcurrentSkipListMap;
public class ConcurrentSkipListMapExample {
public static void main(String[] args) {
// Create a ConcurrentSkipListMap of strings
ConcurrentSkipListMap<String, Integer> scoreMap = new ConcurrentSkipListMap<>();
// Add entries to the map
scoreMap.put("Alice", 95);
scoreMap.put("Bob", 88);
scoreMap.put("Charlie", 92);
scoreMap.put("David", 78);
scoreMap.put("Eve", 85);
// Display the map
System.out.println("Score Map: " + scoreMap);
// Get the first and last entries
System.out.println("First Entry: " + scoreMap.firstEntry());
System.out.println("Last Entry: " + scoreMap.lastEntry());
// Find the ceiling entry for a key
System.out.println("Ceiling Entry for 'Cathy': " + scoreMap.ceilingEntry("Cathy"));
System.out.println("Ceiling Entry for 'Eve': " + scoreMap.ceilingEntry("Eve"));
// Remove an entry
scoreMap.remove("Bob");
// Display the modified map
System.out.println("Score Map after removing 'Bob': " + scoreMap);
}
}
LinkedBlockingDeque
Lớp LinkedBlockingDeque triển khai giao diện BlockingDeque. Lớp này thuộc gói java.util.concurrent. Trong lớp này, bạn có thể chỉ định dung lượng để lưu trữ các phần tử. Nếu bạn không chỉ định dung lượng, thì dung lượng tối đa sẽ có giá trị là Integer.MAX_VALUE. Lớp này chứa các nút được liên kết mà được tạo ra động sau mỗi lần chèn.
Cú pháp cho các hàm tạo như sau:
- LinkedBlockingDeque(): Constructor tạo một thể hiện với dung lượng mặc định được chỉ định trong Integer.MAX_VALUE.
- LinkedBlockingDeque(int capacity): Constructor tạo một thể hiện với dung lượng được chỉ định.
Bảng dưới mô tả các phương thức khác nhau có sẵn trong lớp LinkedBlockingDeque.
Lưu ý rằng đối số e là phần tử sẽ được thêm vào deque.
- addFirst(E e): Chèn phần tử được chỉ định, e, ở đầu deque. Nó không vi phạm ràng buộc về dung lượng.
- pollFirst(): Loại bỏ và trả về phần tử đầu tiên của deque nếu có sẵn, nếu không thì trả về null.
- peekFirst(): Trả về nhưng không loại bỏ phần tử đầu tiên của deque nếu có sẵn, nếu không thì trả về null.
Ví dụ:
import java.util.concurrent.LinkedBlockingDeque;
public class LinkedBlockingDequeExample {
public static void main(String[] args) {
// Create a LinkedBlockingDeque of integers with a capacity of 3
LinkedBlockingDeque<Integer> deque = new LinkedBlockingDeque<>(3);
// Add elements to the deque
try {
deque.put(1);
deque.put(2);
deque.put(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Display the deque
System.out.println("LinkedBlockingDeque: " + deque);
// Offer an element at the front and back of the deque
deque.offerFirst(0);
deque.offerLast(4);
// Display the modified deque
System.out.println("LinkedBlockingDeque after offering elements: " + deque);
// Poll elements from the front and back of the deque
int front = deque.pollFirst();
int back = deque.pollLast();
// Display the modified deque after polling
System.out.println("LinkedBlockingDeque after polling elements: " + deque);
System.out.println("Front Element: " + front);
System.out.println("Back Element: " + back);
}
}
Ví dụ 2:
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
class ProducerDeque implements Runnable {
private String name;
private BlockingDeque<Integer> blockDeque;
public ProducerDeque(String name, BlockingDeque<Integer> blockDeque) {
this.name = name;
this.blockDeque = blockDeque;
}
public void run() {
for (int i = 1; i <= 10; i++) {
try {
blockDeque.addFirst(i);
System.out.println(name + " put " + i);
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IllegalStateException ex) {
System.out.println("Deque filled up to the maximum capacity");
System.exit(0);
}
}
}
}
class ConsumerDeque implements Runnable {
private String name;
private BlockingDeque<Integer> blockDeque;
public ConsumerDeque(String name, BlockingDeque<Integer> blockDeque) {
this.name = name;
this.blockDeque = blockDeque;
}
public void run() {
for (int i = 1; i <= 10; i++) {
try {
if (!blockDeque.isEmpty()) {
Integer value = blockDeque.pollFirst();
System.out.println(name + " takes " + value);
}
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class LinkedBlockingDequeClass {
public static void main(String[] args) {
BlockingDeque<Integer> blockDeque = new LinkedBlockingDeque<>(5);
Runnable producer = new ProducerDeque("Producer", blockDeque);
Runnable consumer = new ConsumerDeque("Consumer", blockDeque);
new Thread(producer).start();
new Thread(consumer).start();
}
}
AbstractMap.Simpleintry
AbstractMap.SimpleEntry là một lớp tĩnh được lồng trong lớp AbstractMap. Lớp này được sử dụng để triển khai một map tùy chỉnh. Một thể hiện của lớp này lưu trữ cặp khóa-giá trị của một mục trong một map. Giá trị của mục có thể thay đổi.
Phương thức getKey() trả về khóa của mục trong thể hiện. Phương thức getValue() trả về giá trị của mục. Phương thức setValue() cập nhật giá trị của mục.
Cú pháp:
- AbstractMap.SimpleEntry(K key, V value): Constructor tạo một thể hiện với cặp khóa-giá trị cụ thể được đặc trưng bởi key và value.
Ví dụ:
import java.util.AbstractMap;
import java.util.Map;
import java.util.Map.Entry;
public class SimpleEntryExample {
public static void main(String[] args) {
// Create a key-value pair using AbstractMap.SimpleEntry
Entry<String, Integer> entry = new AbstractMap.SimpleEntry<>("Alice", 25);
// Display the key and value
System.out.println("Key: " + entry.getKey());
System.out.println("Value: " + entry.getValue());
// You can also use it to create a Map
Map<String, Integer> map = Map.ofEntries(
new AbstractMap.SimpleEntry<>("Bob", 30),
new AbstractMap.SimpleEntry<>("Charlie", 28)
);
// Display the Map
System.out.println("Map: " + map);
}
}
AbstractMap.SimpleImmutableEntry
Lớp AbstractMap.SimpleImmutableEntry là một lớp tĩnh được lồng trong lớp AbstractMap. Như tên gọi, nó không cho phép sửa đổi giá trị trong một mục. Nếu có bất kỳ cố gắng thay đổi giá trị nào, nó sẽ dẫn đến việc ném ra một UnsupportedOperationException.
Ví dụ:
import java.util.AbstractMap;
import java.util.Map;
import java.util.Map.Entry;
public class SimpleImmutableEntryExample {
public static void main(String[] args) {
// Create an immutable key-value pair using AbstractMap.SimpleImmutableEntry
Entry<String, Integer> entry = new AbstractMap.SimpleImmutableEntry<>("Alice", 25);
// Display the key and value
System.out.println("Key: " + entry.getKey());
System.out.println("Value: " + entry.getValue());
// You can also use it to create a Map
Map<String, Integer> map = Map.ofEntries(
new AbstractMap.SimpleImmutableEntry<>("Bob", 30),
new AbstractMap.SimpleImmutableEntry<>("Charlie", 28)
);
// Display the Map
System.out.println("Map: " + map);
// Attempting to modify the entry will result in an error
// entry.setValue(35); // This will cause an UnsupportedOperationException
}
}
Bài tập
1. Iterator
- Bài tập 1: Viết một chương trình Java để tạo một danh sách
ArrayList
các số nguyên. Sử dụngIterator
để duyệt qua danh sách và in ra các số lẻ. - Bài tập 2: Sử dụng
Iterator
để xóa tất cả các phần tử có giá trị nhỏ hơn 10 trong một danh sáchLinkedList
chứa các số nguyên.
2. Unmodifiable Collection
- Bài tập 1: Tạo một
List
các chuỗi và sau đó tạo một phiên bản không thể chỉnh sửa của nó bằng cách sử dụngCollections.unmodifiableList()
. Hãy thử thay đổi danh sách và bắt lỗiUnsupportedOperationException
. - Bài tập 2: Tương tự, tạo một
Set
không thể thay đổi từ một tập hợpHashSet
. Kiểm tra xem việc thêm phần tử mới có gây ra lỗi không.
3. Vector
- Bài tập 1: Tạo một
Vector
để lưu trữ danh sách tên sinh viên. Thêm 5 sinh viên vào danh sách, sau đó in danh sách ra màn hình. - Bài tập 2: Dùng
Vector
để quản lý hàng đợi (queue) của một ngân hàng. Thực hiện các thao tác thêm khách hàng và xóa khách hàng khi đến lượt phục vụ.
4. LinkedList
- Bài tập 1: Viết chương trình quản lý danh sách các công việc theo thứ tự ưu tiên sử dụng
LinkedList
. Thêm công việc mới vào đầu và cuối danh sách, sau đó duyệt qua danh sách. - Bài tập 2: Sử dụng
LinkedList
để mô phỏng hàng đợi (queue) của khách hàng trong siêu thị và thực hiện các thao tác thêm và xóa khách hàng khỏi hàng đợi.
5. SortedSet
- Bài tập 1: Tạo một
SortedSet
để lưu trữ các số nguyên không trùng lặp. Thêm các số theo thứ tự ngẫu nhiên và in chúng ra theo thứ tự tự nhiên. - Bài tập 2: Tạo một
SortedSet
để lưu trữ danh sách các chuỗi. Kiểm tra xem danh sách này có tự động sắp xếp các chuỗi theo thứ tự từ điển hay không.
6. HashSet
- Bài tập 1: Viết chương trình sử dụng
HashSet
để lưu trữ các từ trong một đoạn văn và in ra danh sách từ không trùng lặp. - Bài tập 2: Tạo một
HashSet
chứa các số từ 1 đến 20. Xóa các số là bội số của 3 và in danh sách kết quả.
7. LinkedHashSet
- Bài tập 1: Tạo một
LinkedHashSet
để lưu trữ các số nguyên. Thêm 10 số vào danh sách và in ra danh sách theo thứ tự đã thêm. - Bài tập 2: Viết chương trình sử dụng
LinkedHashSet
để lưu trữ và in danh sách tên của sinh viên, đảm bảo rằng thứ tự in ra giống như thứ tự thêm vào.
8. TreeSet
- Bài tập 1: Tạo một
TreeSet
để lưu trữ danh sách các chuỗi và tự động sắp xếp chúng theo thứ tự từ điển. - Bài tập 2: Tạo một
TreeSet
để lưu trữ các số nguyên và in ra số nhỏ nhất và lớn nhất trong tập hợp.
9. TreeMap
- Bài tập 1: Tạo một
TreeMap
để lưu trữ thông tin về sinh viên và điểm số của họ. Sắp xếp danh sách sinh viên theo tên và in ra bảng điểm. - Bài tập 2: Tạo một
TreeMap
lưu trữ từ và tần suất xuất hiện của chúng trong một đoạn văn bản. In ra danh sách từ được sắp xếp theo thứ tự từ điển.
10. LinkedHashMap
- Bài tập 1: Sử dụng
LinkedHashMap
để lưu trữ danh sách sinh viên và tuổi của họ. Thêm 5 sinh viên vào danh sách và in ra theo thứ tự đã thêm. - Bài tập 2: Tạo một chương trình quản lý hàng đợi phục vụ khách hàng trong ngân hàng sử dụng
LinkedHashMap
.
11. Deque
- Bài tập 1: Tạo một
Deque
để mô phỏng hàng đợi hai đầu. Thêm các phần tử vào đầu và cuối danh sách và duyệt qua danh sách theo cả hai chiều. - Bài tập 2: Viết chương trình quản lý lịch trình công việc sử dụng
Deque
, nơi công việc ưu tiên có thể được thêm vào cả hai đầu của danh sách.
12. PriorityQueue
- Bài tập 1: Tạo một
PriorityQueue
để quản lý danh sách công việc với các mức độ ưu tiên khác nhau. Thêm các công việc và in ra theo thứ tự ưu tiên. - Bài tập 2: Sử dụng
PriorityQueue
để mô phỏng hệ thống hàng đợi ưu tiên trong bệnh viện, nơi bệnh nhân được phục vụ theo mức độ khẩn cấp.