JavaRush /Курси /JAVA 25 SELF /Стандартні формати серіалізації: бінарний, текстовий

Стандартні формати серіалізації: бінарний, текстовий

JAVA 25 SELF
Рівень 42 , Лекція 2
Відкрита

1. Бінарна серіалізація в Java

Бінарна серіалізація — це стандартний механізм Java, за якого об’єкт перетворюється на потік байтів максимально компактно й швидко. Для цього використовуються класи ObjectOutputStream і ObjectInputStream. Отриманий файл — набір байтів, який не призначений для читання людиною.

Її називають бінарною, оскільки все серіалізується в «сирому» вигляді: числа, рядки, масиви, навіть посилання між об’єктами перетворюються на байти. Це як щільно запакована валіза: ефективно й швидко, але без інструкції неочевидно, де що лежить.

Як це працює в Java?

Припустімо, у нас є клас User:

import java.io.Serializable;

public class User implements Serializable {
    private String name;
    private int age;

    // Конструктор, гетери та сетери
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }
}

Серіалізація у бінарний файл

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

User user = new User("Вася", 30);

try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
    out.writeObject(user);
    System.out.println("Об’єкт User серіалізовано у файл user.bin");
} catch (Exception e) {
    e.printStackTrace();
}

Десеріалізація з бінарного файлу

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("Прочитали з файлу: " + loadedUser.getName() + ", " + loadedUser.getAge());
} catch (Exception e) {
    e.printStackTrace();
}

Увага: якщо відкрити файл user.bin у текстовому редакторі, ви побачите щось на кшталт: ¬í sr ... — це нормально, так і задумано!

Переваги бінарної серіалізації

  • Компактність і швидкість. Збереження та читання виконуються максимально швидко, без зайвих «прикрашань».
  • Зберігаються всі поля об’єкта, включно із вкладеними об’єктами (якщо вони також серіалізовані через Serializable).
  • Просто використовувати для внутрішнього кешу або передавання між Java-програмами.

Недоліки

  • Нечитабельність. Людина не зможе «підглянути» вміст і зрозуміти, що там.
  • Жорстка прив’язаність до версії класу. Зміна структури (додавання/видалення полів) може «зламати» читання старих файлів.
  • Проблеми сумісності між різними версіями Java і JVM.
  • Не підходить для обміну з іншими мовами програмування.
  • Безпека: десеріалізація даних із неперевірених джерел — прямий шлях до вразливостей.

2. Текстові формати серіалізації: JSON, XML та інші

Бінарна серіалізація добра для внутрішнього використання, але часто потрібно передавати дані між різними мовами (Java, JavaScript, Python) або зберігати їх у читабельному вигляді — зручно для конфігурацій, логів, API. Для цього використовують текстові формати: JSON, XML, YAML, CSV тощо.

JSON — найпопулярніший

JSON (JavaScript Object Notation) — компактний і читабельний формат. Приклад серіалізованого об’єкта User:

{
  "name": "Вася",
  "age": 30
}

У Java для роботи з JSON найчастіше використовують бібліотеки: Jackson (найпопулярніша), Gson, а також Moshi, JSON-B тощо.

XML — давній друг програміста

XML (Extensible Markup Language) — більш «багатослівний», але формальний і строгий.

<User>
  <name>Вася</name>
  <age>30</age>
</User>

Для XML у Java часто застосовують стандартну бібліотеку JAXB (або старішу XStream).

YAML, CSV та інші

  • YAML — схожий на JSON, але більш лаконічний; частіше використовують для конфігурацій, ніж для серіалізації складних об’єктів.
  • CSV — добрий для «пласких» таблиць, але погано підходить для вкладених структур.
  • Інші формати є на будь-який смак, але в Java найчастіше використовують JSON і XML.

3. Порівняння форматів: коли що використовувати?

Формат Читабельність Компактність Швидкість Сумісність Коли використовувати
Бінарний Ні ++ ++ Лише Java Внутрішній кеш, швидке збереження між JVM
JSON Так + + Будь-які мови REST API, обмін із зовнішніми сервісами, конфіги
XML Так - - Будь-які мови Інтеграція, суворі схеми, старі системи
  • Бінарний — обирайте для внутрішнього використання, коли не потрібен обмін із зовнішніми системами й важлива максимальна продуктивність.
  • JSON — найкращий вибір для обміну з вебзастосунками, мобільними клієнтами та REST API, а також для зберігання налаштувань.
  • XML — потрібен за суворих схем і інтеграції з «корпоративними» рішеннями.

Важливо! Бінарна серіалізація підходить лише для передавання даних між Java-програмами, і навіть у цьому випадку безпечніше використовувати її між програмами однієї версії. Текстові формати на кшталт JSON і XML універсальніші: вони підходять для обміну даними між різними мовами та платформами, роблячи інформацію читабельною й переносимою.

4. Практика: серіалізація в бінарний і текстовий формат

Бінарна серіалізація (ObjectOutputStream/ObjectInputStream)

Уже бачили вище, але повторимо для закріплення:

// Серіалізація
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("user.bin"))) {
    out.writeObject(user);
}

// Десеріалізація
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("user.bin"))) {
    User loadedUser = (User) in.readObject();
}

Серіалізація в JSON за допомогою Jackson (коротко)

Щоб працювати з Jackson, потрібно додати його бібліотеки до проєкту. Згодом ми вивчимо Maven і Gradle, а поки що можна під’єднати JAR-файли вручну. Приклад залежності для Maven:

<!-- Maven -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.17.0</version>
</dependency>

Приклад серіалізації/десеріалізації:

import com.fasterxml.jackson.databind.ObjectMapper;

User user = new User("Вася", 30);
ObjectMapper mapper = new ObjectMapper();

try {
    // Серіалізація в рядок
    String json = mapper.writeValueAsString(user);
    System.out.println(json); // {"name":"Вася","age":30}

    // Серіалізація у файл
    mapper.writeValue(new File("user.json"), user);

    // Десеріалізація з рядка
    User loadedUser = mapper.readValue(json, User.class);

    // Десеріалізація з файлу
    User loadedFromFile = mapper.readValue(new File("user.json"), User.class);

} catch (Exception e) {
    e.printStackTrace();
}

JSON-файл можна відкрити в будь-якому текстовому редакторі, що робить дані легко читабельними та переносними між різними застосунками й мовами.

5. Коли який формат використовувати: практичні поради

  • Внутрішнє кешування, тимчасові файли, швидкий запис/читання між Java-програмами: використовуйте стандартну бінарну серіалізацію. Але пам’ятайте про сумісність версій!
  • Обмін із зовнішніми сервісами, зберігання налаштувань, інтеграція з фронтендом: використовуйте JSON (Jackson, Gson).
  • Інтеграція з «корпоративними» системами, де потрібна сувора схема: XML (JAXB).
  • Потрібно, щоб людина могла відкрити й прочитати файл: JSON або XML, але не бінарний формат.

6. Типові помилки під час роботи з форматами серіалізації

Помилка № 1: Намагаються серіалізувати об’єкт із несеріалізованими полями. Якщо у вашого класу є поле, яке не реалізує Serializable (наприклад, потік або з’єднання з БД), бінарна серіалізація спричинить помилку. Для JSON це не так критично, але з «нестандартними» типами також трапляються проблеми.

Помилка № 2: Відкривають бінарний файл у текстовому редакторі й лякаються. Це нормально! Бінарні файли не призначені для читання людиною.

Помилка № 3: Змінюють структуру класу, а старі бінарні файли перестають читатися. Бінарна серіалізація чутлива до змін структури класу — часто виникає InvalidClassException. У JSON/XML це менш критично: невідомі поля зазвичай ігноруються або отримують значення за замовчуванням.

Помилка № 4: Використовують бінарну серіалізацію для обміну із зовнішніми системами. Це не спрацює: бінарний формат розуміє лише Java, та й то за збігу версій.

Помилка № 5: Для JSON/XML забувають додати необхідні анотації. Деякі бібліотеки вимагають анотації на кшталт @JsonProperty, @XmlElement, інакше серіалізація/десеріалізація може працювати не так, як очікується.

Помилка № 6: Не перевіряють, що всі вкладені об’єкти можуть бути серіалізовані. Для бінарної серіалізації це часта проблема; для JSON — теж, якщо в моделі трапляються складні типи.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ