Что нового в java 11
Перейти к содержимому

Что нового в java 11

  • автор:

Зарелизилась Java 11 — что же там нового?

Парни, это случилось. Наконец-то зарелизилась следующая версия long-term support (LTS) версия Java 11 — https://blogs.oracle.com/java-platform-group/introducing-java-se-11. Что же хорошего там появилось?

В первую очередь, к сожалению, надо поговорить за плохие новости. Пришло время сказать: «Пока» — Ораклу. Увы, пацаны решили, что хватит за бесплатно поставлять LTS-версии Джавы. Теперь все длинные релизы будут только за деньги. Oracle просто позволит вам пользоваться 11-ой джавой до тех пор, пока не появится 12-ая версия, то есть, около 6 месяцев (примерно, до марта 2019 года, когда должен состояться релиз Java 12).

Как жить дальше? Если честно, не очень понятно. У нас есть ряд Java-вендоров: IBM, RedHat, Oracle, Azul и Excelsior JET (последние две ещё и из Новосибирска, респект пацанам, делают реальную работу). Ещё у нас есть OpenJDK — по факту, почти нолная копия версии Oracle Java. Бесплатно, как я понимаю, сейчас можно использовать только OpenJDK. Вроде как, Java 11 от OpenJDK будет доступна вплоть до Сентября 2022 года. Наверное, это сейчас единственный здравый вариант.

По поводу Фич. Их, на самом деле, довольно много. Ведь весь мир сидел на Java 8, а сейчас все начнут мигрировать на Java 11. Поэтому, по факту мы рассматриваем сразу 3 релиза. На самом деле, уже есть довольно много статей, которые описывают, что произошло за это время. Например, эта — https://winterbe.com/posts/2018/09/24/java-11-tutorial/, или эта — https://blog.codefx.org/java/java-11-migration-guide/.

Если кратко, то можно выделить следующие важные вещи:

    Ключевое слово var для локальных переменных. Все, кто ревьюит код в браузере, заплакали в этом месте.

var text = "Hello Java 10";
var list = List.of("A", "B", "C");

Ещё важно, что появилась возможность использовать GraalVM JIT буквально с помощью нескольких ключиков. Об этом часто любит рассказывать Олег Чирухин (парень, который щас херачит по 7 статей в неделю на хабр за джаву). Вроде как, использование этого JIT-а принесёт вам прирост перфоманса. Но это всё такое. надо тестить на ваших нагрузках. Кстати, есть и второй проповедующий Грааль в Рунете, тоже Олег — Oleg Šelajev. Так что, если у вас будут проблемы с Граалем, есть пацаны, с кем можно перетереть за это.

Конечно же, это далеко не полный список того, что появилось нового в Java 11. Есть масса оптимизаций в компиляторе, а также виртуальной машине, которые просто автоматически ускорят ваши программы. Кроме того, добавлются новые фичи, направленные на секьюрность. Например, поддержка TLS 1.3. Поэтому, в любом случае стоит обновляться, как бы это не было сейчас больно.

Другие записи из этой рубрики:

  • Java EE 7 — Введение
  • Курс Java EE 7
  • Реактивный JPoint 2019
Обо мне

Всем привет! Меня зовут Денис. Я увлекаюсь веб-разработкой, а также пытаюсь стать профессионалом в стеке технологий Linux, Apache, MySQL, PHP.

twitter icon

@Hixon101

Прямой эфир
  • Пишем простой Roslyn анализатор для C#
  • С новым, 2024 годом
  • Как переехать с WordPress на Cloudflare Pages
  • Используем telegram как второй фактор аутентификации
  • Мои любимые VIM жесты движений (motions)

© 2012 — 2024 hixon.ru — Копирование материалов сайта запрещено.

Новые функции в Java 11

Oracle выпустила Java 11 в сентябре 2018 года, всего через 6 месяцев после предшественницы, версии 10.

Java 11 — это первый выпуск с долгосрочной поддержкой (LTS) после Java 8. Oracle также прекратила поддержку Java 8 в январе 2019 года. Как следствие, многие из нас перейдут на Java 11.

В этом руководстве мы рассмотрим варианты выбора JDK для Java 11. Затем мы рассмотрим новые функции, удаленные функции и улучшения производительности, представленные в Java 11.

2. Oracle против Open JDK​

Java 10 был последним бесплатным выпуском Oracle JDK, который мы могли использовать в коммерческих целях без лицензии. Начиная с Java 11, Oracle не предоставляет бесплатную долгосрочную поддержку (LTS).

К счастью, Oracle продолжает предоставлять выпуски Open JDK , которые мы можем скачать и использовать бесплатно.

Помимо Oracle, мы можем рассмотреть и других поставщиков Open JDK .

3. Функции разработчика​

Давайте посмотрим на изменения в общих API, а также на некоторые другие функции, полезные для разработчиков.

3.1. Новые строковые методы​

В Java 11 к классу String добавлено несколько новых методов « : isBlank , lines , strip , stripLeading , stripTrailing и repeat .

Давайте посмотрим, как мы можем использовать новые методы для извлечения непустых зачищенных строк из многострочной строки:

 String multilineString = "ForEach helps \n \n developers \n explore Java.";   ListString> lines = multilineString.lines()   .filter(line -> !line.isBlank())   .map(String::strip)   .collect(Collectors.toList());   assertThat(lines).containsExactly("ForEach helps", "developers", "explore Java."); 

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

В случае методов полосы они обеспечивают функциональность, аналогичную более знакомому методу обрезки ; однако с более точным управлением и поддержкой Unicode.

3.2. Новые файловые методы​

Кроме того, теперь стало проще читать и записывать String из файлов.

Мы можем использовать новые статические методы readString и writeString из класса Files :

 Path filePath = Files.writeString(Files.createTempFile(tempDir, "demo", ".txt"), "Sample text");   String fileContent = Files.readString(filePath);   assertThat(fileContent).isEqualTo("Sample text"); 

3.3. Коллекция в массив​

Интерфейс java.util.Collection содержит новый метод toArray по умолчанию , который принимает аргумент IntFunction .

Это упрощает создание массива нужного типа из коллекции:

 List sampleList = Arrays.asList("Java", "Kotlin");   String[] sampleArray = sampleList.toArray(String[]::new);   assertThat(sampleArray).containsExactly("Java", "Kotlin"); 

3.4. Непредикатный метод​

В интерфейс Predicate добавлен статический метод not . Мы можем использовать его для отрицания существующего предиката, подобно методу отрицания :

 ListString> sampleList = Arrays.asList("Java", "\n \n", "Kotlin", " ");   List withoutBlanks = sampleList.stream()   .filter(Predicate.not(String::isBlank))   .collect(Collectors.toList());   assertThat(withoutBlanks).containsExactly("Java", "Kotlin"); 

Хотя not(isBlank) читается более естественно, чем isBlank .negate() , большим преимуществом является то, что мы также можем использовать not со ссылками на методы, например not(String:isBlank) .

3.5. Синтаксис локальной переменной для Lambda​

В Java 11 была добавлена поддержка использования синтаксиса локальных переменных ( ключевое слово var ) в параметрах лямбда.

Мы можем использовать эту функцию для применения модификаторов к нашим локальным переменным, например, для определения аннотации типа:

 ListString> sampleList = Arrays.asList("Java", "Kotlin");   String resultString = sampleList.stream()   .map((@Nonnull var x) -> x.toUpperCase())   .collect(Collectors.joining(", "));   assertThat(resultString).isEqualTo("JAVA, KOTLIN"); 

3.6. HTTP-клиент​

Новый HTTP-клиент из пакета java.net.http был представлен в Java 9. Теперь он стал стандартной функцией в Java 11.

Новый HTTP API повышает общую производительность и обеспечивает поддержку как HTTP/1.1, так и HTTP/2:

 HttpClient httpClient = HttpClient.newBuilder()   .version(HttpClient.Version.HTTP_2)   .connectTimeout(Duration.ofSeconds(20))   .build();   HttpRequest httpRequest = HttpRequest.newBuilder()   .GET()   .uri(URI.create("http://localhost:" + port))   .build();   HttpResponse httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());   assertThat(httpResponse.body()).isEqualTo("Hello from the server!"); 

3.7. Контроль доступа на основе гнезда​

Java 11 вводит понятие соплеменников и связанных с ними правил доступа в JVM.

Вложение классов в Java подразумевает как внешний/основной класс, так и все его вложенные классы:

 assertThat(MainClass.class.isNestmateOf(MainClass.NestedClass.class)).isTrue(); 

Вложенные классы связаны с атрибутом NestMembers , а внешний класс связан с атрибутом NestHost :

 assertThat(MainClass.NestedClass.class.getNestHost()).isEqualTo(MainClass.class); 

Правила доступа JVM разрешают доступ к закрытым членам между соседями; однако в предыдущих версиях Java API отражения запрещал такой же доступ.

Java 11 устраняет эту проблему и предоставляет средства для запроса новых атрибутов файла класса с использованием API отражения:

 SetString> nestedMembers = Arrays.stream(MainClass.NestedClass.class.getNestMembers())   .map(Class::getName)   .collect(Collectors.toSet());   assertThat(nestedMembers).contains(MainClass.class.getName(), MainClass.NestedClass.class.getName()); 

3.8. Запуск Java-файлов​

Основное изменение в этой версии заключается в том, что нам больше не нужно явно компилировать исходные файлы Java с помощью javac :

 $ javac HelloWorld.java $ java HelloWorld  Hello Java 8! 

Вместо этого мы можем напрямую запустить файл с помощью команды java :

 $ java HelloWorld.java Hello Java 11! 

4. Повышение производительности​

Теперь давайте взглянем на пару новых функций, основной целью которых является повышение производительности.

4.1. Динамические константы файла класса​

Формат файла классов Java расширен для поддержки новой формы пула констант с именем CONSTANT_Dynamic .

Загрузка нового пула констант делегирует создание методу начальной загрузки, точно так же, как связывание сайта вызова invokedynamic делегирует связь с методом начальной загрузки.

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

4.2. Улучшенная внутренняя структура Aarch64​

Java 11 оптимизирует существующие встроенные функции строк и массивов на процессорах ARM64 или AArch64. Кроме того, реализованы новые встроенные функции для методов sin, cos и log java.lang.Math .

Мы используем встроенную функцию, как и любую другую; однако встроенная функция обрабатывается компилятором особым образом. Он использует код сборки для конкретной архитектуры ЦП для повышения производительности.

4.3. Сборщик мусора без операций​

Новый сборщик мусора под названием Epsilon доступен для использования в Java 11 в качестве экспериментальной функции.

Он называется No-Op (без операций), потому что он выделяет память, но фактически не собирает мусор. Таким образом, Epsilon применим для моделирования ошибок нехватки памяти.

Очевидно, что Epsilon не подходит для типичного производственного Java-приложения; однако есть несколько конкретных случаев использования, в которых это может быть полезно:

  • Тестирование производительности
  • Тестирование нагрузки на память
  • Тестирование интерфейса ВМ и
  • Чрезвычайно кратковременные работы

Чтобы включить его, используйте флаг -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC .

4.4. Бортовой регистратор​

Java Flight Recorder (JFR) теперь является открытым исходным кодом в Open JDK , тогда как раньше он был коммерческим продуктом в Oracle JDK. JFR — это инструмент профилирования, который мы можем использовать для сбора данных диагностики и профилирования из работающего приложения Java.

Чтобы начать 120-секундную запись JFR, мы можем использовать следующий параметр:

 -XX:StartFlightRecording=duration=120s,settings=profile,filename=java-demo-app.jfr 

Мы можем использовать JFR в производственной среде, так как его накладные расходы на производительность обычно не превышают 1%. По истечении времени мы можем получить доступ к записанным данным, сохраненным в файле JFR; однако для анализа и визуализации данных нам необходимо использовать другой инструмент под названием JDK Mission Control (JMC).

5. Удаленные и устаревшие модули​

По мере развития Java мы больше не можем использовать какие-либо из удаленных функций и должны прекратить использование любых устаревших функций. Давайте кратко рассмотрим наиболее заметные из них.

5.1. Java EE и CORBA​

Отдельные версии технологий Java EE доступны на сторонних сайтах; поэтому для Java SE нет необходимости их включать.

В Java 9 уже объявлены устаревшими некоторые модули Java EE и CORBA. В выпуске 11 теперь полностью удалено:

  • API Java для веб-служб на основе XML (java.xml.ws )
  • Архитектура Java для привязки XML (java.xml.bind )
  • Платформа активации JavaBeans (java.activation )
  • Общие аннотации (java.xml.ws.annotation )
  • Общая архитектура брокера объектных запросов (java.corba)
  • API JavaTransaction (java.transaction )

5.2. JMC и JavaFX​

JDK Mission Control (JMC) больше не входит в состав JDK. Автономная версия JMC теперь доступна для отдельной загрузки.

То же самое верно и для модулей JavaFX ; JavaFX будет доступен в виде отдельного набора модулей вне JDK.

5.3. Устаревшие модули​

Кроме того, в Java 11 устарели следующие модули:

  • Движок Nashorn JavaScript, включая инструмент JJS
  • Схема сжатия Pack200 для файлов JAR

6. Прочие изменения​

Java 11 представила еще несколько изменений, о которых важно упомянуть:

  • Новые реализации шифров ChaCha20 и ChaCha20-Poly1305 заменяют небезопасный потоковый шифр RC4.
  • Поддержка соглашения о криптографическом ключе с Curve25519 и Curve448 заменяет существующую схему ECDH.
  • Обновление Transport Layer Security (TLS) до версии 1.3 обеспечивает повышение безопасности и производительности.
  • Представлен сборщик мусора с малой задержкой, ZGC, в качестве экспериментальной функции с коротким временем паузы.
  • Поддержка Unicode 10 приносит больше символов, символов и смайликов.

7. Заключение​

В этой статье мы рассмотрели некоторые новые функции Java 11.

Мы рассмотрели различия между Oracle и Open JDK. Мы также рассмотрели изменения API, а также другие полезные функции разработки, улучшения производительности и удаленные или устаревшие модули.

Как всегда, исходный код доступен на GitHub .

  • 1. Обзор
  • 2. Oracle против Open JDK
  • 3. Функции разработчика
    • 3.1. Новые строковые методы
    • 3.2. Новые файловые методы
    • 3.3. Коллекция в массив
    • 3.4. Непредикатный метод
    • 3.5. Синтаксис локальной переменной для Lambda
    • 3.6. HTTP-клиент
    • 3.7. Контроль доступа на основе гнезда
    • 3.8. Запуск Java-файлов
    • 4.1. Динамические константы файла класса
    • 4.2. Улучшенная внутренняя структура Aarch64
    • 4.3. Сборщик мусора без операций
    • 4.4. Бортовой регистратор
    • 5.1. Java EE и CORBA
    • 5.2. JMC и JavaFX
    • 5.3. Устаревшие модули

    Java 17: что нового по сравнению с Java 11

    Версия Java 17 была выпущена не так уж давно. Отличие этого релиза в том, что это — новая TLS-версия (Long Term Support, с долговременной поддержкой) после Java 11.

    В этой статье рассмотрим новые практические функции, которые были введены между 11-ой и 17-ой версиями.

    1. Switch -выражения.
    2. Текстовые блоки.
    3. Сопоставление с образцом (Pattern Matching) для instanceof .
    4. Полезные NullPointerException .
    5. Записи (Records).
    6. Запечатанные (sealed) классы.
    7. Сопоставление с образцом для switch .

    Switch-выражения

    Switch -выражения — это оператор switch с улучшенным синтаксисом и функциональностью. Как они работают?

    Выведем информацию о том, является ли данный день будним или выходным. При использовании операторов switch это выглядит так:

    DayOfWeek dayOfWeek = // назначение значений
    switch (dayOfWeek) case SUNDAY:
    case SATURDAY:
    System.out.println("Weekend");
    break;
    case FRIDAY:
    case THURSDAY:
    case WEDNESDAY:
    case TUESDAY:
    case MONDAY:
    System.out.println("Weekday");
    break;
    default:
    System.out.println("Unknown Day!");
    >

    С помощью новых switch -выражений этот код можно переписать так:

    System.out.println(switch (day) case SUNDAY, SATURDAY -> "Weekend"; 
    case FRIDAY, THURSDAY, WEDNESDAY, TUESDAY, MONDAY -> "Weekday";
    >);

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

    Во-вторых, больше не нужно использовать ключевое слово break , чтобы остановить выполнение. При использовании switch -выражений выполняется только правая часть соответствующего случая, если применяется синтаксис со стрелкой ( -> ).

    В-третьих, поскольку операторы switch стали switch -выражениями, а выражения вычисляют значение, то теперь они могут возвращать значение.

    В-четвертых, выражения switch являются исчерпывающими. Если вы забудете указать случай в выражении switch , то получите ошибку во время компиляции. Если вы охватываете все случаи, вам не нужно иметь случай “по умолчанию”.

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

    System.out.println(switch (day) case SUNDAY, SATURDAY -> "Weekend"; 
    case FRIDAY, THURSDAY, WEDNESDAY, TUESDAY, MONDAY -> // какая-то логика
    yield "Weekday";
    >
    >);

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

    Текстовые блоки

    Текстовые блоки — это просто многострочные строковые литералы.

    Чтобы поместить в код такой JSON:

     "name":"fatih", 
    "surname":"iver",
    "birthYear":1996
    >

    Нужно отформатировать его таким образом:

    String json = " " \"name\":\"fatih\",\n" + 
    " \"surname\":\"iver\",\n" +
    " \"birthYear\":1996\n" +
    ">";

    С помощью текстовых блоков можно просто написать следующее:

    String json = """ 
    "name":"fatih",
    "surname":"iver",
    "birthYear":1996
    >
    """;

    С текстовыми блоками больше не нужно экранировать кавычки или объединять несколько линий, чтобы сформировать одну строку.

    Особенно это облегчает жизнь, если вы храните HTML, JSON, SQL и XML в исходном коде.

    Новые текстовые блоки делают код более красивым и простым для чтения.

    Сопоставление с образцом (Pattern Matching) для instanceof

    instanceof позволяет проверить, принадлежит ли объект к нужному типу. Если это так, мы приводим этот объект к желаемому типу, чтобы вызвать метод, доступный только для этого типа. Пример:

    Object o = "Hello, World!";if (o instanceof String) String s = (String) o; 
    System.out.println(s.length());
    >

    При сопоставлении с образцом не нужно явное приведение типов:

    Object o = "Hello, World!";if (o instanceof String s) System.out.println(s.length());
    >

    Вы даже можете использовать переменную s , как это показано ниже, если выражение instanceof принимает значение true :

    Object o = "Hello, World!";if (o instanceof String s && !s.isBlank()) System.out.println(s.toLowerCase());
    >

    Полезные NullPointerException

    При выполнении следующего кода:

    Map map = new HashMap<>();
    System.out.println(map.get("key").toLowerCase());
    Exception in thread "main" java.lang.NullPointerException 
    at Main.example(Main.java:14)
    at Main.main(Main.java:10)

    Фрагмент лишь сообщает, в какой строке произошло исключение. При этом ничего не сказано о том, приняла ли карта значение null или же в ней не оказалось нужного ключа.

    С новым улучшением мы получаем:

    Exception in thread "main" java.lang.NullPointerException: 
    Cannot invoke "String.toLowerCase()" because the return value of "java.util.Map.get(Object)" is null
    at helpful_null_pointer_exception.Main.example(Main.java:15)
    at helpful_null_pointer_exception.Main.main(Main.java:9)

    Сообщение говорит, где и почему произошло NPE.

    Записи

    Чтобы определить неизменяемый класс, можно действовать так:

    public class Person  
    private final String name;
    private final String surname;
    private final Integer age;

    public Person(String name, String surname, Integer age) this.name = name;
    this.surname = surname;
    this.age = age;
    >

    public String getName() return name;
    >

    public String getSurname() return surname;
    >

    public Integer getAge() return age;
    >

    @Override
    public boolean equals(Object o) if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Person person = (Person) o;

    if (!Objects.equals(name, person.name)) return false;
    if (!Objects.equals(surname, person.surname)) return false;
    return Objects.equals(age, person.age);
    >

    @Override
    public int hashCode() int result = name != null ? name.hashCode() : 0;
    result = 31 * result + (surname != null ? surname.hashCode() : 0);
    result = 31 * result + (age != null ? age.hashCode() : 0);
    return result;
    >

    @Override
    public String toString() return "Person "name='" + name + '\'' +
    ", surname='" + surname + '\'' +
    ", age=" + age +
    '>';
    >
    >

    Получается довольно много строк. Упростим синтаксис, воспользовавшись библиотекой Lombok:

    @Value
    public class Person String name;
    String surname;
    Integer age;
    >

    Не слишком расписывая код и не завися от стороннего решения, с помощью записей можно написать этот класс следующим образом:

    public record Person(String name, String surname, Integer age) 
    >

    Тип record создает неизменяемый класс с приватными финализированными полями, геттерами, методом toString , а также методами equals и hashCode .

    Таким образом, есть три разных способа добиться одного и того же. В первом подходе мы были слишком многословны, а во втором — зависели от стороннего решения. При третьем код намного короче, и мы не зависим от стороннего решения.

    Запечатанные классы

    При помощи этой функции класс может указывать, какие классы могут его расширять. Например:

    public abstract sealed class Developer permits BackendDeveloper, FrontendDeveloper >

    Следующий код не будет компилироваться с приведенным выше определением:

    public final class ProductManager extends Developer >

    Этот код не компилируется, потому что класс Developer разрешает расширять себя только классам BackendDeveloper и FrontendDeveloper . Однако его пытается расширить класс ProductManager . И возникает ошибка компиляции.

    Такие классы, вероятно, больше всего пригодятся разработчикам библиотек и фреймворков.

    Сопоставление с образцом для switch

    Для этого объяснения используется пример с сайта OpenJDK.

    static String formatter(Object o) String formatted = "unknown"; 
    if (o instanceof Integer i) formatted = String.format("int %d", i);
    > else if (o instanceof Long l) formatted = String.format("long %d", l);
    > else if (o instanceof Double d) formatted = String.format("double %f", d);
    > else if (o instanceof String s) formatted = String.format("String %s", s);
    >
    return formatted;
    >

    При сопоставлении с образцом switch :

    static String formatterPatternSwitch(Object o) return switch (o) case Integer i -> String.format("int %d", i); 
    case Long l -> String.format("long %d", l);
    case Double d -> String.format("double %f", d);
    case String s -> String.format("String %s", s);
    default -> o.toString();
    >;
    >

    Мы сопоставили объект на основе его типа и не выполняли никакого явного приведения.

    Эту функцию можно объединить с запечатанными классами. Так получится писать точные и довольно емкие switch -выражения.

    Бонус

    До Java 16 мы собирали потоки в виде списка, как показано ниже:

    List digits = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    List evenDigits = digits.stream()
    .filter(digit -> digit % 2 == 0)
    .collect(Collectors.toList());

    Теперь для той же цели можно вызвать новый метод ToList для потоков:

    List digits = List.of(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    List evenDigits = digits.stream()
    .filter(digit -> digit % 2 == 0)
    .toList();
    • 3 способа мониторинга изменений лог-файлов в Java
    • Как правильно учиться Java-программированию: история одного тьютора
    • String, StringBuilder и StringBuffer: понимаете ли вы разницу?

    Читайте нас в Telegram, VK и Дзен

    Новые возможности в Java версий 12 — 17

    Через три года после Java 11 — на данный момент последней версии с долгосрочной поддержкой (LTS), Java 17 LTS будет выпущена в сентябре 2021 года. Пришло время сделать краткий обзор новых функций, которыми разработчики могут пользоваться после обновления с 11 до 17. Обратите внимание, что было внесено гораздо больше улучшений — в этой статье основное внимание уделяется тем функциям, которые могут напрямую использоваться большинством разработчиков:

    • Switch выражения (JEP 361)
    • Текстовые блоки (JEP 378)
    • Инструмент для упаковки (JEP 392)
    • Сопоставление с образцом для instanceof (JEP 394)
    • Записи (JEP 395)
    • Запечатанные классы (JEP 409)

    Switch выражения

    Теперь switch может возвращать значение, как и выражение:

    // assign the group of the given planet to a variable String group = switch (planet) < case MERCURY, VENUS, EARTH, MARS ->"inner planet"; case JUPITER, SATURN, URANUS, NEPTUNE -> "outer planet"; >;

    Если правая часть одного case требует большего количества кода, его можно записать внутри блока, а значение возвращается с помощью yield :

    // print the group of the given planet, and some more info, // and assign the group of the given planet to a variable String group = switch (planet) < case EARTH, MARS -> < System.out.println("inner planet"); System.out.println("made up mostly of rock"); yield "inner"; >case JUPITER, SATURN -> < System.out.println("outer planet"); System.out.println("ball of gas"); yield "outer"; >>;

    Однако switch с использованием новых меток со стрелками не требует возврата значения, как и void выражение:

    // print the group of the given planet // without returning anything switch (planet) < case EARTH, MARS ->System.out.println("inner planet"); case JUPITER, SATURN -> System.out.println("outer planet"); >

    По сравнению с традиционным переключателем, новое Switch выражение

    • Использует «->» вместо «:»
    • Позволяет использовать несколько констант для каждого case
    • Не имеет сквозной семантики (т. е. не требует break)
    • Делает переменные, определенные внутри ветви case, локальными для этой ветви

    Более того, компилятор гарантирует полноту переключения в том смысле, что выполняется ровно один из случаев, что означает, что либо

    • Все возможные значения перечислены как case (как в приведенном выше перечислении, состоящем из восьми планет), или
    • Должна быть предоставлена ​​ветка «default».

    Текстовые блоки

    Текстовые блоки позволяют писать многострочные строки, содержащие двойные кавычки, без использования \n или \» escape-последовательностей:

    String block = """ Multi-line text with indentation and "double quotes"! """;

    Текстовый блок открывается тремя двойными кавычками, «»» за которыми следует разрыв строки, и закрывается тремя двойными кавычками.

    Компилятор Java использует интеллектуальный алгоритм для удаления начального пробела из результирующей строки, чтобы:

    • отступ, необходимый только для лучшей читаемости исходного кода Java, был удален.
    • отступ, относящийся к самой строке, остался нетронутым

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

    Multi-line.text .with.indentation ..and."double.quotes"!

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

    String block = """ Multi-line text with indentation and "double quotes"! """;

    Результат представлен в следующей строке:

    ..Multi-line.text . with.indentation . and."double.quotes"!

    Кроме того, из каждой строки удаляется конечный пробел, чего можно избежать, используя новую escape-последовательность \s .

    Разрывы строк внутри текстовых блоков можно экранировать:

    String block = """ No \ line \ breaks \ at \ all \ please\ """;

    Результатом является следующая строка без разрывов строк:

    No.line.breaks.at.all.please

    В качестве альтернативы последний разрыв строки также можно удалить, добавив закрывающий разделитель непосредственно в конец строки:

    String block = """ No final line break at the end of this string, please""";

    Вставка переменных в текстовый блок может выполняться как обычно с помощью статического метода String::format или с помощью нового метода экземпляра String::formatted , который немного короче для записи:

    String block = """ %s marks the spot. """.formatted("X");

    Инструмент для упаковки

    Предположим, у вас есть JAR-файл demo.jar в каталоге lib вместе с дополнительными JAR-файлами зависимостей. Следующая команда:

    jpackage --name demo --input lib --main-jar demo.jar --main-class demo.Main

    упаковывает это демонстрационное приложение в собственный формат, соответствующий вашей текущей платформе:

    • Linux: deb или rpm
    • Windows: msi или exe
    • macOS: pkg или dmg

    Результирующий пакет также содержит те части JDK, которые требуются для запуска приложения, а также собственный модуль запуска. Это означает, что пользователи могут устанавливать, запускать и удалять приложение стандартным способом, зависящим от платформы, без предварительной установки Java.

    Кросс-компиляция не поддерживается: если вам нужен пакет для пользователей Windows, вы должны создать его с помощью jpackage на машине Windows.

    Создание пакета можно настроить с помощью многих других параметров, которые задокументированы на странице руководства jpackage.

    Сопоставление с образцом для Instanceof

    Сопоставление с образцом (Pattern matching) для instanceof позволяет исключить шаблонный код для выполнения приведений после сравнения типов:

    Object o = "string disguised as object"; if (o instanceof String s)

    В приведенном выше примере область действия новой переменной s интуитивно ограничена if веткой. Чтобы быть точным, переменная находится в области видимости, в которой гарантировано совпадение шаблона, что также делает следующий код допустимым:

    if (o instanceof String s && !s.isEmpty())

    А также наоборот:

    if (!(o instanceof String s)) < throw new RuntimeException("expecting string"); >// s is in scope here! System.out.println(s.toUpperCase());

    Записи

    Записи (Records) сокращают шаблонный код для классов, которые являются простыми носителями данных:

    record Point(int x, int y)

    Эта строка кода в результате приводит к созданию класса записи, в котором автоматически определены:

    • поля для x и y (как private и final)
    • канонический конструктор для всех полей
    • геттеры для всех полей
    • equals , hashCode и toString (с учетом всех полей)
    // canonical constructor Point p = new Point(1, 2); // getters - without "get" prefix p.x(); p.y(); // equals / hashCode / toString p.equals(new Point(1, 2)); // true p.hashCode(); // depends on values of x and y p.toString(); // Point[x=1, y=2]

    Некоторые из наиболее важных ограничений классов записей заключаются в том, что они:

    • неизменяемы (поскольку их поля являются private и final)
    • неявно final
    • невозможно определить дополнительные поля экземпляра
    • всегда наследует от Record класса
    • определить дополнительные методы
    • реализовать интерфейсы
    • кастомизировать канонический конструктор и аксессоры
    record Point(int x, int y) < // explicit canonical constructor Point < // custom validations if (x < 0 || y < 0) throw new IllegalArgumentException("no negative points allowed"); // custom adjustments (usually counter-intuitive) x += 1000; y += 1000; // assignment to fields happens automatically at the end >// explicit accessor public int x() < // custom code here. return this.x; >>

    Кроме того, внутри метода можно определить локальную запись:

    public void withLocalRecord() < record Point(int x, int y) < >; Point p = new Point(1, 2); >

    Sealed классы

    Sealed (запечатанный) класс явно перечисляет допустимые прямые подклассы. Другие классы не могут наследовать от этого класса:

    public sealed class Parent permits ChildA, ChildB, ChildC

    Точно так же запечатанный интерфейс явно перечисляет разрешенные прямые субинтерфейсы и реализующие классы:

    sealed interface Parent permits ChildA, ChildB, ChildC

    Классы или интерфейсы в permits списке должны находиться в одном пакете (или в том же модуле, если родитель находится в названном модуле).

    permits список может быть опущена, если подклассы (или интерфейсы) расположены в том же файле:

    public sealed class Parent < final class Child1 extends Parent <>final class Child2 extends Parent <> final class Child3 extends Parent <> >

    Каждый подкласс или интерфейс в permits списке должен использовать только один из следующих модификаторов:

    • final (запрещает дальнейшее наследование; только для подклассов, поскольку интерфейсы не могут быть final)
    • sealed (допускает дальнейшее, ограниченное наследование)
    • non-sealed (снова разрешает неограниченное наследование)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *