Java 8: Cách thiết kế một lớp công cụ chuyển đổi giữa Instant và String? - Pk16vn Bet

| Feb 15, 2025 min read

Ngày 15 tháng 11 năm 2023 | Máy tính

Bài viết này sẽ giới thiệu cách thực hiện các lớp công cụ chuyển đổi truyền thống giữa DateString trước khi có Java 8; sau đó khám phá cách triển khai việc chuyển đổi giữa InstantString trong Java 8, cũng như cách xây dựng lớp công cụ mới.

1. Thiết kế lớp công cụ chuyển đổi ngày tháng truyền thống

Trước Java 8, chúng ta thường sử dụng Date để biểu diễn ngày và giờ. Khi thiết kế lớp công cụ chuyển đổi giữa DateString, chỉ cần sử dụng SimpleDateFormat, bạn có thể dễ dàng thực hiện.

Mã ví dụ như sau:

import java.text.ParseException;
import [cwin 667](/post/istio-traffic-managemen/)  java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtil {
    public static Date str2Date(String dateStr, String pattern) {
        try {
            return new SimpleDateFormat(pattern).parse(dateStr);
        } catch (ParseException e) {
            throw new RuntimeException("Chuyển đổi ngày thất bại");
        }
    }

    public static String date2Str(Date date, String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    public static void main(String[] args) {
        // Chuyển chuỗi thành ngày
        Date date = DateUtil.str2Date("2023-11-15", "yyyy-MM-dd");

        // Chuyển ngày thành chuỗi
        String str = DateUtil.date2Str(date, "yyyy/MM");
        System.out.println(str);
    }
}

Như có thể thấy, phương thức str2Datedate2Str của lớp DateUtil trên có thể lần lượt thực hiện việc chuyển đổi giữa StringDate, cũng như giữa DateString.

2. Java 8: Thiết kế lớp công cụ chuyển đổi giữa Instant và String

Java 8 đã giới thiệu một lớp mới gọi là Instant, đại diện cho một điểm trên dòng thời gian (thời khắc). Làm thế nào để thiết kế một lớp công cụ chuyển đổi giữa InstantString?

Đầu tiên, chúng ta sẽ xem xét một ví dụ sai lầm, sau đó tìm hiểu cách sửa lỗi để tạo iwin68.club phiên bản mới ra ví dụ chính xác.

Trong Java 8, chúng ta cần sử dụng DateTimeFormatter để thực hiện việc chuyển đổi giữa InstantString.

Dưới đây là một ví dụ không hoàn chỉnh dẫn đến lỗi.

2.1 Ví dụ Sai Lầm

Dưới đây là nỗ lực bao gói lớp công cụ chuyển đổi giữa InstantString. Vì nó có một số vấn đề nên chúng tôi đặt tên là FatalInstantUtil. Phương thức str2Instant được dùng để chuyển từ String sang Instant; phương thức instant2Str được dùng để chuyển từ Instant sang String.

// Ví dụ sai
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class FatalInstantUtil {
    public static Instant str2Instant(String dateTimeStr, String pattern) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(dateTimeStr, formatter)
                .atZone(ZoneId.systemDefault())
                .toInstant();
    }

    public static String instant2Str(Instant instant, String pattern) {
        return DateTimeFormatter.ofPattern(pattern).format(instant);
    }

    public static void main(String[] args) {
        // Chuyển chuỗi thành instant
        Instant instant = str2Instant("2023-11-15", "yyyy-MM-dd");
        System.out.println(instant);

        // Chuyển instant thành chuỗi
        String str = instant2Str(Instant.now(), "yyyy-MM");
        System.out.println(str);
    }
}

Khi sử dụng phương thức str2Instant để chuyển đổi từ String sang Instant, các đoạn mã dưới đây đều hoạt động bình thường:

str2Instant("2023-11-15 17:23:56", "yyyy-MM-dd HH:mm:ss");
str2Instant("2023-11-15 17:23", "yyyy-MM-dd HH:mm");
str2Instant("2023-11-15 17", "yyyy-MM-dd HH");

Tuy nhiên, các đoạn mã sau sẽ gây lỗi:

str2Instant("2023-11-15", "yyyy-MM-dd");
str2Instant("2023-11", "yyyy-MM");
str2Instant("2023", "yyyy");

Lỗi xảy ra khi thực thi str2Instant("2023-11-15", "yyyy-MM-dd") với thông báo như sau:

Exception in thread "main" java.time.format.DateTimeParseException: Text '2023-11-15' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {},ISO resolved to 2023-11-15 of type java.time.format.Parsed

Lý do của lỗi này nằm ở chỗ chưa cung cấp giá trị mặc định cho tháng, ngày, giờ, phút và giây. Nếu thiếu những giá trị này, DateTimeFormatter sẽ không biết phải xử lý chúng như thế nào và sẽ ném ra ngoại lệ DateTimeParseException.

Ngoài ra, khi sử dụng phương thức instant2Str để chuyển đổi từ Instant sang String, cũng sẽ xuất hiện lỗi. Ví dụ, khi thực thi instant2Str(Instant.now(), "yyyy-MM"), thông báo lỗi như sau:

Exception in thread "main" java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra

Nguyên nhân của lỗi này là do chưa chỉ định múi giờ cho DateTimeFormatter. Do đó, khi thực hiện format, nó không biết chuyển đổi theo múi giờ nào và sẽ ném ra ngoại lệ.

Sau khi hiểu rõ nguyên nhân của các lỗi, chúng ta sẽ sửa chữa và xem ví dụ đúng.

2.2 Ví dụ Đúng

Mã nguồn đã sửa như sau:

// Ví dụ đúng
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;

public class InstantUtil {
    public static Instant str2Instant(String dateTimeStr, String pattern) {
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .appendPattern(pattern)
                .parseDefaulting(ChronoField.MONTH_OF_YEAR, 1)
                .parseDefaulting(ChronoField.DAY_OF_MONTH, 1)
                .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
                .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
                .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
                .toFormatter();

        return LocalDateTime.parse(dateTimeStr, formatter)
                .atZone(ZoneId.systemDefault())
                .toInstant();
    }

    public static String instant2Str(Instant instant, String pattern) {
        return DateTimeFormatter.ofPattern(pattern)
                .withZone(ZoneId.systemDefault())
                .format(instant);
    }

    public static void main(String[] args) { [2233win](/post/2020-summary/) 
        // Chuyển chuỗi thành instant
        Instant instant = str2Instant("2023-11-15", "yyyy-MM-dd");
        System.out.println(instant);

        // Chuyển instant thành chuỗi
        String str = instant2Str(Instant.now(), "yyyy-MM");
        System.out.println(str);
    }
}

Trong đoạn mã đã sửa, phương thức str2Instant sử dụng DateTimeFormatterBuilder để xây dựng DateTimeFormatter. Nó sử dụng parseDefaulting để chỉ định giá trị mặc định cho tháng, ngày, giờ, phút và giây. Khi những giá trị này bị thiếu, chúng sẽ được điền bằng các giá trị mặc định và không còn gây lỗi.

Phương thức instant2Str đã được sửa bằng cách chỉ định múi giờ cho DateTimeFormatter, đảm bảo rằng việc chuyển đổi từ Instant sang String sẽ không gặp lỗi.

Từ đó, chúng ta đã hoàn thành việc thiết kế một lớp công cụ chuyển đổi giữa InstantString hiệu quả.

Toàn bộ mã nguồn trong bài viết đã được lưu trữ trên GitHub cá nhân của tôi, mọi người có thể theo dõi hoặc Fork.

[1] Java: Không thể lấy LocalDateTime từ TemporalAccessor khi phân tích LocalDateTime | Stack Overflow - stackoverflow.com
[2] Java: UnsupportedTemporalTypeException khi định dạng Instant thành String | Stack Overflow - stackoverflow.com

#Java