Вышла общедоступная версия Java 20. В этот релиз попало около 1500 закрытых задач и 7 JEP'ов. Release Notes можно посмотреть здесь. Изменения API – здесь.



Ссылки на скачивание:




Вот список JEP'ов, которые попали в Java 20.



Паттерны записей (Second Preview) (JEP 432)


В паттерны записей, которые появились в Java 19 в режиме preview (и остающиеся в этом статусе в Java 20), было внесено три главные изменения.



Во-первых, добавилась поддержка вывода типов в записях-дженериках:


record Box<T>(T t) {}

static void test(Box<String> box) {
    if (box instanceof Box(var s)) { // Выводится Box<String>(var s)
        System.out.println("String " + s);
    }
}


Во-вторых, паттерны записей теперь могут присутствовать в заголовке улучшенного цикла for:


record Point(int x, int y) {}

static void dump(Point[] pointArray) {
    for (Point(var x, var y) : pointArray) {
        System.out.println("(" + x + ", " + y + ")");
    }
}

Примечание: эту возможность было решено удалить в Java 21, но она снова может появиться в будущем в другом JEP'е.



В-третьих, исчезла поддержка именованных паттернов записей. Это значит, что такой код, который компилировался в Java 19, в Java 20 уже не будет компилироваться:


if (obj instanceof Point(var x, var y) p) { // Syntax error
    ...
}


Хотя именованные паттерны и исчезли в этом релизе, это не значит, что они исчезли насовсем. Возможно они появятся в одном из будущих релизов, когда будут более тщательно продуманы.



Паттерн-матчинг для switch (Fourth Preview) (JEP 433)


Это уже четвёртая итерация preview паттерн-матчинга в Java. Напомним, что предыдущие три попали в Java 17, 18 и 19. В новой версии три главных изменения.



Во-первых, исчерпывающий switch по перечислениям теперь выбрасывает MatchException, а не IncompatibleClassChangeError, если ни одна из меток switch не сматчилась.



Во-вторых, упростилась грамматика меток switch в JLS.



В-третьих, добавилась поддержка вывода типов в записях-дженериках, если они являются паттернами в switch:


record Pair<S, T>(S first, T second) {}

static void recordInference(Pair<String, Integer> pair) {
    switch (pair) {
        case Pair(var fst, var snd) -> ... // Выводится Pair<String, Integer>
        ...
    }
}


Как видите, здесь JEP 433 полностью согласуется с JEP 432.



Паттерны записей и паттерн-матчинг для switch предлагается финализировать в Java 21 (JEP 440 и JEP 441).



Virtual Threads (Second Preview) (JEP 436)


Виртуальные потоки, которые появились в Java 19, продолжают оставаться в статусе Preview API (предлагается финализировать их в Java 21). Изменений API, связанных с проектом Loom, в этом релизе нет (если не считать scoped values и structured concurrency, которые имеют инкубационный статус).



Scoped Values (Incubator) (JEP 429)


Появился новый класс ScopedValue, который позволяет обмениваться иммутабельными данными без их передачи через аргументы методов. Он является альтернативой существующему классу ThreadLocal.


Классы ThreadLocal и ScopedValue похожи тем, что решают одну и ту же задачу: передать значение переменной в рамках одного потока (или дерева потоков) из одного места в другое без использования явного параметра. В случае ThreadLocal для этого вызывается метод set(), который кладёт значение переменной для данного потока, а потом метод get() вызывается из другого места для получения значения переменной. У данного подхода есть ряд недостатков:


  • Неконтролируемая мутабельность (set() можно вызвать когда угодно и откуда угодно).
  • Неограниченное время жизни (переменная очистится, только когда завершится исполнение потока или когда будет вызван ThreadLocal.remove(), но про него часто забывают).
  • Высокая цена наследования (дочерние потоки всегда вынуждены делать полную копию переменной, даже если родительский поток никогда не будет её изменять).

Эти проблемы усугубляются с появлением виртуальных потоков, которые могут создаваться в гораздо больше количестве, чем обычные.


ScopedValue лишён вышеперечисленных недостатков. В отличие от ThreadLocal, ScopedValue не имеет метода set(). Значение ассоциируется с объектом ScopedValue путём вызова другого метода where(). Далее вызывается метод run(), на протяжении которого это значение можно получить (через метод get()), но нельзя изменить. Как только исполнение метода run() заканчивается, значение отвязывается от объекта ScopedValue. Поскольку значение не меняется, решается и проблема дорогого наследования: дочерним потоком не надо копировать значение, которое остаётся постоянным в течение периода жизни.

Пример использования ScopedValue:


static final ScopedValue<Credentials> CREDENTIALS = new ScopedValue<>();

Credentials creds = ...
ScopedValue.where(CREDENTIALS, creds).run(() -> {
   ...
   Connection connection = connectDatabase();
   ...
});

Connection connectDatabase() {
   Credentials credentials = CREDENTIALS.get();
   ...
}

Во многих случаях ScopedValue будет являться предпочтительной заменой ThreadLocal. Однако когда иммутабельный подход неприменим для решения задачи, ThreadLocal может остаться предпочтительным.


На период инкубации новое API будет находиться в модуле jdk.incubator.concurrent.


В Java 21 scoped values, скорее всего, станут preview.



Structured Concurrency (Second Incubator) (JEP 437)


Structured concurrency, которое появилось в Java 19, остаётся в инкубационном статусе в модуле jdk.incubator.concurrent (вместе со ScopedValue).


Единственное отличие от предыдущей версии API – это то, что StructuredTaskScope теперь поддерживает наследование scoped values потоками, созданными внутри области видимости задачи.



Foreign Function & Memory API (Second Preview) (JEP 434)


Foreign Function & Memory API, ставшее preview в Java 19, продолжает находиться в этом статусе. API находится в пакете java.lang.foreign.


Основные изменения в этом релизе:


  • Исчез интерфейс MemoryAddress. Теперь адреса моделируются через MemorySegment с нулевой длиной.
  • Улучшена иерархия sealed интерфейса MemoryLayout, чтобы лучше соответствовать паттерн-матчингу для switch.
  • Исчез интерфейс MemorySession. Он разделён на два интерфейса Arena и SegmentScope.

В Java 21 Foreign Function & Memory API останется на третье preview.



Vector API (Fifth Incubator) (JEP 438)


Векторное API всё никак не хочет становиться стабильным и остаётся в инкубационном статусе уже в пятый раз (модуль jdk.incubator.vector). В этом релизе лишь небольшие исправления багов и улучшения производительности. Скорее всего, инкубационный статус будет оставаться до тех пор, пока необходимые фичи проекта Valhalla не появятся в режиме preview (проект Panama сильно зависит от проекта Valhalla).



Заключение


Java 20 не является LTS-релизом и будет получать обновления от Oracle только в течение полугода (до сентября 2023 года). LTS-релизом станет следующая версия, Java 21.

Комментарии (22)


  1. SimSonic
    00.00.0000 00:00
    -5

    Ждём, пока ломбок подтянется, и в прод!


    1. kzoraks
      00.00.0000 00:00
      +1

      здесь так много людей, которые не любят ломбок ?


      1. SimSonic
        00.00.0000 00:00
        +1

        Здесь так много тех, кто любит минусовать и не аргументировать :)


  1. Demos7787
    00.00.0000 00:00
    -17

    Какой смысл в Java, если есть .NET 7?


    1. atygaev
      00.00.0000 00:00
      +7

      Так .NET-то всего 7, Java-то уже 21. Java уже взрослая, пригодна для серьезной работы)))


    1. breninsul
      00.00.0000 00:00
      +1

      Для котлина


    1. nepempaxep
      00.00.0000 00:00
      -4

      a ego i ne bylo


    1. Yo1
      00.00.0000 00:00

      На .net пишут лишь унылую бизнес логику, элита что пишет хадупы, spark, Kafka, Cassandra, h2o плотно сидит на jvm языках


  1. endpoints
    00.00.0000 00:00
    +9

    Столько нового напихали, не нравится мне такой ускоренный темп штамповки новых версии


    1. tmaxx
      00.00.0000 00:00
      +5

      А вы смотрите только на стабильные фичи, а не на «выкатили превью» - «упс, фигня вышла, откатили обратно». Получится не так много.

      Стабильные JEP’ы в 20 и 19 версиях отсутствуют (если не считать порт на неведомый RISC-V). В 18 и 17 - несколько мелких APIs и deprecations.

      Из больших проектов двигается только Amber (синтаксический сахар).

      java.lang.foreign судя по всему к сентябрю не стабилизируют - то есть это еще минимум 2,5 года жизни с Unsafe

      Если виртуальные потоки выкатят по нормальному в 21-й - уже за счастье будет


    1. PahanMenski
      00.00.0000 00:00
      +1

      По мне так наоборот - ужасно медленно развивается, особенно если с C# сравнивать. Хорошо, что Kotlin есть.


      1. tsypanov
        00.00.0000 00:00

        Будь ниша Котлина столь же объёмна, как ниша джавы, он развивался бы столь же медленно.


        1. orionll Автор
          00.00.0000 00:00
          +3

          По-моему, в последнее время темп развития Котлина сильно замедлился, а Джавы – наоборот, ускорился


          1. nerumb
            00.00.0000 00:00

            Большие языковые изменения тяжело делать до выхода K2, иначе каждую из них придется делать 2 раза в обоих компиляторах. Но близится дата релиза, после нее, надеюсь, фичи будут активнее появляться.


          1. tsypanov
            00.00.0000 00:00

            Согласен, есть такое. Котлин на первых порах реализовал много того, что хотели в джаве и благодаря юности мог быстро и безболезенно меняться. Ну и его ниша даже сейчас, если верить https://pypl.github.io/PYPL.html, - 1,82% доля джавы - 16,58%. А сейчас объективно нужно оглядываться на сообщество и экосистему, плюс накапливается технический долг, плюс кодовая база растёт, поэтому стало медленее.


          1. SimSonic
            00.00.0000 00:00
            +1

            Джава ускорилась, и JebBrains приходится больше сил тратить на её поддержку в IDEA, чем развивать Котлин :)


  1. granit1986
    00.00.0000 00:00

    А в чём прикол выпускать в релизных версиях превью каких-то фич? Мне кажется идея не очень


    1. Prototik
      00.00.0000 00:00
      +1

      Именно что бы народ попробовал и оценил, дал обратную связь и скорректировать разработку до релиза. А то впилят какую-то фичу как стабильную, потом выясняется, что всё не так надо было делать и вообще по-другому, а старое трогать уже нельзя, штабильность же.


      1. granit1986
        00.00.0000 00:00

        Почему тогда не делать превью версии, как у .NET?


        1. Shatun
          00.00.0000 00:00

          А чем превью версии лучше чем превью фичи? Мне кажется просто разный подход.


    1. kzoraks
      00.00.0000 00:00

      так это не LTS релиз это раз, во вторых если выкатывать эти фичи в каких-то бета сборках их будут тестить единицы, а так потенциально каждая крупная компания может оставить фидбэк


      1. granit1986
        00.00.0000 00:00
        +1

        Вряд ли крупные компании кинутся сразу пробовать новую превью фичу. Не уверен, что вообще много где последние версии используют