Каковы ключевые различия между JDK 8 и JDK 21?

Ответ

Переход с JDK 8 на JDK 21 (LTS) — это огромный скачок, включающий множество нововведений, которые меняют стиль программирования на Java.

1. Новые возможности языка (после Java 8)

  • Локальный вывод типов (var, Java 10): var list = new ArrayList<String>();
  • Switch выражения (Java 14, доработаны): Возвращают значение и используют новый синтаксис ->.
    // JDK 21 (окончательная версия)
    String dayType = switch (day) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
    case SATURDAY, SUNDAY -> "Weekend";
    };
  • Текстовые блоки (Java 15): Многострочные строки.
    String json = """
    {
        "name": "John",
        "age": 30
    }
    """;
  • Records (Java 16): Неизменяемые классы для хранения данных.
    record Point(int x, int y) {}
  • Sealed классы (Java 17): Контролируют иерархию наследования.
    public sealed class Shape permits Circle, Rectangle, Triangle {}
  • Pattern Matching (постепенное внедрение):
    • instanceof с паттернами (Java 16): if (obj instanceof String s) { System.out.println(s.length()); }
    • Pattern Matching for switch (Java 21, preview в более ранних): Позволяет использовать паттерны и sealed-иерархии в switch.
      // Упрощенная форма с Records и Sealed классами
      String format(Object obj) = switch (obj) {
      case Point(int x, int y) -> String.format("Point(%d,%d)", x, y);
      case null -> "null";
      default -> obj.toString();
      };
  • Virtual Threads (Java 21): Важнейшая инновация. Легковесные потоки, управляемые JVM, для написания высокомасштабируемого синхронного кода без сложностей асинхронного программирования.
    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
    } // Запуск 10k "потоков" становится практичным

2. Изменения в JDK и API

  • Модульная система (Java 9): JPMS, jlink для создания минимальных runtime-образов.
  • Новые сборщики мусора:
    • ZGC (Java 15): Масштабируемый низколатентный сборщик.
    • Shenandoah (Java 12): Низколатентный сборщик с одновременной эвакуацией.
    • G1 — сборщик по умолчанию с Java 9.
  • Удаление устаревших компонентов: Полностью удалены Java EE, CORBA модули, Nashorn JavaScript движок.
  • Улучшения производительности: Непрерывные улучшения JIT-компилятора, новые API (например, Vector API — incubator до Java 21).

3. Процесс выпуска

  • Быстрый цикл релизов: С Java 9 новый фича-релиз каждые 6 месяцев, LTS-релиз каждые 2 года (11, 17, 21).
  • Preview-фичи: Новые возможности сначала выпускаются в статусе preview для тестирования (например, pattern matching в switch).

Итог: JDK 21 предлагает революционные изменения: виртуальные потоки для масштабируемости, современный синтаксис (records, pattern matching, sealed classes) для выразительности и безопасного кода, а также современную runtime-платформу с улучшенной производительностью и безопасностью. Миграция с JDK 8 требует значительных усилий по модернизации кода и зависимостей, но открывает доступ к современной экосистеме Java.

Ответ 18+ 🔞

Вот, смотри, слышь, что творится в мире Java. Сидишь ты такой на своём JDK 8, как царь на печи, всё тебя устраивает, лямбды есть, стримы есть — красота, блядь. А потом бац — и вокруг уже JDK 21, и ты чувствуешь себя, будто из пещеры с дубиной вылез, а вокруг уже летающие тарелки и лазерные хуи.

Переход с восьмёрки на двадцать первую — это не обновление, это, сука, прыжок через пропасть на мотоцикле. Овердохуища всего нового налепили, глаза разбегаются.

1. Новые штуки в языке (после того, как ты застрял на восьмёрке)

  • var (Java 10): Теперь можно не писать ArrayList<String> list = new ArrayList<String>();, а просто var list = new ArrayList<String>();. Не "динамическая типизация", а "локальный вывод типов", умники говорят. Удобно, но сначала глаз дёргается.
  • Switch, который внезапно стал выражением (Java 14): Раньше switch был таким громоздким, что хотелось в глаза себе вилкой ткнуть. Теперь он может значение возвращать, да ещё и с новой стрелочкой ->.
    // Вот так теперь, в JDK 21
    String dayType = switch (day) {
    case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "Weekday";
    case SATURDAY, SUNDAY -> "Weekend";
    };
    // Красота, блядь. Ни одного break, всё чисто.
  • Текстовые блоки (Java 15): Наконец-то, ебать мои старые костыли, можно JSON, SQL или HTML в коде писать без этих диких конкатенаций и экранирований.
    String json = """
    {
        "name": "John",
        "age": 30
    }
    """;
    // Просто взял и написал. Как в Питоне, только Java, блядь.
  • Records (Java 16): Это просто песня, а не фича. Раньше ты писал класс DataTransferObject на 100 строк с геттерами, сеттерами, equals, hashCode и toString. Теперь — раз, и готово.
    record Point(int x, int y) {}
    // Всё, ёпта. Класс создан. Он immutable, у него всё есть. Волшебство, блядь.
  • Sealed классы (Java 17): Раньше ты пишешь абстрактный класс Shape и молишься, чтобы какой-нибудь хитрожопый коллега не унаследовал от него класс UglyShapeWithSideEffects. Теперь можно явно указать, кто имеет право наследоваться.
    public sealed class Shape permits Circle, Rectangle, Triangle {}
    // Всё, приехали. Больше никаких сюрпризов. Компилятор сам следит, чтобы пидарасы шерстяные не лезли.
  • Pattern Matching (постепенно внедряли):
    • instanceof без каста (Java 16): Раньше if (obj instanceof String) { String s = (String) obj; ... }. Теперь if (obj instanceof String s) { System.out.println(s.length()); }. Мелочь, а приятно, блядь.
    • Pattern Matching в switch (Java 21): Вот это уже мощно. Можно прямо в switch разбирать объекты по полям, особенно с record и sealed классами.
      // Смотри, какая красота получается
      String format(Object obj) = switch (obj) {
      case Point(int x, int y) -> String.format("Point(%d,%d)", x, y); // Разобрал record нахуй!
      case null -> "null"; // И с null можно работать явно!
      default -> obj.toString();
      };
  • Virtual Threads (Java 21): А вот это, блядь, главная причина, ради которой стоит всё это городить. Виртуальные потоки. Раньше чтобы 10 тысяч соединений обслужить, нужно было либо городить асинхронщину с колбэками (пиздец, а не код), либо пул потоков на 200 ядер раздувать. Теперь — пожалуйста, на каждый запрос свой легковесный виртуальный поток. JVM сама всем управляет.
    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1)); // И не бойся блокирующих операций!
            return i;
        });
    });
    } // Запуск 10 тысяч "потоков" — теперь не безумие, а норма.

2. Что там под капотом поменяли

  • Модули (Java 9): JPMS, ёперный театр. С одной стороны, можно минимальные runtime-образы собирать (jlink), с другой — если у тебя legacy-проект, то это головная боль ебаная на этапе миграции.
  • Новые сборщики мусора: ZGC и Shenandoah. Говорят, низколатентные, масштабируемые. Если у тебя не высоконагруженный сервис, можешь пока и на G1 (он теперь по умолчанию) остаться. Но знать, что они есть, — надо.
  • Выкинули всё лишнее: Java EE, CORBA, Nashorn (JavaScript движок) — всё, в утиль. Не грусти, они тебе всё равно не нужны были.
  • Производительность: JIT-компилятор постоянно улучшают, новые API для векторных операций пилят (Vector API). В общем, железо жмут по полной.

3. Как теперь релизы выходят

  • Каждые полгода — новый релиз. Как в браузерах, блядь. LTS (Long-Term Support) — только каждые два года (11, 17, 21). Остальные — просто фичи, поддержка короткая.
  • Preview-фичи: Самые сырые и интересные штуки сначала выпускают как preview. Их нужно специально ключом включать, чтобы потестить. Pattern matching в switch так года три в этом статусе болтался.

Итог, Колян: Сидеть на JDK 8 в 2024 году — это как ездить на Запорожце, когда у всех уже Теслы. Да, Запорожец завёлся и едет, но ебушки-воробушки, насколько же вокруг всё изменилось. JDK 21 — это виртуальные потоки (прощай, сложная асинхронщина), это records и pattern matching (прощай, boilerplate-код), это sealed классы (прощай, неконтролируемое наследование). Миграция будет больно, зависимости поломаются, придётся код переписывать. Но игра, блядь, стоит свеч. Потому что после перехода ты оказываешься в современном мире, а не в музее.