Перевод. Оригинал статьи: https://foojay.io/today/9-outdated-ideas-about-java/
Миф 1: Java старая и не развивается.
Бытует мнение что Java это устаревший язык программирования, хотя PHP такой же старый, а тот же Python ещё на четыре года старше.
Что касается развития языка, то у Java до 9-й версии не было установленного графика выпуска. Новая версия выпускалась, когда реализовывался предопределенный список новых функций. Но с 2018 года у Java появился шестимесячный цикл релизов с фиксированными датами, и каждая новая версия содержит функции, которые полностью завершены и протестированы сообществом. Также в релизе присутствуют и экспериментальные функции, которые все еще находятся в разработке, однако они доступны только в том случае, если приложение собрано и запущено с дополнительными флагами.
Благодаря этому новому подходу каждая новая версия приносит улучшения как в плане производительности, так и в плане написания кода. А поскольку с обратной совместимостью в OpenJDK всё хорошо, то в большинстве случаев можно без проблем запускать существующие приложения с более новыми версиями JDK не меняя кода, при этом получая выгоду от меньшего времени запуска, меньшего использования памяти и улучшенной сборкой мусора.
Вот очень краткий обзор ряда изменений в версиях OpenJDK, но имейте в виду, что это лишь малая часть новых функций и улучшений. Некоторые функции были впервые представлены как экспериментальные (превью) и доработаны только в более поздней версии:
Версия | Изменения |
---|---|
OpenJDK 19 | Виртуальные потоки (превью) |
OpenJDK 18 | Pattern Matching для switch (второй превью) |
OpenJDK 17 | Sealed типы |
OpenJDK 16 | Новый тип объявления классов - record, Pattern matching для instanceof |
OpenJDK 15 | Текстовые блоки |
OpenJDK 14 | Helpful NPE, стримминг из запущенного приложения в JFR, Java Packager (jpackage), Pattern matching |
OpenJDK 13 | Улучшенные версии превью-фич |
OpenJDK 12 | Первое превью текстовых блоков |
OpenJDK 11 | Упрощённый запуск программ из одного файла, Java Flight Recorder (JFR) |
OpenJDK 10 | Local Variable Type Inference (LVTI) - он же тип var |
OpenJDK 9 | Модульность, Java Dependency Analyser (jdeps), Java Shell (jshell) |
OpenJDK 8 |
Лямбда-выражения и Stream API, default-методы в интерфейсах. Всё это очень сильно повлияло на стиль программирования на Java. |
Факт: 6-месячный цикл выпуска привнес много изменений в OpenJDK.
Миф 2: Нужно скомпилировать код, прежде чем его можно будет запустить
Действительно, Java - это компилируемый язык программирования, и для выполнения программы лучший вариант это предварительно скомпилировать код в class-файл. Этот файл содержит байтовый код, который может выполняться виртуальной машиной Java (JVM) на любой платформе.
Но есть и другие способы выполнения Java-кода!
В Java 9 появился jshell как часть Java Development Kit (JDK). Это интерфейс командной строки для выполнения кода Java, который можно использовать, например, для тестирования ваших кусков кода. Как описано в JEP 222, код все еще компилируется, но это происходит за кулисами.
% jshell
| Welcome to JShell -- Version 18.0.1
| For an introduction type: /help intro
jshell> String message = "Hello World";
message ==> "Hello World"
jshell> "Test: " + message
$2 ==> "Test: Hello World"
jshell> 8*9
$3 ==> 72
А в Java 11 появился новый способ - выполнения однофайлового кода. Он позволяет запускать программу, состоящую из одного файла, точно так же, как запускаются скрипты PHP или bash. Например:
java HelloWorld.java
Кроме этого, существует такой инструмент, как JBang, который позволяет выполнять код, использующий зависимости, без необходимости его компилировать или использовать инструменты сборки (Maven или Gradle). И если на компьютере не установлена Java, то JBang поставит её за вас!
Факт: под капотом действительно Java-код должен быть скомпилирован, прежде чем его можно будет запустить. Но теперь доступны различные инструменты, которые позволяют «скрыть» этот процесс и упростить непосредственное выполнение Java-кода.
Миф 3: Java медленная
C 1999 года в Java появилась динамическая (Just-In-Time) компиляция.
Текущий Hotspot JIT компилятор или например улучшенный компилятор Falcon, разработанный компанией Azul, позволяют приложениям на Java работать наравне с приложениями на C++. Так же Java намного быстрее, чем большинство популярных скриптовых языков, таких как Python или JavaScript.
Однако есть нюанс - приложения на Java запускаются медленнее, чем приложения на C++, и требуют специальной подготовки, пока JIT компилятор не начнет действовать. Из-за данной особенности в начале 2000-х годов на персональных компьютерах запуск Java-приложений происходил заметно медленнее, приложений на C++, из-за чего создалось впечатление что Java работает медленно.
В настоящее время Java не очень популярен для десктопных приложений, но зато наиболее часто используется для разработки серверных приложений.
Факт: Java однозначно доминирует в серверной разработке, и, благодаря своей скорости, очень часто применяется для написания высоконагруженных приложений в крупных компаниях.
Миф 4: Java небезопасна
В конце 90-х и 2000-х простого HTML было явно недостаточно, поэтому были очень популярны браузерные плагины, которые позволяли запускать различные приложения. Наиболее известными в то время технологиями были Flash, ActiveX, Silverlight и Java-апплеты. Все эти технологии, основанные на плагинах, устарели и полностью запрещены в корпоративной среде, так как с развёртыванием и безопасностью у них очень плохо.
Среди этих технологий Flash был одним из самых уязвимых, и хотя Java-апплеты были лучше изолированы и безопаснее чем Flash - полностью проблема безопасности решена не была, что и способствовало распространению мифа о том, что Java небезопасна.
Java-приложения, работающие на поддерживаемой версии JVM, безопаснее, чем большинство приложений написанных на других языках программирования, поскольку среда выполнения Java может обновляться независимо от самого приложения. Еще одним аргументом в пользу того что Java безопасна, являются четыре выпуска активных версий в год.
Многие дистрибьюторы выпускают улучшенные среды выполнения в течение нескольких часов или дней после публикации списка обнаруженных уязвимостей и угроз (CVE).
Факт: полностью безопасной системы не существует, но наличие рабочего процесса, который собирает, документирует и устраняет проблемы, гарантирует, что безопасность Java поддерживается на высоком уровне.
Миф 5: Сложно установить Java на свой компьютер, и не понятно что с лицензией
Поскольку OpenJDK - это проект с открытым исходным кодом, любой может создать свою реализацию JVM. Многие некоммерческие и коммерческие организации как раз взяли на себя эту роль.
Это привело к появлению длинного списка дистрибутивов, которые вы можете использовать на всех типах устройств, от высокопроизводительных серверов до одноплатных компьютеров, таких как Raspberry Pi. Выбирайте то, что вам больше подходит, и оно будет работать на вашем устройстве, поскольку все дистрибутивы основаны на одних и тех же ветках OpenJDK и (должны быть) протестированы на соответствие спецификациям. Некоторые компании могут предоставлять дополнительные инструменты, поддержку и лицензии.
Факт: большинство дистрибутивов OpenJDK имеют установщики для различных платформ, а такие инструменты, как SDKMAN, позволяют легко устанавливать и переключаться между версиями.
Миф 6: Для запуска Java-кода на ПК должна быть установлена среда выполнения Java
Традиционно среда выполнения Java (JRE) используется для выполнения программ на Java. Но, начиная с OpenJDK 11, имеется альтернатива - связать требуемую JRE с приложением для удобства развертывания и максимальной совместимости.
jlink (JEP 282) - это инструмент, который позволяет собирать модули и их зависимости в пользовательский образ Java Runtime. Можно сказать, что он создает минимально необходимую среду выполнения Java (JRE), специально поддерживающую ваше приложение.
Начиная с OpenJDK 14, был добавлен jpackage (JEP 343) для создания собственного исполняемого файла на основе вывода jlink. Так jpackage создает один исполняемый файл, который автоматически распаковывается без участия пользователя.
Есть и другие упаковщики, например, GluonFX Plugin for Maven может создавать приложения для Windows, macOS, Linux, Android и iOS.
Факт: установка среды выполнения Java на вашем компьютере — это самый простой способ запуска приложений Java. Но доступны и другие инструменты для создания исполняемых файлов, в которые включена среда выполнения JRE.
Миф 7: Приложение приостанавливается во время очистки памяти
В некоторых ситуациях это именно то что нужно, особенно когда правильность результата важнее скорости выполнения, например для длительных пакетных операций. И в таком случае лучше всего подойдет так называемый сборщик мусора Stop-The-World.
Однако за прошедшие годы было реализовано множество других сборщиков мусора, и некоторые из них работают изолированно от потоков вашего приложения (параллельные сборщики мусора) и почти не влияют на выполнение кода, либо влияют минимально (минимальное время остановки). Из стандартных это Garbage First и Z Garbage Collector, а до это ещё был Concurrent Mark Sweep, но в данный момент он объявлен устаревшим. Так же имеются и сторонние реализации, например C4 GC (Continuously Concurrent Compacting Collector) от Azul.
Факт: в некоторых ситуациях сборщик мусора Stop-The-World - это то что нужно, а для других случаев можно использовать параллельные сборщики мусора.
Миф 8: Java не поддерживает множественного наследования
Изначально в Java не поддерживалось множественное наследование чтобы избежать так называемой "проблемы алмаза" (diamond problem), она же - ромбовидное наследование. Однако, с появлением JDK 8 появилась возможность множественного наследования поведения с решением данной проблемы.
Давайте рассмотрим пример с двумя интерфейсами ExampleA и ExampleB, имеющими дефолтный метод doSomething(). Если некий класс ExampleC имплементирует интерфейсы ExampleA и ExampleB, то вызов метода doSomething() приведет к двусмысленности, поскольку и ExampleA, и ExampleB предоставляют этот метод, и компилятор не знает какой из них использовать.
interface ExampleA {
default void doSomething() {
System.out.println("Output of A");
}
}
interface ExampleB {
default void doSomething() {
System.out.println("Output of B");
}
}
public class ExampleC implements ExampleA, ExampleB {
@Override
public void doSomething() {
System.out.println("Output of C");
}
public static void main(String args[]){
ExampleC example = new ExampleC();
example.doSomething();
}
}
Приведенный выше код без переопределённого метода doSomething() в ExampleC сгенерирует эту ошибку:
class ExampleC inherits unrelated defaults for doSomething() from types ExampleA and ExampleB
Но достаточно переопределить doSomething() в ExampleC и компилятор сразу поймёт что от него хотят:
Output of C
Факт: начиная с JDK 8 доступно множественное наследование поведения.
Миф 9: Интерфейсы не могут содержать методы с реализацией
Статические методы и default-методы сняли это ограничение с Java, теперь можно легко поместить реализацию в интерфейс.
Как вы можете видеть в приведенном выше примере кода, оба интерфейса ExampleA и ExampleB содержат метод, выполняющий код.
Факт: это уже не так, и интерфейсы могут содержать методы с реализацией.
Заключение
С момента перехода на шестимесячный цикл релизов в 2018 году язык и инструменты Java претерпели множество изменений Одни фичи находятся «под капотом» и служат для повышения производительности и улучшения использования памяти, в то время как другие ориентированы на упрощение написания и поддержку кода. Так же не забываем и про prewiew-фичи!
Список фич можно посмотреть тут. Особенно любопытен раздел "Draft and submitted JEPs".