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

Что такое java 11

  • автор:

Причины перехода на Java 11 и более

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

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

Переход на Java 11

Переход на Java 11 можно выполнять поэтапно. Для работы с Java 11 вам не нужно использовать в коде специальные модули Java. Java 11 можно использовать для запуска кода, который был разработан и скомпилирован в JDK 8. Но при этом могут возникать некоторые проблемы, которые преимущественно связаны с устаревшими API, загрузчиками классов и отражениями.

Обобщенное описание отличий между Java 8 и 11

В этом разделе не перечисляются все изменения, внесенные в Java версии 9 [1], 10 [2], и 11 [3]. Выделены лишь те из них, которые заметно влияют на эффективность, диагностику и производительность.

Модули [4]

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

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

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

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

В приложении можно как и прежде использовать classpath. При этом вам не нужно переходить на использование модулей работы с Java 11.

Профилирование и диагностика

Летчик Java [5]

Java Flight Recorder собирает данные диагностики и профилирования из запущенного приложения Java. Java Flight Recorder практически не влияет на работу приложения Java. Собранные данные потом можно проанализировать с помощью Java Mission Control или других средств. В Java 8 Java Flight Recorder и Java Mission Control предоставлялись на коммерческой основе, а в Java 11 они включены как компоненты с открытым кодом.

Управление миссиями Java [6]

Java Mission Control (JMC) предоставляет графическое отображение данных, собранных Java Flight Recorder (JFR) и открытый код в Java 11. Помимо общих сведений о работающем приложении JMC позволяет пользователю детализировать данные. Java Flight Recorder и Java Mission Control можно использовать для диагностики проблем, возникающих во время выполнения, включая утечки памяти, затраты на сборку мусора, горячие методы, узкие места и блокирующие операции ввода-вывода.

Единое ведение журнала [7]

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

Профилирование кучи с низкими затратами [8]

В виртуальную машину Java добавлен новый API, который предназначен для выборки выделений памяти в куче Java. Эта выборка создает низкую нагрузку и ее можно не отключать. Хотя выделение кучи можно отслеживать с помощью Java Flight Recorder, используемый метод выборки работает только для выделений. Кроме того, эта реализация может упускать выделения памяти. При этом выборка кучи в Java 11 предоставляет сведения как об активных, так и о неработающих объектах.

Поставщики средств наблюдения за производительностью приложений уже применяют эту новую функцию, и инженерная группа Java оценивает возможность объединить ее со средствами мониторинга производительности Azure.

StackWalker [9]

Получение моментального снимка стека в текущем потоке будет очень полезным при ведении журналов. Основная проблема заключается в том, чтобы выбрать объем трассировки стека для записи в журнал, а также принять решение о записи трассировки стека. Например, вам нужно отслеживать трассировку стека только для определенного исключения в одном методе. Класс StackWalker (добавлен в Java 9) предоставляет моментальный снимок стека и несколько методов, которые позволяют программисту контролировать использование трассировки стека.

Сборка мусора [10]

В Java 11 доступны следующие сборщики мусора: последовательные, параллельные, Garbage-First и Epsilon. По умолчанию в Java 11 используется сборщик мусора G1GC (Garbage First Garbage Collector).

Остальные здесь упоминаются для полноты информации. Сборщик мусора ZGC (Z Garbage Collector) нацелен на параллельное выполнение с низкой задержкой — по возможности не более 10 мс. ZGC используется в Java 11 в качестве экспериментальной функции. Сборщик мусора Shenandoah рассчитан на краткую приостановку, которой он добивается за счет выполнения большего количества сборок мусора параллельно с запущенной программой Java. Shenandoah предоставляется в качестве экспериментальной функции в Java 12, но существуют реализации с обратной совместимостью с Java 11. Доступен также сборщик CMS (Concurrent Mark and Sweep), но, начиная с версии Java 9, он объявлен нерекомендуемым.

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

G1GC

По умолчанию в Java 11 используется сборщик мусора G1 (G1 Garbage Collector). Задача G1GC — найти баланс между задержкой и пропускной способностью. Сборщик мусора G1 пытается достичь высокой пропускной способности, с высокой вероятностью обеспечивая заданное значение приостановки. G1GC предназначен для предотвращения полных коллекций, но когда параллельные коллекции не могут освободить память достаточно быстро, будет выполнена резервная сборка мусора. При полной сборке мусора используется такое же количество параллельных рабочих потоков, что и при сборки молодого и смешанного мусора.

Сборщик мусора Parallel

Сборщик Parallel используется по умолчанию в Java 8. Сборщик мусора Parallel нацелен на обеспечение высокой пропускной способности при использовании нескольких потоков для ускорения сборки.

Epsilon [11]

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

Улучшения для контейнеров Docker [12]

До версии Java 10 в виртуальной машине Java не учитывались ограничения памяти и ЦП, заданные для контейнера. Например, в Java 8 виртуальная машина Java по умолчанию ограничивала размер кучи на уровне 1/4 от общего объема физической памяти базового узла. Начиная с Java 10, в виртуальной машине Java учитываются ограничения, заданные для групп управления контейнерами (cgroup), при установке ограничений памяти и ЦП (см. примечание ниже). Например, максимальный размер кучи по умолчанию составляет 1/4 от ограничения памяти для контейнера (500 МБ при использовании -m2G).

Также добавлены новые параметры виртуальной машины Java. Они позволяют пользователям контейнеров Docker контролировать объем системной памяти, который будет использоваться для кучи Java.

Эта возможность включена по умолчанию, но доступна только на платформах под управлением Linux.

Большая часть работы по поддержке cgroup направлена на обеспечение обратной совместимости в Java 8, начиная с версии jdk8u191. Мы не гарантируем, что последующие улучшения будут доступны в версии 8.

Jar-файлы с несколькими выпусками [13]

В Java 11 можно создать JAR-файл, который содержит несколько версий файлов классов, предназначенных для конкретных выпусков Java. Такие JAR-файлы позволяют разработчикам библиотек поддерживать несколько версий Java без необходимости предоставлять несколько версий JAR-файлов. Для потребителей этих библиотек такие JAR-файлы решают проблему подбора правильных JAR-файлов для каждой целевой версии среды выполнения.

Разные улучшения производительности

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

  • JEP 197: сегментированные кэши кода [14] — делит кэш кода на отдельные сегменты. Такая сегментация позволяет управлять объемом памяти, используемой виртуальной машиной Java, ускоряет сканирование скомпилированных методов, значительно снижает фрагментацию кэша кода и повышает производительность.
  • JEP 254: компактные строки [15] — изменяет внутреннее представление строки с двух байтов на char на один или два байта на char в зависимости от кодировки char. Так как большинство строк содержат символы кодировки ISO-8859-1/Latin-1, это изменение вдвое сокращает пространство, необходимое для хранения строк.
  • JEP 310: совместное использование приложений Class-Data [16] — Class-Data общий доступ уменьшает время запуска, позволяя архивным классам сопоставляться с памятью во время выполнения. а также расширяет возможность совместного использования данных класса, позволяя размещать классы приложений в архив Common Data Service. Если несколько виртуальных машин Java совместно используют один и тот же файл архива, потребление памяти и общее время отклика системы снижаются.
  • JEP 312: Thread-Local подтверждения [17] — позволяет выполнять обратный вызов в потоках без выполнения глобальной безопасной точки виртуальной машины, что помогает виртуальной машине достичь меньшей задержки за счет уменьшения числа глобальных безопасных точек.
  • Отложенное выделение потоков компилятора [18] — в многоуровневом режиме компиляции виртуальная машина запускает большое количество потоков компилятора. Этот режим используется по умолчанию в системах с большим количеством процессоров. Такие потоки создаются независимо от объема доступной памяти или количества запросов компиляции. Потоки потребляют память, даже когда бездействуют (что происходит почти все время), что приводит к неэффективному использованию ресурсов. Для решения этой проблемы реализация изменена так, чтобы при запуске открывался только один поток компилятора каждого типа. Запуск дополнительных потоков и завершение работы неиспользуемых потоков осуществляется динамически.

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

  • JEP 193: дескриптора переменных [19] — определяет стандартный способ вызова эквивалентов различных операций java.util.concurrent.atomic и sun.misc.Unsafe при полях объектов и элементах массива, стандартный набор операций ограждения для точного управления упорядочением памяти, а также стандартная операция обеспечения доступности и ограждения для обеспечения строгой доступности объекта.
  • JEP 269: удобные фабричные методы для коллекций [20] — определяет API библиотеки, чтобы упростить создание экземпляров коллекций и карт с небольшим количеством элементов. Эти статические фабричные методы в интерфейсах коллекции создают компактный и неизменяемый экземпляр коллекции. Такие экземпляры по своей сути являются более эффективными. API создают коллекции, которые хранятся в компактном виде и не имеют класс-оболочку.
  • JEP 285: Spin-Wait подсказки [21] — предоставляет API, который позволяет Java намекать системе времени выполнения, что она находится в цикле спина. Некоторые аппаратные платформы могут использовать информацию от программного обеспечения о том, что поток находится в состоянии активного ожидания.
  • JEP 321: HTTP-клиент (стандартная версия) [22]. Предоставляет новый API клиента HTTP, который реализует HTTP/2 и WebSocket и может заменить устаревший API HttpURLConnection.

Переход с Java 8 на Java 11

Для перехода с Java 8 на Java 11 не существует универсального решения. Переход нетривиального приложения с Java 8 на Java 11 может быть трудоемким процессом. К потенциальным проблемам относятся удаленные API, устаревшие пакеты, использование внутреннего API, изменения в загрузчиках классов, а также изменения в сборке мусора.

В целом, подходы заключаются в попытке запуска на Java 11 без перекомпиляции, или с начальной компиляцией с JDK 11. Если цель состоит в том, чтобы запустить приложение как можно быстрее, то зачастую лучшим подходом является попытка запустить приложение на Java 11. Для библиотеки целью будет публикация артефакта, который компилируется и тестируется с помощью JDK 11.

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

Этот документ касается средств для проверки кода. Здесь также рассматриваются проблемы, с которыми вы можете столкнуться, и рекомендации по их устранению. Вам также следует принять во внимание другие руководства, такие как Oracle JDK Migration Guide (Руководство по миграции Oracle JDK). В этом руководстве не обсуждается вопрос изменения существующего кода на модулярный.

Панель элементов

В Java 11 есть два инструмента, jdeprscan и jdeps, полезные при выявлении потенциальных проблем. Эти инструменты можно запустить в существующих классах или JAR-файлах. Вы можете оценить усилия для перехода, не нуждаясь в выполнении перекомпиляции.

jdeprscan ищет варианты использования нерекомендуемого или удаленного API. Использование нерекомендуемого API не является блокирующей проблемой, однако на него следует обратить внимание. У вас есть обновленный JAR-файл? Нужно ли заносить проблему в журнал, чтобы решить проблему использования нерекомендуемого API? Использование удаленного API — это блокирующая проблема, которую необходимо решить до попытки запуска на Java 11.

jdeps, представляющий собой анализатор зависимости от класса Java. При использовании с опцией —jdk-internals , jdeps сообщает, от которого внутреннего API зависит каждый класс. Вы можете продолжать использовать внутренний API на Java 11, однако приоритетом должна стать замена потребления. На вики-странице OpenJDK Java Dependency Analysis Tool (Средство анализа зависимости от класса Java) содержатся рекомендуемые замены для некоторых широко используемых внутренних API для JDK.

Для Gradle и Maven есть подключаемые модули jdeps и jdeprscan. Мы рекомендуем добавить эти инструменты в ваши скрипты сборки.

Инструмент Подключаемый модуль Gradle Подключаемый модуль Maven
jdeps jdeps-gradle-plugin Подключаемый модуль Apache Maven JDeps
jdeprscan jdeprscan-gradle-plugin Подключаемый модуль Apache Maven JDeprScan

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

Что jdeprscan и jdeps не могут сделать, так это предупредить об использовании отражения для доступа к инкапсулированному API. Доступ с помощью рефлексии проверяется во время выполнения. Безусловно, чтобы быть уверенным, код следует запустить на Java 11.

Использование jdeprscan

Самый простой способ использовать jdeprscan — предоставить ему JAR-файл из существующей сборки. Ему можно также предоставить каталог, например выходной каталог компилятора или имя отдельного класса. Используйте параметр —release 11 , чтобы получить наиболее полный список нерекомендуемых API. Если вы хотите определить, какой из нерекомендуемых API следует использовать, снова верните для параметра значение —release 8 . API, признанный нерекомендуемым на Java 8, скорее всего, будет удален раньше, чем API, признанный нерекомендуемым совсем недавно.

jdeprscan --release 11 my-application.jar 

Инструмент jdeprscan генерирует сообщение об ошибке при возникновении проблем с разрешением зависимого класса. Например, error: cannot find class org/apache/logging/log4j/Logger . Рекомендуется добавлять зависимые классы в —class-path или использовать путь класса приложения, однако инструмент продолжит сканирование без него. Аргумент — —class-path. Никакие другие вариации аргумента пути класса не сработают.

jdeprscan --release 11 --class-path log4j-api-2.13.0.jar my-application.jar error: cannot find class sun/misc/BASE64Encoder class com/company/Util uses deprecated method java/lang/Double::(D)V 

Этот вывод говорит о том, что класс com.company.Util вызывает нерекомендуемый конструктор класса java.lang.Double . javadoc порекомендует, какой API следует использовать вместо нерекомендуемого. Никакой объем работы не решит error: cannot find class sun/misc/BASE64Encoder , поскольку это API, который был удален. Начиная с Java 8, следует использовать java.util.Base64 .

Запустите jdeprscan —release 11 —list , чтобы получить представление о том, какие API стали нерекомендуемыми после Java 8. Чтобы получить список удаленных API, запустите jdeprscan —release 11 —list —for-removal .

Использование jdeps

Используйте jdeps, с опцией —jdk-internals , что найти зависимости от внутреннего API для JDK. Для этого примера нужен параметр командной строки —multi-release 11 , поскольку log4j-core-2.13.0.jar является JAR-файлом с несколькими выпусками. Без этой опции при нахождении JAR-файла с несколькими выпусками jdeps будет создавать предупреждение. Параметр определяет, какую версию файлов классов необходимо проверить.

jdeps --jdk-internals --multi-release 11 --class-path log4j-core-2.13.0.jar my-application.jar Util.class -> JDK removed internal API Util.class -> jdk.base Util.class -> jdk.unsupported com.company.Util -> sun.misc.BASE64Encoder JDK internal API (JDK removed internal API) com.company.Util -> sun.misc.Unsafe JDK internal API (jdk.unsupported) com.company.Util -> sun.nio.ch.Util JDK internal API (java.base) Warning: JDK internal APIs are unsupported and private to JDK implementation that are subject to be removed or changed incompatibly and could break your application. Please modify your code to eliminate dependence on any JDK internal APIs. For the most recent update on JDK internal API replacements, please check: https://wiki.openjdk.java.net/display/JDK8/Java+Dependency+Analysis+Tool JDK Internal API Suggested Replacement ---------------- --------------------- sun.misc.BASE64Encoder Use java.util.Base64 @since 1.8 sun.misc.Unsafe See http://openjdk.java.net/jeps/260 

Выход дает несколько хороших советов по устранению использования внутреннего API JDK. Замена API предлагается на всех возможных местах. В скобках указано имя модуля, в котором инкапсулирован пакет. Имя модуля можно использовать с —add-exports или —add-opens , если необходимо явно прервать инкапсуляцию.

Использование sun.misc.BASE64Encoder или sun.misc.BASE64Decoder приведет на Java 11 к ошибке java.lang.NoClassDefFoundError. Использующий эти API код следует модифицировать для использования java.util.Base64.

Попробуйте исключить использование любых API, исходящих из модуля jdk.unsupported. API из этого модуля будет ссылаться на Предложение по усовершенствованию JDK (JEP) 260 в качестве предлагаемой замены. Если кратко, то JEP 260 говорит, что использование внутреннего API будет поддерживаться до тех пор, пока не будет доступен заменяющий API. Несмотря на то, что ваш код может использовать внутренний API для JDK, он будет продолжать работать, по крайней мере, некоторое время. Взгляните на JEP 260, так как он указывает на замену некоторых внутренних API. переменные дескрипторы можно использовать, например, вместо некоторых API sun.misc.Unsafe.

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

Использование javac

Компиляция с JDK 11 потребует обновлений для сборки скриптов, инструментов, тестовых платформ и включенных библиотек. Используйте параметр -Xlint:unchecked для javac, чтобы получить подробные сведения об использовании внутреннего API JDK и других предупреждений. Также для демонстрации компилятору инкапсулированных пакетов может потребоваться использование —add-opens или —add-reads (см. JEP 261).

Библиотеки могут рассматривать упаковку как JAR-файл с несколькими выпусками. JAR-файлы с несколькими выпусками позволяют поддерживать среды выполнения как Java 8, так и Java 11 из одного и того же JAR-файла. Они действительно добавляют сложность в выполнение сборки. Сведения о сборке JAR-файлов с несколькими выпусками не входят в область, рассматриваемую эти документом.

Выполнение на Java 11

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

Большинство проблем, с которыми вы можете столкнуться, можно решить, не выполняя перекомпиляцию кода. Если проблему следует исправлять в коде, исправьте ее, но продолжайте компилировать с помощью JDK 8. По возможности работайте над доведением приложения до запуска с java версией 11 до компиляции с JDK 11.

Проверка параметров командной строки

Перед выполнением на Java 11 следует выполнить быструю проверку параметров командной строки. Удаленные опции приведут к выходу виртуальной машины Java. Эта проверка особенно важна, если вы используете опции ведения журнала для сборки мусора, поскольку они радикально изменились с Java 8. Инструмент JaCoLine хорошо подходит для обнаружения проблем с параметрами командной строки.

Проверка сторонних библиотек

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

Рекомендуется вносить как можно меньше изменений и обновлять сторонние библиотеки в виде отдельных трудозатрат. Если вы обновляете стороннюю библиотеку, то чаще всего вам потребуется самая последняя версия, совместимая с Java 11. В зависимости от того, насколько отстает ваша текущая версия, возможно, вы захотите применить более осторожный подход и обновить ее до первой версии, совместимой с Java 9+.

Кроме просмотра заметок о выпуске, для оценки JAR-файла можно использовать jdeps и jdeprscan. Кроме того, Группа контроля качества OpenJDK поддерживает вики-страницу Quality Outreach (Популяризация качественного содержимого), на которой перечислен статус тестирования многих проектов FOSS с версиями OpenJDK.

Явно установленная сборка мусора

Сборщик мусора Parallel (Parallel GC) — это стандартный сборщик мусора в Java 8. Если приложение использует значение по умолчанию, сборку мусора следует явно задать с помощью параметра командной строки -XX:+UseParallelGC . Вместо значения по умолчанию в Java 9 используется сборщик мусора G1GC (Garbage First Garbage Collector). Чтобы справедливо сравнить приложение, работающее на Java 8, с Java 11, настройки сборки мусора должны быть одинаковыми. Экспериментирование с настройками сборки мусора следует отложить, пока приложение не будет проверено на Java 11.

Явно заданные параметры по умолчанию

При запуске на ВМ HotSpot, установка параметра командной строки -XX:+PrintCommandLineFlags будет сбрасывать значения параметров, установленных ВМ, в частности, значения по умолчанию, установленные сборкой мусора. Запускайте с этим флагом на Java 8 и используйте печатные параметры при запуске на Java 11. По большей части, значения по умолчанию для версий от 8 до 11 одинаковы. Но использование настроек из 8 обеспечивает четность.

Рекомендуется использовать параметр командной строки —illegal-access=warn . Использование рефлексии для доступа к внутреннему API для JDK в Java 11 приведет к появлению предупреждения о недопустимом доступе с помощью рефлексии. По умолчанию предупреждение выдается только при первом недопустимом доступе. Установка —illegal-access=warn приведет к вызову предупреждения при каждом недопустимом доступе с помощью рефлексии. Установив параметр на предупреждение, вы сможете найти еще больше случаев недопустимого доступа. Но вы также будете получать много лишних предупреждений.
После запуска приложения на Java 11, установите —illegal-access=deny для имитации будущего поведения во время выполнения Java. Начиная с Java 16, значением по умолчанию будет —illegal-access=deny .

Предостережения ClassLoader

В Java 8 загрузчик системного класса можно привести к URLClassLoader . Обычно это выполняется приложениями и библиотеками, которые хотят внедрить классы в путь к классу во время выполнения. В Java 11 иерархия классов загрузчиков изменилась. Загрузчик системного класса (также известный как загрузчик класса приложения) теперь является внутренним классом. Приведение к URLClassLoader вызовет ClassCastException во время выполнения. Java 11 не имеет API для динамического дополнения пути к классу во время выполнения, но это можно сделать с помощью рефлексии, с очевидными предостережениями об использовании внутреннего API.

В Java 11 загрузчик класса загрузки загружает только основные модули. При создании загрузчика классов с нулевым родительским элементом, он сможет найти не все классы платформы. В Java 11 в таких случаях в качестве загрузчика класса родительского элемента нужно передавать ClassLoader.getPlatformClassLoader() , а не null .

Изменения локальных данных

Источник локальных данных по умолчанию на Java 11 изменен с помощью JEP 252 на Единый репозиторий локальных данных консорциума Юникод. Это может повлиять на локальное форматирование. При необходимости установите системное свойство java.locale.providers=COMPAT,SPI для возврата к поведению языкового стандарта Java 8.

Возможные проблемы

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

  • Нераспознанный параметр ВМ
  • Нераспознанный параметр
  • Предупреждение ВМ: игнорирование параметра
  • Предупреждение ВМ: параметр option> нерекомендуемый
  • ПРЕДУПРЕЖДЕНИЕ: возникла недопустимая операция доступа с помощью рефлексии
  • java.lang.reflect.InaccessibleObjectException
  • java.lang.NoClassDefFoundError
  • -Xbootclasspath/p больше не поддерживается
  • java.lang.UnsupportedClassVersionError
Нераспознанные параметры

Если параметр командной строки удален, то приложение выведет Unrecognized option: или Unrecognized VM option , за которым последует имя конфликтующего параметра. Нераспознанный параметр приведет к выходу ВМ. Нерекомендуемые параметры, которые не были удалены, будут выдавать предупреждение ВМ.

В общем, удаленные параметры не заменяются, и единственным решением является удаление параметра из командной строки. Исключением являются опции для ведения журнала о сборе мусора. Ведение журнала о сборке мусора реализовано в Java 9 для использования унифицированной платформы ведения журналов JVM. См. «Table 2-2 Mapping Legacy Garbage Collection Logging Flags to the Xlog Configuration» (Таблица 2-2. Сопоставление флагов ведения журнала устаревших сборок мусора с конфигурацией Xlog) в разделе Enable Logging with the JVM Unified Logging Framework (Включение ведения журнала с помощью унифицированной платформы ведения журналов JVM) из Справочника по инструментам Java SE 11.

Предупреждения ВМ

Использование нерекомендуемых параметров приведет к созданию предупреждения. Параметр становится нерекомендуемым, если он заменен или больше не используется. Как и в случае с удаленными параметрами, эти параметры следует удалить из командной строки. Предупреждение VM Warning: Option was deprecated означает, что параметр все еще поддерживается, но эта поддержка может быть удалена в будущем. Параметр, который больше не поддерживается, будет выдавать предупреждение VM Warning: Ignoring option . Неподдерживаемые параметры не влияют на среду выполнения.

На веб-странице VM Options Explorer (Обозреватель параметров ВМ) представлен исчерпывающий список параметров, которые были добавлены в Java, начиная с JDK 7 или добавлены в него.

Ошибка: Не удалось создать виртуальную машину Java.

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

ПРЕДУПРЕЖДЕНИЕ. Возникла недопустимая операция доступа с помощью рефлексии

Если Java-код использует отражение для доступа к внутреннему API JDK, во время выполнения будет выдано предупреждение о недопустимом доступе с помощью рефлексии.

WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by my.sample.Main (file:/C:/sample/) to method sun.nio.ch.Util.getTemporaryDirectBuffer(int) WARNING: Please consider reporting this to the maintainers of com.company.Main WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release 

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

Чтобы решить это предупреждение, найдите обновленный код, который не использует внутренний API. Если проблему невозможно решить с помощью обновленного кода, для открытия доступа к пакету можно использовать либо параметр —add-exports , либо параметр командной строки —add-opens . Эти параметры позволяют получить доступ к неэкспортированным типам одного модуля из другого.

Параметр —add-exports позволяет целевому модулю получить доступ к общедоступным типам именованного пакета модуля-источника. Иногда для доступа к членам и API, не являющимся открытыми, код будет использовать setAccessible(true) . Он известен, как глубокое отражение. В этом случае используйте —add-opens для предоставления вашему коду доступа к членам пакета, которые не являются открытыми. Если вы не уверены, использовать —add-exports или —add-opens, начните с —add-exports.

Параметры —add-exports или —add-opens следует рассматривать как обходной путь, а не как долгосрочное решение. Использование этих опций прерывает инкапсуляцию модульной системы, которая должна препятствовать использованию внутреннего API JDK. Если внутренний API будет удален или изменен, приложение выйдет из строя. Доступ с помощью рефлексии будет запрещен на Java 16, за исключением случаев, когда доступ будет разрешен параметрами командной строки, такими как —add-opens . Чтобы имитировать будущее поведение, установите —illegal-access=deny в командной строке.

Предупреждение в приведенном выше примере выдается потому, что пакет sun.nio.ch не экспортируется модулем java.base . Другими словами, в файле module-info.java модуля java.base нет exports sun.nio.ch; . Это можно решить с помощью —add-exports=java.base/sun.nio.ch=ALL-UNNAMED . Классы, не определенные в модуле, неявно принадлежат неименованному модулю, буквально названному ALL-UNNAMED .

java.lang.reflect.InaccessibleObjectException

Это исключение указывает на то, что вы пытаетесь вызвать setAccessible(true) в поле, или метод инкапсулированного класса. Вы также можете получить предупреждение о недопустимом доступе с помощью рефлексии. Используйте —add-opens для предоставления вашему коду доступа к членам пакета, которые не являются открытыми. Сообщение об исключении сообщит, что модуль «не открывает» пакет модулю, который пытается вызвать setAccessible. Если модуль является «неименованным», используйте UNNAMED-MODULE в качестве целевого модуля в параметре —add-opens.

java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.ArrayList jdk.internal.loader.URLClassPath.loaders accessible: module java.base does not "opens jdk.internal.loader" to unnamed module @6442b0a6 $ java --add-opens=java.base/jdk.internal.loader=UNNAMED-MODULE example.Main 
java.lang.NoClassDefFoundError

Ошибка NoClassDefFoundError, скорее всего, вызвана разделенным пакетом или ссылкой на удаленные модули.

Ошибка NoClassDefFoundError, вызванная разделением пакетов

Раздельный пакет —это пакет, находящийся в нескольких библиотеках. Симптомом проблемы разделения пакетов является то, что класс, который должен находится в пути класса, невозможно найти.

Эта проблема будет возникать только при использовании пути модуля. Система модулей Java оптимизирует поиск классов, ограничивая пакет одним именованным модулем. При выполнении поиска классов предпочтение отдается пути модуля, а не класса. Если пакет разделен между модулем и путем к классу, то для поиска класса используется только модуль. Это может привести к ошибкам NoClassDefFound .

Простой способ проверки разделенного пакета — подключить путь к модулю и к классу в jdeps и использовать путь к файлам класса приложения в качестве значения . Если есть разделенный пакет, jdeps выведет предупреждение: Warning: split package: .

Эту проблему можно решить, используя —patch-module =[,] для добавления разделенного пакета в именованный модуль.

Ошибка NoClassDefFoundError, вызванная использованием модулей Java EE или CORBA

Если приложение работает на Java 8, но вызывает java.lang.NoClassDefFoundError или java.lang.ClassNotFoundException , то вполне вероятно, что приложение использует пакет из модулей Java EE или CORBA. Эти модули признаны нерекомендуемыми на Java 9 и удалены на Java 11.

Чтобы решить проблему, добавьте в проект зависимость среды выполнения.

Удаленный модуль Затронутый пакет Предлагаемая зависимость
Java API для Веб-служб XML (JAX-WS) java.xml.ws Среда выполнения RI для JAX WS
Архитектура Java для привязки XML (JAXB) java.xml.bind Среда выполнения JAXB
Платформа активации JavaBeans (JAV) java.activation Платформа активации JavaBeans (TM)
Общие заметки java.xml.ws.annotation API заметки Javax
Архитектура брокера запросов общих объектов (CORBA) java.corba GlassFish CORBA ORB
API транзакций Java (JTA) java.transaction API транзакций Java
-Xbootclasspath/p больше не поддерживается

Поддержка для -Xbootclasspath/p удалена. Используйте вместо этого —patch-module . Параметр —patch-module описан в JEP 261. Ищите раздел с названием «Patching module content» (Исправление содержимого модуля). —patch-module можно использовать с javac и java для переопределения или дополнения классов в модуле.

Что делает —patch-module, так это вставляет модуль исправления в поиск класса модульной системы. Модульная система сначала захватит класс из модуля исправления. Это тот же эффект, что и в случае с bootclasspath на Java 8.

UnsupportedClassVersionError

Это исключение означает, что вы пытаетесь запустить код, который был скомпилирован с более поздней версией Java, на более ранней версии Java. Например, вы работаете на Java 11 с JAR-файлом, скомпилированным с JDK 13.

Версия Java Версия формата файла класса
8 52
9 53
10 54
11 55
12 56
13 57

Дальнейшие действия

После того, как приложение запустится на Java 11, рассмотрите возможность переноса библиотек с пути класса на путь модуля. Выполните поиск обновленных версий библиотек, от которых зависит ваше приложение. Если возможно, выбирайте модульные библиотеки. Используйте путь модулей, даже если вы не планируете использовать модули в своем приложении. Использование пути модуля предоставляет производительность при загрузке классов, которая намного лучше производительности при использовании пути модуля.

Руководство по версиям и возможностям Java

Здесь есть все, что вам нужно знать о различных версиях и функциях Java.

Java 8, Java 11, Java 13 — какая разница?

Вы можете использовать это руководство, чтобы найти и установить последнюю версию Java, понять различия между дистрибутивами Java (AdoptOpenJdk, OpenJDK, OracleJDK и т.д.), А также получить обзор возможностей языка Java, включая версии Java 8-13.

Примечание переводчика
09 апреля 2020 г. Марко опубликовал новую версию Руководства, в которую добавлено описание Java 14.
Перевод новой версии Руководства предлагается Вашему вниманию.

Исходная информация

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

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

Какую версию Java я должен использовать?

По состоянию на сентябрь 2019 года Java 13 является последней выпущенной версией Java, с новыми версиями, выходящими каждые 6 месяцев — Java 14 запланирована на март 2020 года, Java 15 на сентябрь 2020 года и т.д. В прошлом циклы выпуска Java были намного длиннее, до 3-5 лет!

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

  • Унаследованные проекты в компаниях часто связаны с использованием Java 8 (см. Раздел «Почему компании все еще застревают на Java 8?» Ниже). Таким образом, вы также будете вынуждены использовать Java 8.
  • Некоторые унаследованные проекты даже работают на Java 1.5 (выпущен в 2004 г.) или 1.6 (выпущен в 2006 г.) — сожалею, друзья!
  • Если вы уверены, что используете самые последние IDE, интегрированные среды и инструменты сборки и запускаете новый проект, вы можете без колебаний использовать Java 11 (LTS) или даже самую последнюю версию Java 13.
  • Есть специальная область разработки Android, где Java в основном застряла на версии Java 7, с доступом к определенному набору функций Java 8. Но вы можете переключиться на использование языка программирования Kotlin.

Почему компании все еще застряли на Java 8?

Существует множество разных причин, по которым компании все еще придерживаются Java 8. Вот некоторые из них:

  • Инструменты сборки (Maven, Gradle и т.д.) и некоторые библиотеки изначально имели ошибки с версиями Java версий> 8 и нуждались в обновлениях. Даже сегодня, например, с Java 9+, некоторые инструменты сборки выводят предупреждения «reflective access» при создании проектов Java, которые просто «не готовы», даже если со сборкой все в порядке.
  • До Java 8 вы в основном использовали JDK-сборки Oracle, и вам не нужно было заботиться о лицензировании. Однако в 2019 году Oracle изменила схему лицензирования, что привело к тому, что Интернет сошел с ума, сказав, что «Java больше не является бесплатной», — и последовало значительное замешательство. Однако на самом деле это не проблема, о чем вы узнаете в разделе «Дистрибутивы Java» данного руководства.
  • В некоторых компаниях действуют политики, позволяющие использовать только версии LTS, и полагаются на поставщиков своих ОС для предоставления этих сборок, что требует времени.

Подводя итог, у вас есть сочетание практических вопросов (обновление ваших инструментов, библиотек, фреймворков) и политических проблем.

Почему некоторые версии Java называются 1.X?

Java до версии 9 просто имела другую схему именования. Итак, Java 8 также может называться 1.8, Java 5 может называться 1.5 и т.д. Когда вы выполнили команду java -version с этими версиями, вы получили такой вывод:

c:\Program Files\Java\jdk1.8.0_191\bin>java -version java version "1.8.0_191" (1) Java(TM) SE Runtime Environment (build 1.8.0_191-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

Это просто означает Java 8. С переходом к основанным на времени выпускам с Java 9 также изменилась схема именования, и версии Java больше не имеют префикса 1.x. Теперь номер версии выглядит так:

c:\Program Files\Java\jdk11\bin>java -version openjdk version "11" 2018-09-25 (1) OpenJDK Runtime Environment 18.9 (build 11+28) OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

В чем разница между версиями Java?

Должен ли я изучать конкретную?

Придя из других языков программирования с большими перерывами между выпусками, как, например, Python 2–3, вы можете спросить, применимо ли это к Java.

Java особенная в этом отношении, поскольку она чрезвычайно обратно совместима. Это означает, что ваша программа на Java 5 или 8 гарантированно будет работать с виртуальной машиной Java 8-13 — с некоторыми исключениями, о которых вам сейчас не нужно беспокоиться.

Очевидно, что это не работает наоборот, скажем, ваша программа использует функции Java 13, которые просто недоступны в Java 8 JVM.

Это означает несколько вещей:

  • Вы не просто «изучаете» конкретную версию Java, например Java 12.
  • Скорее, вам нужно получить хорошую основу для всех языковых возможностей вплоть до Java 8.
  • И затем, из этого руководства вы можете узнать, какие дополнительные функции появились в Java 9-13, чтобы использовать их всегда, когда это возможно.

Каковы примеры этих новых возможностей новых версий Java?

Взгляните на раздел «Возможности Java 8-13» ниже.

Но, как правило: старые, более длинные циклы выпуска (3-5 лет, вплоть до Java 8) означали множество новых функций в каждом выпуске.

Шестимесячный цикл выпуска означает меньшее количество функций на выпуск, поэтому вы можете быстро освоить языковые функции Java 9-13.

В чем разница между JRE и JDK?

До сих пор мы говорили только о Java. Но что именно означает «Java»?

Во-первых, вам нужно провести различие между JRE (Java Runtime Environment) и JDK (Java Development Kit).

Исторически, вы загружали только JRE, если вас интересовали только программы Java. JRE включает, помимо прочего, виртуальную машину Java (JVM) и инструмент командной строки «java».

Для разработки новых программ на Java вам нужно было загрузить JDK. JDK включает в себя все, что есть в JRE, а также компилятор javac и несколько других инструментов, таких как javadoc (генератор документации Java) и jdb (отладчик Java).

Теперь, почему я говорю в прошедшем времени?

Вплоть до Java 8 веб-сайт Oracle предлагал JRE и JDK в качестве отдельных загрузок, хотя JDK также всегда включал JRE в отдельной папке. В Java 9 это различие практически исчезло, и вы всегда загружаете JDK. Структура каталогов JDK также изменилась, так как в ней больше не было явной папки JRE.

Таким образом, хотя некоторые дистрибутивы (см. Раздел «Дистрибутивы Java») по-прежнему предлагают отдельную загрузку JRE, похоже, существует тенденция предлагать только JDK. Следовательно, теперь мы будем использовать Java и JDK взаимозаменяемо.

Как мне установить Java или JDK?

На данный момент не обращайте внимания на образы Java-Docker, оболочки MSI или пакеты для конкретной платформы. В конце концов, Java — это просто файл .zip; ни больше ни меньше.

Поэтому все, что вам нужно сделать, чтобы установить Java на свой компьютер, — это разархивировать файл jdk-.zip. Вам даже не нужны права администратора для этого.

Ваш распакованный файл Java будет выглядеть так:

Directory C:\dev\jdk-11 12.11.2019 19:24 . 12.11.2019 19:24 .. 12.11.2019 19:23 bin 12.11.2019 19:23 conf 12.11.2019 19:24 include 12.11.2019 19:24 jmods 22.08.2018 19:18 legal 12.11.2019 19:24 lib 12.11.2019 19:23 1.238 release

Магия происходит в каталоге / bin, который в Windows выглядит следующим образом:

Directory C:\dev\jdk-11\bin . 12.11.2019 19:23 272.736 java.exe . 12.11.2019 19:23 20.832 javac.exe . 

Поэтому все, что вам нужно сделать, это разархивировать этот файл и поместить каталог /bin в переменную PATH, чтобы вы могли вызывать команду java из любого места.

В случае, если вам интересно, установщики с графическим интерфейсом, такие как Oracle или AdoptOpenJDK, выполняет распаковку и изменение переменной PATH вместо вас.

Чтобы убедиться, что вы правильно установили Java, вы можете просто выполнить команду java -version. Если вывод выглядит так, как показано ниже, вы готовы!

openjdk version "11" 2018-09-25 OpenJDK Runtime Environment 18.9 (build 11+28) OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

Теперь остался один вопрос: откуда вам взять этот .zip файл с Java? Что подводит нас к теме дистрибутивов.

Дистрибутивы Java

Существует множество сайтов, предлагающих загрузку Java (читай: JDK), и неясно, «кто что предлагает и с каким лицензированием». Этот раздел проливает свет на это.

Проект OpenJDK

С точки зрения исходного кода Java (читай: исходный код вашего JRE / JDK) есть только один — на сайте проекта OpenJDK.

Однако это всего лишь исходный код, а не распространяемая сборка (подумайте: ваш файл .zip с скомпилированной командой java для вашей конкретной операционной системы). Теоретически вы и я могли бы создать сборку из этого исходного кода, назвать ее, скажем, MarcoJDK, и начать ее дистрибуцию. Но наш дистрибутив не будет сертифицирован, чтобы можно было называть этот дистрибутив совместимым с Java SE.

Вот почему на практике есть несколько поставщиков, которые фактически создают эти сборки, сертифицируют (см. TCK) и затем распространяют их.

И хотя поставщики не могут, скажем, удалить метод из класса String перед созданием новой сборки Java, они могут добавить брэндинг (вay!) или добавить некоторые другие утилиты (например, CLI), которые они считают полезными. Но в остальном исходный код одинаков для всех дистрибутивов Java.

OpenJDK (от Oracle) и сборки OracleJDK

Один из поставщиков, который создает Java из исходного кода, — это Oracle. Это приводит к двум разным дистрибутивам Java, что поначалу может быть очень запутанными.

  1. Сборки OpenJDK от Oracle (!). Эти сборки бесплатны и не имеют торговой марки, но Oracle не выпустит обновления для более старых версий, скажем, Java 13, как только выйдет Java 14.
  2. OracleJDK — это коммерческая сборка под брендом, выпускаемая начиная с изменения лицензии в 2019 году. Это означает, что ее можно использовать бесплатно во время разработки, но вы должны платить Oracle, если используете ее в рабочей среде. При этом вы получаете более длительную поддержку, то есть все обновления дистрибутива и номер телефона, по которому можно позвонить, если с вашей JVM будут проблемы.

Исторически (до Java 8) существовали реальные исходные различия между сборками OpenJDK и сборками OracleJDK, при этом можно было сказать, что OracleJDK был «лучше». Но на сегодняшний день обе версии практически одинаковы, с небольшими отличиями.

Впрочем все сводится к тому, что вам требуется платная коммерческая поддержка (номер телефона) для используемой версии Java.

AdoptOpenJDK

В 2017 году группа участников, разработчиков и поставщиков Java User Group (Amazon, Microsoft, Pivotal, Red Hat и другие) создала сообщество под названием AdoptOpenJDK.

Они предоставляют бесплатные надежные сборки OpenJDK с более длительной доступностью / обновлениями и даже предлагают вам выбор из двух разных виртуальных машин Java: HotSpot и OpenJ9.

Я очень рекомендую ее, если вы хотите установить Java.

Azul Zulu, Amazon Corretto, SAPMachine

Полный список сборок OpenJDK вы найдете на сайте OpenJDK Wikipedia. Среди них Azul Zulu, Amazon Corretto, а также https://sap.github.io/SapMachine/ и многие другие. Упрощенно говоря, различия сводятся к тому, что у вас есть различные варианты поддержки/ гарантии обслуживания.

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

Рекомендация

Повторим с еще раз, что с 2019 года, если у вас нет особых требований, найдите файл jdk.zip (.tar.gz/.msi/.pkg) по адресу https://adoptopenjdk.net или выберите пакет, предоставленный вашим поставщиком ОС.

Возможности Java 8-13

Как уже упоминалось в самом начале этого руководства: в сущности все (если вы не будьте слишком требовательны) функции языка Java 8 работают в Java 13. То же самое касается всех других версий Java между ними.

В свою очередь, это означает, что знание всех языковых функций Java 8 дает хорошую базу в изучении Java, а все остальные версии (Java 9-13) в значительной степени дают дополнительные функции поверх этого базового уровня.

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

Java 8

Java 8 была массовым выпуском, и вы можете найти список всех функций на веб-сайте Oracle. Здесь я хотел бы упомянуть два основных набора функций:

Особенности языка: лямбды и т.д.

До Java 8 всякий раз, когда вы хотели создать экземпляр, например, нового Runnable, вы должны были написать анонимный внутренний класс, например, так:

 Runnable runnable = new Runnable() < @Override public void run()< System.out.println("Hello world !"); >>;

С лямбдами тот же код выглядит так:

Runnable runnable = () -> System.out.println("Hello world two!");

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

Коллекции и потоки

В Java 8 вы также получили операции в функциональном стиле для коллекций, также известные как Stream API. Быстрый пример:

List list = Arrays.asList("franz", "ferdinand", "fiel", "vom", "pferd");

До Java 8, вам нужно было написать циклы for, чтобы что-то сделать с этим списком.

С помощью API Streams вы можете сделать следующее:

list.stream() .filter(name -> name.startsWith("f")) .map(String::toUpperCase) .sorted() .forEach(System.out::println);

Java 9

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

Коллекции

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

List list = List.of("one", "two", "three"); Set set = Set.of("one", "two", "three"); Map map = Map.of("foo", "one", "bar", "two");
Streams

Потоки получили несколько дополнений, в виде методов takeWhile, dropWhile и iterate.

Stream stream = Stream.iterate("", s -> s + "s") .takeWhile(s -> s.length() < 10);
Optionals

Optionals получили метод ifPresentOrElse, которого крайне не хватало.

user.ifPresentOrElse(this::displayAccount, this::displayLogin);
Интерфейсы

Интерфейсы получили private методы:

public interface MyInterface < private static void myPrivateMethod()< System.out.println("Yay, I am private!"); >>
Другие возможности языка

И пара других улучшений, таких как улучшенный оператор try-with-resources или расширения diamond оператора.

JShell

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

% jshell | Welcome to JShell -- Version 9 | For an introduction type: /help intro jshell> int x = 10 x ==> 10
HTTPClient

Java 9 принес первоначальную предварительную версию нового HttpClient. До этого встроенная поддержка Http в Java была довольно низкоуровневой, и вам приходилось использовать сторонние библиотеки, такие как Apache HttpClient или OkHttp (кстати, отличные библиотеки).

В Java 9 у Java появился собственный современный клиент — хотя он находится в режиме превью, что означает, что он может быть изменен в более поздних версиях Java.

Проект Jigsaw: модули Java и файлы Jar с несколькими выпусками

Java 9 получила Jigsaw Module System, которая чем-то напоминает старую добрую спецификацию OSGI. Целью данного руководства не является подробное описание Jigsaw — посмотрите предыдущие ссылки, чтобы узнать больше.

Файлы Multi-Release .jar позволили создать один файл .jar, содержащий разные классы для разных версий JVM. Таким образом, ваша программа может вести себя по-разному / иметь разные классы, используемые при запуске на Java 8 и на Java 10, например.

Java 10

В Java 10 было несколько изменений, таких как сборка мусора и т.д. Но единственное реальное изменение, которое вы, как разработчик, вероятно, заметите, — это введение ключевого слова var, также называемого выводом типа локальной переменной.

Вывод типа локальной переменной: ключевое слово var

// Pre-Java 10 String myName = "Marco"; // With Java 10 var myName = "Marco"

Чувствуете себя как в Javascript-е, не так ли? Однако Java все еще строго типизирован и var применяется только к переменным внутри методов (спасибо, dpash, за то, что снова указал на это).

Java 11

Java 11 также была несколько меньшей версией с точки зрения разработчика.

Строки и файлы

Строки и файлы получили несколько новых методов (не все перечислены здесь):

"Marco".isBlank(); "Mar\nco".lines(); "Marco ".strip(); Path path = Files.writeString(Files.createTempFile("helloworld", ".txt"), "Hi, my name is!"); String s = Files.readString(path);
Запустить исходные файлы

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

ubuntu@DESKTOP-168M0IF:~$ java MyScript.java
Вывод типа локальной переменной (var) для лямбда-параметров

В заголовке все сказано:

(var firstName, var lastName) -> firstName + lastName
HttpClient

HttpClient из Java 9, но уже в окончательной, а не превью версии.

Другие вкусности

Flight Recorder (Регистратор полетов), сборщик мусора No-Op, Nashorn-Javascript-Engine объявлен deprecated (устаревшим) и т.д.

Java 12

В Java 12 появилось несколько новых функций и исправлений, но здесь стоит упомянуть только поддержку Unicode 11 и превью нового выражения switch, о котором вы узнаете в следующем разделе.

Java 13

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

Switch выражение (Preview — предварительная версия)

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

Старые операторы switch выглядели так:

switch(status) < case SUBSCRIBER: // code block break; case FREE_TRIAL: // code block break; default: // code block >

В то время как в Java 13 операторы switch могут выглядеть так:

boolean result = switch (status) < case SUBSCRIBER ->true; case FREE_TRIAL -> false; default -> throw new IllegalArgumentException("something is murky!"); >;
Многострочные строки (превью)

Наконец-то вы можете сделать это на Java:

String htmlBeforeJava13 + " \n" + " 

Hello, world

\n" + " \n" + "\n"; String htmlWithJava13 = """

Hello, world

""";

Java 14 и позже

Будет рассмотрено здесь, как только их выпустят. Зайдите в ближайшее время!

Вывод

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

  • Как установить Java, какую версию получить и где ее получить (подсказка: AdoptOpenJDK).
  • Что такое дистрибутив Java, какие существуют и в чем различия.
  • Каковы различия между конкретными версиями Java.

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

Спасибо за прочтение!

Там больше, откуда это появилось

Эта статья первоначально появилась на сайте как часть серии руководств по современному программированию на Java. Чтобы найти больше руководств, посетите веб-сайт или подпишитесь на рассылку, чтобы получать уведомления о недавно опубликованных руководствах: https://bit.ly/2K0Ao4F.

Благодарности

Стивен Колебурн написал фантастическую статью о различных доступных дистрибутивах Java. Спасибо, Стивен!

Что такое java 11

Недавно корпорация Oracle объявила о выпуске релиза Java 11 LTS (Long Term Support) и формально это событие знаменует собой завершение монументального сдвига в экосистеме Java. Со сложностями перехода от Java 8 к модульному и гибкому JDK с шестимесячным циклом выпуска релизов, с новыми лицензионными соглашениями и долгосрочными моделями поддержки, мы вступили в новую эру!

Теперь кодовые базы должны следовать за нововведениями, и многие проекты перейдут с Java 8 непосредственно на Java 11. Если вы с этим согласны, то вы пришли в нужное место — это руководство по миграции сообщит вам все, что нужно знать при переходе с Java 8 на Java 11.

Мы начнем с супер-быстрого тура по новому циклу релизов, лицензированию и поддержке прежде, чем обсуждать, как подготовить миграцию. И, наконец, как преодолеть четыре наиболее распространенных препятствия (если вы уже перешли на Java 9, можете пропустить, пройденную вами часть). Обратите внимание, что мы говорим о миграции, а не модуляции (это не требуется и должно быть отдельным шагом), поэтому мы не будем создавать какие-либо модули.

О релизах, JDK и лицензиях

Это может показаться скучным, но шестимесячный цикл выпуска релизов, коммерциализация Oracle JDK и открытый вопрос о долгосрочной поддержке OpenJDK, вероятно, окажут большее влияние на ваши проекты, чем технические проблемы перехода на Java 11. Итак, давайте обсудим это, но будем краткими — подробности можно найти в прилагаемых ссылках

⇝ Java Next (talk at JavaZone 2018)
Новые правила выпуска релизов Java

Это самое известное изменение, поэтому скажем кратко:

  • выход новых крупных релизов каждые полгода (март и сентябрь)
  • спустя один и четыре месяца после выхода релиза будут выпускаться пакеты с незначительными обновлениями

OpenJDK — новый стандарт

В былые темные времена (до сентября 2018 года) JDK от Oracle (и ранее JDK от Sun) были более функциональными, более эффективными и более стабильными, следовательно — это был выбор по умолчанию для большей части пользователей экосистемы Java. OpenJDK при этом был похож на уродливого утенка, которого большинство разработчиков пытались избегать. Но теперь, с Java 11, OpenJDK превратилась в лебедя!

Oracle JDK становится полностью коммерческим

Компания Oracle долго и тяжело работала над тем, чтобы Oracle JDK 11 и OpenJDK 11 стали практически идентичными с технической точки зрения — до такой степени, что наиболее важным отличием между ними является файл лицензии. Oracle подталкивает разработчиков к использованию OpenJDK, делая свой фирменный JDK коммерческим, то есть вы не можете использовать его в продакшен, не платя Oracle с первого дня запуска проекта (вы можете использовать Oracle JDK для разработки и тестирования).

Как следствие, теперь именно OpenJDK станет новым стандартом с полным набором функций, максимальной производительностью и бесплатной лицензией (GPL + CE), что будет отличным выбором! На следующей ступени идут бок о бок Oracle и другие производители со своими вариантами OpenJDK, для которых они продают долгосрочную поддержку.

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

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