1. Tuần tự hóa nhị phân trong Java
Tuần tự hóa nhị phân là cơ chế tiêu chuẩn của Java, trong đó đối tượng được biến thành luồng byte một cách tối đa gọn nhẹ và nhanh chóng. Để làm điều này, sử dụng các lớp ObjectOutputStream và ObjectInputStream. Tệp thu được là một tập hợp byte, không dành cho con người đọc.
Gọi là nhị phân vì mọi thứ được tuần tự hóa ở dạng “thô”: số, chuỗi, mảng, thậm chí cả tham chiếu giữa các đối tượng đều biến thành byte. Nó giống như một chiếc vali được đóng gói chặt: hiệu quả và nhanh, nhưng nếu không có hướng dẫn thì không rõ thứ gì nằm ở đâu.
Nó hoạt động thế nào trong Java?
Giả sử chúng ta có lớp User:
import java.io.Serializable;
public class User implements Serializable {
private String name;
private int age;
// Constructor, getter và setter
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
Tuần tự hóa ra tệp nhị phân
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
User user = new User("Vasya", 30);
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
out.writeObject(user);
System.out.println("Đối tượng User đã được tuần tự hóa vào tệp user.bin");
} catch (Exception e) {
e.printStackTrace();
}
Giải tuần tự từ tệp nhị phân
import java.io.FileInputStream;
import java.io.ObjectInputStream;
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.bin"))) {
User loadedUser = (User) in.readObject();
System.out.println("Đã đọc từ tệp: " + loadedUser.getName() + ", " + loadedUser.getAge());
} catch (Exception e) {
e.printStackTrace();
}
Lưu ý: nếu mở tệp user.bin trong trình soạn thảo văn bản, bạn sẽ thấy thứ gì đó như: ¬í sr ... — điều đó là bình thường, nó được thiết kế như vậy!
Ưu điểm của tuần tự hóa nhị phân
- Gọn và nhanh. Ghi và đọc diễn ra nhanh nhất có thể, không có “trang trí” thừa.
- Lưu tất cả các trường của đối tượng, bao gồm cả đối tượng lồng nhau (nếu chúng cũng có thể tuần tự hóa qua Serializable).
- Dễ dùng cho bộ đệm nội bộ hoặc truyền giữa các chương trình Java.
Nhược điểm
- Khó đọc. Con người không thể mở và hiểu nội dung.
- Phụ thuộc chặt vào phiên bản lớp. Thay đổi cấu trúc (thêm/xóa trường) có thể làm “hỏng” việc đọc các tệp cũ.
- Vấn đề tương thích giữa các phiên bản Java và JVM khác nhau.
- Không phù hợp để trao đổi với các ngôn ngữ lập trình khác.
- Bảo mật: giải tuần tự dữ liệu từ nguồn không được kiểm chứng là con đường trực tiếp dẫn tới lỗ hổng.
2. Các định dạng tuần tự hóa dạng văn bản: JSON, XML và khác
Tuần tự hóa nhị phân tốt cho nội bộ, nhưng thường cần truyền dữ liệu giữa các ngôn ngữ khác nhau (Java, JavaScript, Python) hoặc lưu ở dạng dễ đọc — tiện cho cấu hình, log và API. Khi đó dùng các định dạng văn bản: JSON, XML, YAML, CSV và các định dạng khác.
JSON — phổ biến nhất
JSON (JavaScript Object Notation) là định dạng gọn và dễ đọc. Ví dụ đối tượng User đã được tuần tự hóa:
{
"name": "Vasya",
"age": 30
}
Trong Java, để làm việc với JSON thường dùng các thư viện: Jackson (phổ biến nhất), Gson, cũng như Moshi, JSON-B và các thư viện khác.
XML — người bạn cũ của lập trình viên
XML (Extensible Markup Language) dài dòng hơn, nhưng mang tính hình thức và nghiêm ngặt.
<User>
<name>Vasya</name>
<age>30</age>
</User>
Với XML trong Java, thường dùng thư viện chuẩn JAXB (hoặc XStream cũ hơn).
YAML, CSV và các định dạng khác
- YAML — giống JSON nhưng súc tích hơn; thường dùng cho cấu hình hơn là tuần tự hóa các đối tượng phức tạp.
- CSV — tốt cho các bảng “phẳng”, nhưng kém phù hợp với cấu trúc lồng nhau.
- Các định dạng khác có đủ loại, nhưng trong Java thường dùng JSON và XML.
3. So sánh định dạng: nên dùng khi nào?
| Định dạng | Tính dễ đọc | Độ gọn | Tốc độ | Tương thích | Khi nào dùng |
|---|---|---|---|---|---|
| Nhị phân | Không | ++ | ++ | Chỉ Java | Bộ đệm nội bộ, lưu/đọc nhanh giữa các JVM |
| JSON | Có | + | + | Bất kỳ ngôn ngữ nào | REST API, trao đổi với dịch vụ bên ngoài, cấu hình |
| XML | Có | - | - | Bất kỳ ngôn ngữ nào | Tích hợp, schema nghiêm ngặt, hệ thống cũ |
- Nhị phân — chọn cho mục đích nội bộ khi không cần trao đổi với hệ thống bên ngoài và hiệu năng tối đa là quan trọng.
- JSON — lựa chọn tốt nhất để trao đổi với ứng dụng web, client di động và REST API, cũng như để lưu cấu hình.
- XML — cần khi có schema nghiêm ngặt và tích hợp với các giải pháp “doanh nghiệp”.
Quan trọng! Tuần tự hóa nhị phân chỉ phù hợp để truyền dữ liệu giữa các chương trình Java, và ngay cả khi đó thì an toàn hơn khi dùng giữa các chương trình cùng phiên bản. Các định dạng văn bản như JSON và XML mang tính phổ quát hơn: chúng phù hợp để trao đổi dữ liệu giữa nhiều ngôn ngữ và nền tảng, giúp thông tin dễ đọc và dễ mang chuyển.
4. Thực hành: tuần tự hóa dạng nhị phân và văn bản
Tuần tự hóa nhị phân (ObjectOutputStream/ObjectInputStream)
Đã thấy ở trên, nhưng nhắc lại để củng cố:
// Tuần tự hóa
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
out.writeObject(user);
}
// Giải tuần tự
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.bin"))) {
User loadedUser = (User) in.readObject();
}
Tuần tự hóa sang JSON bằng Jackson (ngắn gọn)
Để làm việc với Jackson cần thêm các thư viện của nó vào dự án. Chúng ta sẽ học Maven và Gradle sau; hiện tại có thể thêm các tệp JAR thủ công. Ví dụ dependency cho Maven:
<!-- Maven -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
Ví dụ tuần tự hóa/giải tuần tự:
import com.fasterxml.jackson.databind.ObjectMapper;
User user = new User("Vasya", 30);
ObjectMapper mapper = new ObjectMapper();
try {
// Tuần tự hóa ra chuỗi
String json = mapper.writeValueAsString(user);
System.out.println(json); // {"name":"Vasya","age":30}
// Tuần tự hóa ra tệp
mapper.writeValue(new File("user.json"), user);
// Giải tuần tự từ chuỗi
User loadedUser = mapper.readValue(json, User.class);
// Giải tuần tự từ tệp
User loadedFromFile = mapper.readValue(new File("user.json"), User.class);
} catch (Exception e) {
e.printStackTrace();
}
Tệp JSON có thể mở bằng bất kỳ trình soạn thảo văn bản nào, giúp dữ liệu dễ đọc và dễ chuyển giữa các ứng dụng và ngôn ngữ khác nhau.
5. Khi dùng định dạng nào: lời khuyên thực tế
- Bộ đệm nội bộ, tệp tạm, ghi/đọc nhanh giữa các chương trình Java: hãy dùng tuần tự hóa nhị phân chuẩn. Nhưng nhớ vấn đề tương thích phiên bản!
- Trao đổi với dịch vụ bên ngoài, lưu cấu hình, tích hợp với frontend: sử dụng JSON (Jackson, Gson).
- Tích hợp với hệ thống “doanh nghiệp”, nơi yêu cầu schema nghiêm ngặt: XML (JAXB).
- Cần người dùng có thể mở và đọc tệp: JSON hoặc XML, không phải định dạng nhị phân.
6. Các lỗi thường gặp khi làm việc với các định dạng tuần tự hóa
Lỗi № 1: Cố tuần tự hóa đối tượng có các trường không thể tuần tự hóa. Nếu lớp của bạn có một trường không triển khai Serializable (ví dụ, stream hoặc kết nối DB), tuần tự hóa nhị phân sẽ báo lỗi. Với JSON điều này không quá nghiêm trọng, nhưng với các kiểu “không tiêu chuẩn” cũng có thể gặp vấn đề.
Lỗi № 2: Mở tệp nhị phân trong trình soạn thảo văn bản rồi hoảng sợ. Điều đó là bình thường! Tệp nhị phân không dành cho con người đọc.
Lỗi № 3: Thay đổi cấu trúc lớp và các tệp nhị phân cũ không còn đọc được. Tuần tự hóa nhị phân nhạy cảm với thay đổi cấu trúc lớp — thường gặp InvalidClassException. Trong JSON/XML điều này ít nghiêm trọng hơn: các trường không biết thường bị bỏ qua hoặc nhận giá trị mặc định.
Lỗi № 4: Dùng tuần tự hóa nhị phân để trao đổi với hệ thống bên ngoài. Điều này sẽ không hiệu quả: định dạng nhị phân chỉ Java hiểu, và ngay cả vậy cũng cần trùng phiên bản.
Lỗi № 5: Quên thêm các annotation cần thiết cho JSON/XML. Một số thư viện yêu cầu annotation như @JsonProperty, @XmlElement, nếu không, tuần tự hóa/giải tuần tự có thể hoạt động không như kỳ vọng.
Lỗi № 6: Không kiểm tra rằng mọi đối tượng lồng nhau đều có thể tuần tự hóa. Với tuần tự hóa nhị phân đây là vấn đề phổ biến; với JSON — cũng có thể, nếu mô hình xuất hiện các kiểu phức tạp.
GO TO FULL VERSION