Lớp java.time.MonthDay
Lớp MonthDay trong gói java.time của Java được sử dụng để biểu diễn một ngày trong tháng theo lịch ISO-8601, chẳng hạn như "--12-03" (ngày 3 tháng 12). Nó là một đối tượng ngày tháng không đổi (immutable) và lưu trữ thông tin về tháng và ngày. Bên cạnh đó, MonthDay cũng cung cấp các phương thức để truy cập các trường liên quan đến tháng và ngày, chẳng hạn như quý trong năm.
Ⅰ. Đặc điểm của lớp MonthDay
↳ Không lưu trữ hoặc biểu diễn năm, thời gian hoặc múi giờ.
↳ Thích hợp để lưu trữ các cặp tháng-ngày mà không cần quan tâm đến năm cụ thể. Ví dụ, ngày kỷ niệm cưới (ngày 3 tháng 12) có thể được lưu trữ bằng MonthDay.
↳ Do MonthDay không lưu trữ năm, nên ngày 29 tháng 2 (ngày nhuận) được coi là hợp lệ.
↳ Lớp này triển khai TemporalAccessor thay vì Temporal vì không thể xác định ngày 29 tháng 2 có hợp lệ trong một năm cụ thể hay không mà không có thông tin bên ngoài. Điều này dẫn đến việc MonthDay chỉ cung cấp các phương thức để truy vấn và thiết lập các trường MONTH_OF_YEAR (tháng) và DAY_OF_MONTH (ngày).
↳ Sử dụng lịch ISO-8601.
↳ Là lớp bất biến (immutable), các phép toán dựa trên sự so sánh bằng (==) hoặc sử dụng hash code không nên được áp dụng cho MonthDay. Bạn nên sử dụng phương thức equals để so sánh hai ngày trong tháng.
↳ An toàn cho nhiều luồng (thread-safe).
Tóm lại, MonthDay là một lớp hữu ích để làm việc với các cặp tháng-ngày theo lịch ISO-8601 mà không cần quan tâm đến năm hoặc thời gian cụ thể.
Ⅱ. Khai báo lớp MonthDay trong Java
Để sử dụng lớp MonthDay và các lớp khác trong gói java.time, bạn cần thêm câu lệnh import vào đầu file Java của mình.
Cú pháp câu lệnh import:
Cú pháp
import java.time.MonthDay;
Cú pháp khai báo lớp MonthDay:
Cú pháp
public final class MonthDay
extends Object
implements TemporalAccessor, TemporalAdjuster, Comparable<MonthDay>, Serializable
Dưới đây là giải thích chi tiết về cú pháp khai báo này:
↳ public: Lớp này có thể được truy cập từ bất kỳ đâu trong chương trình, không bị giới hạn phạm vi.
↳ final: Lớp này không thể bị kế thừa. Điều này có nghĩa là bạn không thể tạo một lớp con từ MonthDay.
↳ class MonthDay: Khai báo một lớp có tên là MonthDay.
↳ extends Object: Tất cả các lớp trong Java đều kế thừa từ lớp Object (lớp gốc của tất cả các lớp trong Java). Việc này cho phép lớp LocalTime kế thừa các phương thức cơ bản từ Object, chẳng hạn như toString(), equals(), và hashCode().
implements TemporalAccessor, TemporalAdjuster, Comparable<MonthDay>, Serializable
Lớp MonthDay thực hiện (implements) các giao diện implements TemporalAccessor, TemporalAdjuster, Comparable<MonthDay>, Serializable. Điều này có nghĩa là lớp MonthDay phải cung cấp các phương thức được khai báo trong những giao diện này.
↳ implements TemporalAccessor: Giao diện này cung cấp quyền truy cập vào các trường dữ liệu ngày giờ, chẳng hạn như ngày, tháng, năm, giờ, phút, giây, v.v. Các lớp triển khai giao diện này có thể được truy vấn để lấy các giá trị cụ thể của các trường thời gian.
↳ implements TemporalAdjuster: Là một giao diện cho phép điều chỉnh các giá trị thời gian cụ thể, như thay đổi ngày tháng, giờ phút. Ví dụ, nó có thể được sử dụng để tìm ngày thứ Hai tiếp theo hoặc ngày cuối cùng của tháng.
↳ implements Comparable<MonthDay>: Giao diện này cho phép các đối tượng MonthDay có thể so sánh với nhau. Phương thức compareTo được sử dụng để xác định thứ tự tự nhiên của các đối
↳ implements Serializable: Giao diện này cho phép đối tượng MonthDay có thể được tuần tự hóa, tức là có thể chuyển đổi đối tượng thành một chuỗi byte để lưu trữ hoặc truyền qua mạng.
Ⅲ. Các phương thức của lớp MonthDay
Lớp MonthDay cung cấp nhiều phương thức để thao tác với cặp tháng-ngày. Việc phân nhóm các phương thức theo chức năng sẽ giúp bạn hiểu rõ hơn về cách sử dụng lớp MonthDay. Dưới đây là cách phân nhóm các phương thức phổ biến của lớp MonthDay:
Tạo đối tượng MonthDay
↳ now(): Lấy tháng và ngày hiện tại của hệ thống.
↳ of(int month, int dayOfMonth): Tạo một đối tượng MonthDay từ tháng và ngày cho trước.
↳ now(Clock clock): Lấy tháng và ngày hiện tại từ một đồng hồ cụ thể.
Dưới đây là ví dụ về cách sử dụng ba phương thức of(int month, int dayOfMonth), now(), và now(Clock clock) của lớp MonthDay trong Java.
Ví dụ: Example.java
import java.time.Clock;
import java.time.MonthDay;
import java.time.ZoneId;
public class Example {
public static void main(String[] args) {
// Sử dụng phương thức of(int month, int dayOfMonth)
MonthDay specificMonthDay = MonthDay.of(7, 22); // 22nd July
System.out.println("Ngày tháng tự tạo: " + specificMonthDay);
// Sử dụng phương thức now()
MonthDay currentMonthDay = MonthDay.now();
System.out.println("Ngày tháng hiện tại: " + currentMonthDay);
// Sử dụng phương thức now(Clock clock)
Clock clock = Clock.system(ZoneId.of("UTC"));
MonthDay currentMonthDayWithClock = MonthDay.now(clock);
System.out.println("Ngày tháng hiện tại với đồng hồ: " + currentMonthDayWithClock);
}
}
Kết quả của chương trình là:
Ngày tháng hiện tại: --07-22
Ngày tháng hiện tại với đồng hồ: --07-22
Trong ví dụ này, chúng ta đã tạo và in ra ba đối tượng MonthDay bằng cách sử dụng ba phương thức khác nhau. Hy vọng ví dụ này giúp bạn hiểu cách sử dụng các phương thức này trong lớp MonthDay!
Truy xuất thông tin
↳ getMonth(): Lấy tháng dưới dạng một đối tượng Month (enum).
↳ ggetMonthValue(): Lấy giá trị số của tháng (1-12).
↳ getDayOfMonth(): Lấy ngày trong tháng.
↳ get(TemporalField field): Lấy giá trị của một trường ngày tháng cụ thể.
↳ range(TemporalField field): Lấy phạm vi giá trị hợp lệ của một trường ngày tháng cụ thể.
↳ isValidYear(int year): Kiểm tra xem một năm cụ thể có hợp lệ với tháng và ngày hiện tại hay không.
Dưới đây là một ví dụ về cách sử dụng sáu phương thức getMonth(), getMonthValue(), getDayOfMonth(), get(TemporalField field), range(TemporalField field), và isValidYear(int year) của lớp MonthDay trong cùng một lớp Java.
Ví dụ: Example.java
import java.time.Month;
import java.time.MonthDay;
import java.time.temporal.ChronoField;
import java.time.temporal.ValueRange;
public class Example {
public static void main(String[] args) {
// Tạo một đối tượng MonthDay
MonthDay monthDay = MonthDay.of(7, 22); // 22nd July
// Sử dụng phương thức getMonth()
Month month = monthDay.getMonth();
System.out.println("Tháng: " + month); // Tháng dưới dạng đối tượng Month (enum)
// Sử dụng phương thức getMonthValue()
int monthValue = monthDay.getMonthValue();
System.out.println("Giá trị tháng: " + monthValue); // Giá trị số của tháng (1-12)
// Sử dụng phương thức getDayOfMonth()
int dayOfMonth = monthDay.getDayOfMonth();
System.out.println("Ngày trong tháng: " + dayOfMonth); // Ngày trong tháng
// Sử dụng phương thức get(TemporalField field)
int dayOfMonthField = monthDay.get(ChronoField.DAY_OF_MONTH);
System.out.println("Ngày trong tháng (dùng get): " + dayOfMonthField); // Ngày trong tháng sử dụng get
// Sử dụng phương thức range(TemporalField field)
ValueRange range = monthDay.range(ChronoField.DAY_OF_MONTH);
System.out.println("Phạm vi ngày trong tháng: " + range); // Phạm vi giá trị hợp lệ của ngày trong tháng
// Sử dụng phương thức isValidYear(int year)
boolean isValid = monthDay.isValidYear(2024); // Kiểm tra xem năm 2024 có hợp lệ với tháng và ngày hiện tại
System.out.println("Năm 2024 có phải là năm hợp lệ cho Ngày tháng nhất định không? " + isValid);
}
}
Kết quả của chương trình là:
Giá trị tháng: 7
Ngày trong tháng: 22
Ngày trong tháng (dùng get): 22
Phạm vi ngày trong tháng: 1 - 31
Năm 2024 có phải là năm hợp lệ cho Ngày tháng nhất định không? true
Trong ví dụ này, chúng ta đã sử dụng sáu phương thức khác nhau của lớp MonthDay để truy xuất thông tin và in các giá trị ra màn hình. Hy vọng ví dụ này giúp bạn hiểu cách sử dụng các phương thức này trong lớp MonthDay!
Thay đổi giá trị
↳ with(Month month): Tạo một bản sao của MonthDay với tháng mới.
↳ withDayOfMonth(int dayOfMonth): Tạo một bản sao của MonthDay với ngày mới.
↳ atYear(int year): Tạo một LocalDate bằng cách kết hợp MonthDay hiện tại với một năm cụ thể.
Dưới đây là ví dụ về cách sử dụng ba phương thức with(Month month), withDayOfMonth(int dayOfMonth), và atYear(int year) của lớp MonthDay trong cùng một lớp Java.
Ví dụ: Example.java
import java.time.LocalDate;
import java.time.Month;
import java.time.MonthDay;
public class Example {
public static void main(String[] args) {
// Tạo một đối tượng MonthDay
MonthDay originalMonthDay = MonthDay.of(7, 22); // 22nd July
System.out.println("MonthDay gốc: " + originalMonthDay);
// Sử dụng phương thức with(Month month)
MonthDay newMonthDayWithMonth = originalMonthDay.with(Month.DECEMBER); // Thay đổi tháng thành December
System.out.println("MonthDay với Tháng mới: " + newMonthDayWithMonth);
// Sử dụng phương thức withDayOfMonth(int dayOfMonth)
MonthDay newMonthDayWithDay = originalMonthDay.withDayOfMonth(15); // Thay đổi ngày thành 15
System.out.println("MonthDay với ngày mới: " + newMonthDayWithDay);
// Sử dụng phương thức atYear(int year)
LocalDate localDate = originalMonthDay.atYear(2024); // Kết hợp với năm 2024
System.out.println("MonthDay với năm: " + localDate);
}
}
Kết quả của chương trình là:
MonthDay với Tháng mới: --12-22
MonthDay với ngày mới: --07-15
MonthDay với năm: 2024-07-22
Trong ví dụ này, chúng ta đã sử dụng ba phương thức khác nhau của lớp MonthDay để thay đổi giá trị và in các giá trị ra màn hình. Hy vọng ví dụ này giúp bạn hiểu cách sử dụng các phương thức này trong lớp MonthDay!
So sánh
↳ isAfter(MonthDay other): Kiểm tra xem MonthDay hiện tại có sau MonthDay khác hay không.
↳ equals(Object obj): Kiểm tra xem hai đối tượng MonthDay có bằng nhau hay không.
↳ hashCode(): Trả về giá trị băm của MonthDay.
Dưới đây là ví dụ về cách sử dụng ba phương thức isAfter(MonthDay other), equals(Object obj), và hashCode() của lớp MonthDay trong cùng một lớp Java.
Ví dụ: Example.java
import java.time.MonthDay;
public class Example {
public static void main(String[] args) {
// Tạo các đối tượng MonthDay
MonthDay monthDay1 = MonthDay.of(7, 22); // 22nd July
MonthDay monthDay2 = MonthDay.of(12, 25); // 25th December
MonthDay monthDay3 = MonthDay.of(7, 22); // 22nd July (giống monthDay1)
// Sử dụng phương thức isAfter(MonthDay other)
boolean isAfter = monthDay1.isAfter(monthDay2);
System.out.println(monthDay1 + " Sau " + monthDay2 + ": " + isAfter);
// Sử dụng phương thức equals(Object obj)
boolean isEqual = monthDay1.equals(monthDay3);
System.out.println(monthDay1 + " Bằng " + monthDay3 + ": " + isEqual);
// Sử dụng phương thức hashCode()
int hashCode1 = monthDay1.hashCode();
int hashCode2 = monthDay2.hashCode();
int hashCode3 = monthDay3.hashCode();
System.out.println("HashCode của " + monthDay1 + ": " + hashCode1);
System.out.println("HashCode của " + monthDay2 + ": " + hashCode2);
System.out.println("HashCode của " + monthDay3 + ": " + hashCode3);
}
}
Kết quả của chương trình là:
--07-22 Bằng --07-22: true
HashCode của --07-22: 470
HashCode của --12-25: 793
HashCode của --07-22: 470
Trong ví dụ này, chúng ta đã sử dụng ba phương thức khác nhau của lớp MonthDay để so sánh các đối tượng và in các giá trị ra màn hình. Hy vọng ví dụ này giúp bạn hiểu cách sử dụng các phương thức này trong lớp MonthDay!
Định dạng
↳ format(DateTimeFormatter formatter): Định dạng MonthDay thành một chuỗi theo một mẫu định dạng cho trước.
Dưới đây là ví dụ về cách sử dụng phương thức format(DateTimeFormatter formatter) của lớp MonthDay để định dạng đối tượng MonthDay thành một chuỗi theo một mẫu định dạng cho trước.
Ví dụ: Example.java
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
public class Example {
public static void main(String[] args) {
// Tạo một đối tượng MonthDay
MonthDay monthDay = MonthDay.of(7, 22); // 22nd July
// Định dạng MonthDay thành một chuỗi theo mẫu định dạng cho trước
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd");
String formattedMonthDay = monthDay.format(formatter);
// In chuỗi định dạng ra màn hình
System.out.println("MonthDay đã được định dạng: " + formattedMonthDay);
}
}
Kết quả của chương trình là:
Trong ví dụ này, chúng ta đã sử dụng phương thức format(DateTimeFormatter formatter) để định dạng đối tượng MonthDay thành một chuỗi theo mẫu định dạng cho trước và in kết quả ra màn hình. Hy vọng ví dụ này giúp bạn hiểu cách sử dụng phương thức format trong lớp MonthDay!
Các phương thức khác
↳ query(TemporalQuery query): Thực hiện một truy vấn tùy chỉnh trên MonthDay (được sử dụng cho các tính toán phức tạp hơn).
Dưới đây là ví dụ về cách sử dụng phương thức query(TemporalQuery query) của lớp MonthDay để thực hiện một truy vấn tùy chỉnh trên MonthDay.
Ví dụ: Example.java
import java.time.MonthDay;
import java.time.temporal.TemporalQueries;
import java.time.temporal.TemporalQuery;
import java.time.temporal.TemporalUnit;
public class Example {
public static void main(String[] args) {
// Tạo một đối tượng MonthDay
MonthDay monthDay = MonthDay.of(7, 22); // 22nd July
// Sử dụng phương thức query(TemporalQuery query) với TemporalQueries.precision()
TemporalQuery<TemporalUnit> query = TemporalQueries.precision();
TemporalUnit result = monthDay.query(query);
// In kết quả truy vấn ra màn hình
System.out.println("Độ chính xác của MonthDay: " + result);
}
}
Kết quả của chương trình là:
Lưu ý: Trong ví dụ này, kết quả của truy vấn TemporalQueries.precision() trên MonthDay sẽ trả về null vì MonthDay không có độ chính xác được xác định trong phạm vi của truy vấn này. Tuy nhiên, ví dụ này minh họa cách sử dụng phương thức query(TemporalQuery query) với một truy vấn tùy chỉnh.
Các ngoại lệ thường gặp khi sử dụng lớp MonthDay trong Java
Dưới đây là các ngoại lệ thường gặp và nguyên nhân của chúng:
Ngoại lệ DateTimeException
↳ Nguyên nhân: Xảy ra khi tạo một đối tượng MonthDay với tháng hoặc ngày không hợp lệ.
↳ Ví dụ: Khi cố gắng tạo MonthDay với tháng là 13 hoặc ngày là 32.
Ngoại lệ NullPointerException
↳ Nguyên nhân: Xảy ra khi truyền một giá trị null vào các phương thức của MonthDay mà không kiểm tra trước.
↳ Ví dụ: Khi gọi phương thức MonthDay.of(int month, int dayOfMonth) với month hoặc dayOfMonth là null.
Lưu ý:
Khi làm việc với MonthDay, việc kiểm tra dữ liệu đầu vào và các thao tác ngày tháng là rất quan trọng để tránh các ngoại lệ. Sử dụng các khối try-catch để xử lý ngoại lệ và cung cấp thông báo lỗi hoặc xử lý các tình huống bất thường để làm cho ứng dụng của bạn ổn định và dễ duy trì hơn.