Перейти к основному содержимому

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

· 11 мин. чтения

Задача: Наибольшая подстрока без повторений

Для заданной строки s, найдите длину наибольшей подстроки без повторяющихся символов. Подстрока — это непрерывная непустая последовательность символов внутри строки...

ANDROMEDA 42

1. Обзор

В этом руководстве мы поговорим о новостях, связанных с новой версией экосистемы Java, Java SE 17 , включая новые функции и изменения в процессе ее выпуска, поддержку LTS и лицензии.

2. Список JEP

Сначала поговорим о том, что может повлиять на рабочие будни в жизни Java-разработчика.

2.1. Восстановить всегда строгую семантику с плавающей запятой ( JEP 306 )

Этот JEP предназначен в основном для научных приложений и делает операции с плавающей запятой последовательно строгими. Операции с плавающей запятой по умолчанию — strict или strictfp , обе из которых гарантируют одинаковые результаты вычислений с плавающей запятой на каждой платформе.

До Java 1.2 поведение strictfp также было поведением по умолчанию. Однако из-за проблем с оборудованием архитекторы изменились, и для повторного включения такого поведения потребовалось ключевое слово strictfp . Таким образом, нет необходимости использовать это ключевое слово больше.

2.2. Усовершенствованные генераторы псевдослучайных чисел ( JEP 356 )

JEP 356 также относится к более особым случаям использования и предоставляет новые интерфейсы и реализации для генераторов псевдослучайных чисел (PRNG).

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

public IntStream getPseudoInts(String algorithm, int streamSize) {
// returns an IntStream with size @streamSize of random numbers generated using the @algorithm
// where the lower bound is 0 and the upper is 100 (exclusive)
return RandomGeneratorFactory.of(algorithm)
.create()
.ints(streamSize, 0,100);
}

Устаревшие случайные классы, такие как java.util.Random , SplittableRandom и SecureRandom , теперь расширяют новый интерфейс RandomGenerator .

2.3. Новый конвейер рендеринга macOS ( JEP 382 )

Этот JEP реализует внутренний конвейер рендеринга Java 2D для macOS, поскольку Apple объявила устаревшим API OpenGL (в macOS 10.14), используемый внутри графического интерфейса Swing. В новой реализации используется Apple Metal API, и, кроме внутреннего движка, в существующие API не было внесено никаких изменений.

2.4. Порт macOS/AArch64 ( JEP 391 )

Apple объявила о долгосрочном плане по переводу своей линейки компьютеров с X64 на AArch64. Этот JEP переносит JDK для работы на AArch64 на платформах macOS.

2.5. Устаревший API апплета для удаления ( JEP 398 )

Хотя это может быть печально для многих Java-разработчиков, которые начали свою карьеру с помощью Applet API, многие веб-браузеры уже отказались от поддержки подключаемых модулей Java. Поскольку API стал неактуальным, эта версия пометила его для удаления, хотя начиная с версии 9 он был помечен как устаревший.

2.6. Строгая инкапсуляция внутренних компонентов JDK ( JEP 403 )

JEP 403 представляет собой еще один шаг к строгой инкапсуляции внутренних компонентов JDK, поскольку он удаляет флаг –illegal-access . Платформа проигнорирует флаг, и если флаг присутствует, консоль выдаст сообщение о прекращении действия флага.

Эта функция предотвратит доступ пользователей JDK к внутренним API, за исключением критически важных, таких как sun.misc.Unsafe .

2.7. Сопоставление шаблонов для коммутатора (предварительная версия) ( JEP 406 )

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

Давайте посмотрим на два примера новых возможностей:

static record Human (String name, int age, String profession) {}

public String checkObject(Object obj) {
return switch (obj) {
case Human h -> "Name: %s, age: %s and profession: %s".formatted(h.name(), h.age(), h.profession());
case Circle c -> "This is a circle";
case Shape s -> "It is just a shape";
case null -> "It is null";
default -> "It is an object";
};
}

public String checkShape(Shape shape) {
return switch (shape) {
case Triangle t && (t.getNumberOfSides() != 3) -> "This is a weird triangle";
case Circle c && (c.getNumberOfSides() != 0) -> "This is a weird circle";
default -> "Just a normal shape";
};
}

2.8. Удалить активацию RMI ( JEP 407 )

Помеченный для удаления в версии 15, этот JEP удалил API-интерфейс активации RMI с платформы в версии 17.

2.9. Закрытые классы ( JEP 409 )

Запечатанные классы являются частью Project Amber , и этот JEP официально вводит в язык новую функцию, хотя она была доступна в режиме предварительного просмотра в версиях JDK 15 и 16 .

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

Давайте посмотрим на это в действии:

int getNumberOfSides(Shape shape) {
return switch (shape) {
case WeirdTriangle t -> t.getNumberOfSides();
case Circle c -> c.getNumberOfSides();
case Triangle t -> t.getNumberOfSides();
case Rectangle r -> r.getNumberOfSides();
case Square s -> s.getNumberOfSides();
};
}

2.10. Удалите экспериментальный компилятор AOT и JIT ( JEP 410 )

Компиляция Ahead-Of-Time (AOT) ( JEP 295 ) и компилятор Just-In-Time (JIT) из GraalVM ( JEP-317 ), представленные в JDK 9 и JDK 10 соответственно в качестве экспериментальных функций, были функциями с высокой стоимость обслуживания.

С другой стороны, у них не было значительного усыновления. Из-за этого этот JEP удалил их с платформы, но разработчики по-прежнему могут использовать их с помощью GraalVM .

2.11. Устаревший диспетчер безопасности для удаления ( JEP 411 )

Менеджер безопасности, предназначенный для защиты Java-кода на стороне клиента, — еще одна функция, отмеченная для удаления из-за того, что она больше не актуальна.

2.12. Внешние функции и API памяти (инкубатор) ( JEP 412 )

Внешние функции и API памяти позволяют разработчикам Java получать доступ к коду из-за пределов JVM и управлять памятью из кучи. Цель состоит в том, чтобы заменить JNI API и улучшить безопасность и производительность по сравнению со старым.

Этот API -- еще одна функция , разработанная Project Panama , и она была развита и прекращена в JEP 393 , 389 , 383 и 370 .

С помощью этой функции мы можем сделать вызов библиотеки C из класса Java:

private static final SymbolLookup libLookup;

static {
// loads a particular C library
var path = JEP412.class.getResource("/print_name.so").getPath();
System.load(path);
libLookup = SymbolLookup.loaderLookup();
}

Во-первых, необходимо загрузить целевую библиотеку, которую мы хотим вызывать через API.

Далее нам нужно указать сигнатуру целевого метода и, наконец, вызвать его:

public String getPrintNameFormat(String name) {

var printMethod = libLookup.lookup("printName");

if (printMethod.isPresent()) {
var methodReference = CLinker.getInstance()
.downcallHandle(
printMethod.get(),
MethodType.methodType(MemoryAddress.class, MemoryAddress.class),
FunctionDescriptor.of(CLinker.C_POINTER, CLinker.C_POINTER)
);

try {
var nativeString = CLinker.toCString(name, newImplicitScope());
var invokeReturn = methodReference.invoke(nativeString.address());
var memoryAddress = (MemoryAddress) invokeReturn;
return CLinker.toJavaString(memoryAddress);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
throw new RuntimeException("printName function not found.");
}

2.13. Vector API (Второй инкубатор) ( JEP 414 )

Vector API имеет дело с типом операций SIMD (Single Instruction, Multiple Data), что означает параллельное выполнение различных наборов инструкций. Он использует специализированное аппаратное обеспечение ЦП, которое поддерживает векторные инструкции и позволяет выполнять такие инструкции как конвейеры.

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

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

Давайте воспользуемся API, чтобы проиллюстрировать простой пример умножения векторов:

public void newVectorComputation(float[] a, float[] b, float[] c) {
for (var i = 0; i < a.length; i += SPECIES.length()) {
var m = SPECIES.indexInRange(i, a.length);
var va = FloatVector.fromArray(SPECIES, a, i, m);
var vb = FloatVector.fromArray(SPECIES, b, i, m);
var vc = va.mul(vb);
vc.intoArray(c, i, m);
}
}

public void commonVectorComputation(float[] a, float[] b, float[] c) {
for (var i = 0; i < a.length; i ++) {
c[i] = a[i] * b[i];
}
}

2.14. Контекстно-зависимые фильтры десериализации ( JEP 415 )

JEP 290 , впервые представленный в JDK 9, позволил нам проверять входящие сериализованные данные из ненадежных источников, что является распространенным источником многих проблем с безопасностью. Эта проверка происходит на уровне JVM, что обеспечивает большую безопасность и надежность.

С помощью JEP 415 приложения могут настраивать зависящие от контекста и динамически выбираемые фильтры десериализации, определенные на уровне JVM. Каждая операция десериализации будет вызывать такие фильтры.

3. Определение LTS

Изменения остаются не только в коде — меняются и процессы.

Общеизвестно, что выпуски платформы Java были длинными и неточными. Несмотря на то, что он был разработан с трехлетним интервалом между выпусками, он часто становился четырехлетним процессом.

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

В результате с момента выпуска Java 10 (выпущенного 20 марта 2018 г.) была принята новая шестимесячная модель выпуска функций.

3.1. Шестимесячная модель выпуска функций

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

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

3.2. LTS-модель

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

По этой причине были созданы версии с долгосрочной поддержкой (LTS), предлагающие пользователям расширенную поддержку. Таким образом, такие версии, естественно, становятся более стабильными и безопасными благодаря исправлениям ошибок, улучшениям производительности и исправлениям безопасности. В случае с Oracle эта поддержка обычно длится восемь лет.

С момента внесения изменений в модель выпуска версиями LTS были Java SE 11 (выпущена в сентябре 2018 г.) и Java SE 17 (выпущена в сентябре 2021 г.). Тем не менее, версия 17 привнесла в модель что-то новое. Короче говоря, интервал между версиями LTS теперь составляет два года вместо трех, что делает Java 21 (запланированная на сентябрь 2023 года), вероятно, следующей LTS.

Еще один момент, о котором стоит упомянуть, заключается в том, что эта модель выпуска не нова. Она была беззастенчиво скопирована и адаптирована из других проектов, таких как Mozilla Firefox, Ubuntu и других, где модель зарекомендовала себя.

4. Новый процесс выпуска

Мы основывали эту статью на JEP 3 , учитывая, что в ней описаны все изменения в процессе. Пожалуйста, проверьте его для получения дополнительной информации. Мы постараемся кратко изложить его здесь.

Учитывая новую модель, описанную выше, в сочетании с непрерывным развитием платформы и новым шестимесячным графиком выпуска (обычно июнь и декабрь), Java будет развиваться быстрее. Команда разработчиков JDK инициирует цикл выпуска для следующего выпуска функции в соответствии с процессом, описанным далее.

Процесс начинается с разветвления основной линии . Затем разработка продолжается в репозитории стабилизации JDK/JDK$N (например, JDK17 ). Там разработка продолжается с упором на стабилизацию релиза.

Прежде чем мы углубимся в процесс, давайте уточним некоторую терминологию:

  • Баги . В данном контексте баги означают тикеты или задачи:

  • Текущая : это либо фактические ошибки, связанные с текущей версией (новая будет выпущена), либо корректировки новых функций, уже включенных в эту версию (новые JEP).

  • Целевой : относится к более старым версиям и планируется исправить или решить в этой новой версии.

  • Приоритеты : в диапазоне от P1 до P5, где P1 является наиболее важным, с постепенным уменьшением важности до P5.

4.1. Новый формат

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

  • Репозиторий JDK/JDK$N работает как ветка релиза, и на этом этапе в репозиторий не попадают новые JEP новых JEP.
  • Далее разработки в этом репозитории будут стабилизированы и перенесены в основную ветку, где продолжаются другие разработки.
  • Этап 1 постепенного снижения (RDP 1): длится от четырех до пяти недель. Разработчики удаляют все текущие P4-P5 и целевые P1-P3 (в зависимости от отсрочки , исправления или улучшения ). Это означает, что ошибки тестирования/документации P5+ и целевые ошибки кода P3+ не являются обязательными.
  • Этап 2 постепенного снижения (RDP 2): длится от трех до четырех недель. Теперь они откладывают все текущие P3-P5 и целевые P1-P3 (в зависимости от отсрочки , исправления или улучшения ).
  • Наконец, команда публикует сборку-кандидат на выпуск и делает ее общедоступной. Эта фаза длится от двух до пяти недель, и рассматриваются только текущие исправления P1 (используя fix ).

По завершении всех этих циклов новый выпуск становится общедоступной версией (GA).

5. Что дальше?

Архитекторы JDK продолжают работать над многими проектами, направленными на модернизацию платформы. Цель состоит в том, чтобы обеспечить лучший опыт разработки и более надежные и производительные API.

В результате JDK 18 должен выйти через шесть месяцев, хотя эта версия вряд ли будет содержать существенные или разрушительные изменения. Мы можем следить за списком предлагаемых JEP, предназначенных для этой версии, на официальном портале проекта OpenJDK .

Еще одна важная новость, которая затрагивает текущую и будущие версии, — это новая бесплатная лицензия с условиями и положениями , применяемая к дистрибутиву Oracle JDK (или Hotspot). В большинстве случаев Oracle предлагает бесплатное распространение для производственной и других сред, но есть несколько исключений. Опять же, пожалуйста, перейдите по ссылке.

Как упоминалось ранее, новый процесс нацелен на то, чтобы следующей LTS-версией была версия 21, и планируется выпустить ее к сентябрю 2023 года.

6. Заключение

В этой статье мы рассмотрели новости о новой версии Java 17, рассмотрели ее последние разработки, новые возможности, определение поддержки и процесс цикла выпуска.

Как обычно, все примеры кода, использованные в этой статье, доступны на GitHub .