JavaRush /Java блог /Random /Кофе-брейк #37. Новое будущее для Java. JVM, Kotlin и пер...

Кофе-брейк #37. Новое будущее для Java. JVM, Kotlin и перспективы Java после 2020 года

Статья из группы Random
Источник: Medium В основном Java критикуют за две вещи: многословность и количество шаблонного кода, который генерируется во многих случаях без явной необходимости. Хоть мне всегда нравилась Java, я не могу сказать, что эти утверждения ошибочны. Это действительно правда: излишняя детализация в Java может иногда сильно раздражать. Однако мы должны признать, что живем не в идеальном мире, и в большинстве случаев нам приходится выбирать меньшее из двух зол.Кофе-брейк #37. Новое будущее для Java. JVM, Kotlin и перспективы Java после 2020 года - 1Со времен создания Java не была идеальной: мы все это знаем, но главный вопрос заключается в том, почему раньше ничего не делали для решения этих проблем. Мне кажется, единственная причина, по которой изменения заняли так много времени, заключается в том, что языку Java не хватало конкуренции, и все было так, как было. Java доминировала на рынке, вероятно, из-за отсутствия серьезных конкурентов и больших усилий, предпринятых сначала Sun, а затем Oracle. Высокий уровень безопасности типов, который обеспечивается Java, и хорошая структуризация языка сделали его очень популярным для крупных проектов. Кроме того, это мультиплатформенный язык, работающий на собственной виртуальной машине. Если еще учесть автоматическую оптимизацию производительности с помощью JIT-компилятора, все это сводит к минимуму влияние плохо написанного кода. В общем, получается довольно веский набор причин для использования Java. Но что случилось потом? Произошло то, что на рынке появились новые языки, способные работать в той же JVM, что и Java. Языки, которые устраняли некоторые из самых больших неудобств в Java и в ряде случаев предлагали разработчикам более приятную среду в меньшим порогом вхождения. Прежде чем мы продолжим, давайте подведем итоги и сделаем краткий экскурс в историю языков JVM.

История языков JVM

Для начала я бы хотел прояснить одну вещь: я не упомянул некоторые из существующих языков JVM потому, что у них никогда не было достаточной поддержки, чтобы считаться кандидатами для широкого использования в нашей отрасли. А теперь начнем наш краткий обзор истории языков JVM. Первым у нас будет язык Java — самый старый и самый популярный язык в мире JVM. Официально Java выпущена в январе 1996 года, так что язык существует уже 24 года. Неплохо, да? Первоначально Java была сугубо императивным языком, который следовал объектно-ориентированному стилю программирования; это также был строго типизированный язык. Синтаксис Java в некоторой степени похож на языки C ++ и C, но он считается улучшенной версией, поскольку на Java писать код намного проще, чем на C или C ++. С другой стороны, у нас есть самый большой аргумент среди его недоброжелателей — многословность (verbosity). Вторым языком JVM был Groovy. Он существует с 2003 года, хотя его первая стандартизованная версия 1.0 появилась только в январе 2007 года. Преимущество Groovy в том, что его можно использовать в качестве языка сценариев. Groovy — это язык с динамической типизацией, поэтому проверка типов выполняется во время выполнения. Это одна из причин, почему некоторым разработчикам не нравится Groovy. Вы пишете свой код на Groovy, и во время компиляции он выглядит правильно, но затем во время выполнения вы понимаете, что что-то не так. Затем появился еще один популярный язык: мы говорим о Scala. Его выпустили в 2004 году. Он принес в мир JVM новую модель работы: функциональное программирование и декларативный подход. В общем-то, Scala был первым языком, где появилась концепция неизменяемости, которая затем использовалась в усовершенствовании Java. С другой стороны, недоброжелателям Scala не нравится из-за сложной грамматики и достаточно низкой читаемости. Следующим языком, который появился в мире JVM, был Clojure, чисто функциональный язык. Он стал довольно популярным в последнее время, хоть появился еще в 2007 году. Clojure — это язык на основе LISP, отличающийся простотой и использованием простых функций. Среди его недостатков можно упомянуть то, что он динамически типизирован (как и Groovy), а кривая обучения намного круче, поскольку его синтаксис полностью отличается от других языков JVM. И наконец, у нас есть Kotlin. Kotlin впервые появился в феврале 2016 года, и с тех пор его популярность не переставала расти. Он разработан компанией JetBrains с главной целью: устранить самые известные проблемы Java. По своему замыслу Kotlin сохранил все достоинства Java, но в то же время решил многие проблемы. Это самые важные языки JVM. Как я уже сказал, мы пропустили некоторые другие языки, которые не столь популярны: Jython, JRuby, Ceylon, Fantom и т.д. При желании, вы можете узнать весь список существующих языков JVM в Википедии. Наверное, вы уже поняли, что у Java не было особых конкурентов в первые восемь или десять лет после создания, но с тех пор все изменилось. Итак, конкуренция — это хорошо или плохо?

Преимущества растущей конкуренции

Java не сильно изменилась за первые годы своего существования. Вероятно, потому, что в этом не было необходимости. Этот язык широко использовался и всегда был очень популярен, несмотря на то, что он далек от совершенства. Но затем появились конкуренты, более современные языки, которые предлагали новые функции и решали некоторые проблемы, от которых Java-разработчики страдали долгое время. Например, давайте посмотрим на язык Scala. Популярность Scala росла с 2009 года. Разработчики приветствовали этот новый функциональный стиль, который дал им большую гибкость, а также возможность безопасно и легко писать параллельный код. Как Oracle отреагировала на эту новую тенденцию? В 2014 году появились Java Lambdas и Streams. Я думаю, мы все можем согласиться, что именно тогда Java сделала свой самый большой шаг к победе над Scala. Сейчас любой программист знает, что Scala уже не в тренде.Кофе-брейк #37. Новое будущее для Java. JVM, Kotlin и перспективы Java после 2020 года - 2Еще одно преимущество большего числа конкурентов в мире JVM — постоянные улучшения, которые вносят в компилятор JIT и JVM. Теперь намного больше людей заинтересованы в оптимизации JVM и улучшении производительности. Так что конкуренция — это хорошо для всех! Самой свежей альтернативой Java стал язык Kotlin. Его появление стало очень важным для развития Java, поскольку новый язык в некотором смысле указал Oracle путь вперед. Пример Kotlin показал, что можно сохранить плюсы Java, но создать более компактный язык, на котором быстрее писать код. Если посмотреть на график Google Trends, можно увидеть, что с 2016 по 2018 года популярность Kotlin стремительно росла. Но за последние два года ажиотаж упал.Кофе-брейк #37. Новое будущее для Java. JVM, Kotlin и перспективы Java после 2020 года - 3Компания Oracle внимательно изучила реакцию отрасли на Kotlin. Если вы посмотрите примечания к выпуску JDK 15, вы увидите, что некоторые из новых функций Java являются копиями того, что появилось в Kotlin. Это новые записи Java, новые текстовые блоки (многострочные строки с тройными кавычками) и новый оператор switch, который по сути является копией оператора when в Kotlin. Все, о чем мы говорили, я называю «котлинизацией Java». Став более сильным конкурентом, Kotlin указал Java путь, по которому нужно идти.

«Котлинизация» Java

Некоторые из будущих функций Java станут значительным улучшением с точки зрения читабельности и устранения одной из самых слабых сторон языка Java — его многословности. Можно утверждать, что многие анонсированные функции Java подозрительно похожи на некоторые функции Kotlin. Но учтите, что большинство из них являются предварительными версиями. Это означает, что если вы установите JDK 14 или JDK 15 (когда его выпустят), вы не сможете использовать их по умолчанию. Превью функций Java — это новые функции, которые представлены в релизе, но по умолчанию отключены. Они включены в новую версию только для того, чтобы собрать отзывы сообщества разработчиков, поэтому они все еще могут быть изменены. Вот почему не рекомендуется использовать их в рабочем коде. Чтобы включить их во время компиляции, вам нужно будет сделать следующее:

javac --enable-preview --release 14
Если вы хотите включить их во время выполнения, вам нужно будет запустить следующее:

java --enable-preview YourClass
Конечно, вы также можете включить их в своей среде IDE, но будьте осторожны, чтобы не включать предварительный просмотр по умолчанию во всех ваших новых проектах! Давайте посмотрим на те изменения, которые окажут большее влияние на наш кодинг в будущих версиях Java.

Записи Java

Записи Java — это функция, которую многие из нас давно требуют. Я предполагаю, что вы оказывались в ситуации ситуации, когда вам требовалось реализовать toString, hashCode, equals, а также геттеры для каждого существующего поля. В Kotlin для решения этой проблемы есть классы данных, и Java намеревается сделать то же самое, выпуская классы записей, которые уже есть в Scala в виде case classes. Основная цель этих классов — хранить неизменяемые данные в объекте. Давайте на примере посмотрим, насколько лучше может стать Java. Вот сколько кода нам пришлось бы написать, чтобы создавать и сравнивать наш класс Employee:

package com.theboreddev.java14;

import java.util.Objects;

public class Employee {
    private final String firstName;
    private final String surname;
    private final int age;
    private final Address address;
    private final double salary;

    public Employee(String firstName, String surname, int age, Address address, double salary) {
        this.firstName = firstName;
        this.surname = surname;
        this.age = age;
        this.address = address;
        this.salary = salary;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getSurname() {
        return surname;
    }

    public int getAge() {
        return age;
    }

    public Address getAddress() {
        return address;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return age == employee.age &&
                Double.compare(employee.salary, salary) == 0 &&
                Objects.equals(firstName, employee.firstName) &&
                Objects.equals(surname, employee.surname) &&
                Objects.equals(address, employee.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, surname, age, address, salary);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "firstName='" + firstName + '\'' +
                ", surname='" + surname + '\'' +
                ", age=" + age +
                ", address=" + address +
                ", salary=" + salary +
                '}';
    }
}
А также объект Address, который он содержит:

import java.util.Objects;

public class Address {
    private final String firstLine;
    private final String secondLine;
    private final String postCode;

    public Address(String firstLine, String secondLine, String postCode) {
        this.firstLine = firstLine;
        this.secondLine = secondLine;
        this.postCode = postCode;
    }

    public String getFirstLine() {
        return firstLine;
    }

    public String getSecondLine() {
        return secondLine;
    }

    public String getPostCode() {
        return postCode;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(firstLine, address.firstLine) &&
                Objects.equals(secondLine, address.secondLine) &&
                Objects.equals(postCode, address.postCode);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstLine, secondLine, postCode);
    }

    @Override
    public String toString() {
        return "Address{" +
                "firstLine='" + firstLine + '\'' +
                ", secondLine='" + secondLine + '\'' +
                ", postCode='" + postCode + '\'' +
                '}';
    }
}
Наверное, тут слишком много кода для чего-то такого простого, не так ли? Давайте теперь посмотрим, как это будет выглядеть с новыми записями Java:

public record EmployeeRecord(String firstName, String surname, int age, AddressRecord address, double salary) {
}
И еще не забудем класс Address:

public record AddressRecord(String firstLine, String secondLine, String postCode) {
}
Это то же самое, что мы написали ранее с таким большим количеством кода. Согласитесь: это потрясающе. И количество кода, которое мы собираемся cэкономить, и простота написания! Давайте теперь посмотрим, в чем отличия нового оператора switch.

Улучшенный оператор switch

Новый оператор switch в Java решит часть старых проблем, включая некоторые ошибки и дублирование кода. С новым оператором switch эта проблема будет решена. Чтобы объяснить это на примере, мы собираемся создать перечисление DayOfTheWeek на Java:

public enum DayOfTheWeek {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
После этого наш switch сообщит нам, какая позиция на неделе соответствует этому дню. Давайте сначала посмотрим, как мы можем сделать это в настоящее время, используя Java 11.

final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = 0;

        switch (dayOfTheWeek) {
            case MONDAY:
                position = 1;
                break;
            case TUESDAY:
                position = 2;
                break;
            case WEDNESDAY:
                position = 3;
                break;
            case THURSDAY:
                position = 4;
                break;
            case FRIDAY:
                position = 5;
                break;
            case SATURDAY:
                position = 6;
                break;
            case SUNDAY:
                position = 7;
                break;
        }

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
С текущим оператором switch нам нужно будет использовать переменную, и если мы пропустим один из дней недели, наш код будет отлично компилироваться. Это одна из проблем операторов switch: они слишком подвержены ошибкам. Так как же Java 14 улучшает ситуацию? Давайте посмотрим:

final DayOfTheWeek dayOfTheWeek = DayOfTheWeek.THURSDAY;

        int position = switch (dayOfTheWeek) {
            case MONDAY -> 1;
            case TUESDAY -> 2;
            case WEDNESDAY -> 3;
            case THURSDAY -> 4;
            case FRIDAY -> 5;
            case SATURDAY -> 6;
            case SUNDAY -> 7;
        };

        System.out.println("Day " + dayOfTheWeek + " is in position " + position + " of the week");
Как видите, новые операторы switch могут использоваться как выражение, а не только как оператор. Результат более лаконичный и выразительный. Этого было бы достаточно, чтобы убедить многих из нас использовать их, но одно из основных улучшений состоит в том, что теперь операторы switch не будут компилироваться, если мы не охватим все случаи в нашем switch. Он покажет нам вот такую ошибку, например:

Error:(9, 24) java: the switch expression does not cover all possible input values
Отныне в наших операторах switch пропустить регистр будет невозможно. Это очень похоже на операторы when в Kotlin, о которых вы можете прочитать в документации. Давайте также взглянем на новые текстовые блоки.

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

Вы когда-нибудь жаловались на то, как сложно присвоить большой двоичный объект JSON переменной в Java? В Java есть многострочные последовательности, которые вы можете описать, заключив их в тройные кавычки. Когда эта функция будет официально выпущена, станет намного проще описывать длинные последовательности в несколько строк. Давайте посмотрим на различия между двумя режимами. Если мы хотим использовать отформатированный JSON в переменной, получается плохо:

final String text = "{\"widget\": {\n" +
                "    \"debug\": \"on\",\n" +
                "    \"window\": {\n" +
                "        \"title\": \"Sample Konfabulator Widget\",\n" +
                "        \"name\": \"main_window\",\n" +
                "        \"width\": 500,\n" +
                "        \"height\": 500\n" +
                "    },\n" +
                "    \"image\": { \n" +
                "        \"src\": \"Images/Sun.png\",\n" +
                "        \"name\": \"sun1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 250,\n" +
                "        \"alignment\": \"center\"\n" +
                "    },\n" +
                "    \"text\": {\n" +
                "        \"data\": \"Click Here\",\n" +
                "        \"size\": 36,\n" +
                "        \"style\": \"bold\",\n" +
                "        \"name\": \"text1\",\n" +
                "        \"hOffset\": 250,\n" +
                "        \"vOffset\": 100,\n" +
                "        \"alignment\": \"center\",\n" +
                "        \"onMouseUp\": \"sun1.opacity = (sun1.opacity / 100) * 90;\"\n" +
                "    }\n" +
                "}} ";
С другой стороны, когда выпустят новые текстовые блоки, все станет намного проще:

final String multiLineText = """
                {"widget": {
                    "debug": "on",
                    "window": {
                        "title": "Sample Konfabulator Widget",
                        "name": "main_window",
                        "width": 500,
                        "height": 500
                    },
                    "image": {\s
                        "src": "Images/Sun.png",
                        "name": "sun1",
                        "hOffset": 250,
                        "vOffset": 250,
                        "alignment": "center"
                    },
                    "text": {
                        "data": "Click Here",
                        "size": 36,
                        "style": "bold",
                        "name": "text1",
                        "hOffset": 250,
                        "vOffset": 100,
                        "alignment": "center",
                        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
                    }
                }}
                """;
Это явно выглядит лучше. Всё это уже поддерживается в Kotlin, как вы можете увидеть в определениях его типов. Итак, мы увидели, что Java «наследует» многие решения собственных проблем от одного из своих конкурентов: Kotlin. Мы не знаем, вовремя ли отреагировал Oracle на борьбу с ростом популярности Kotlin или, может быть, это произошло слишком поздно. Лично я считаю, что Java делает правильные шаги вперед, даже если эти изменения каким-то образом были инициированы ее конкурентами и могут произойти с некоторым опозданием.

Вывод

Я считаю, что конкуренция — лучшее, что когда-либо случалось с языком Java. У меня сложилось впечатление, что иначе Java почила бы на лаврах. Кроме того, конкуренты Java показали, что возможен другой способ программирования, показывающий, как двигаться вперед и избегать устаревших и неэффективных способов написания кода. Будущие изменения сделают язык Java более мощным, чем когда-либо, языком, адаптированным к современной эпохе, языком, который хочет развиваться.
Комментарии (7)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Джон Дориан Уровень 37
18 августа 2020
"Сейчас любой программист знает, что Scala уже не в тренде." Расскажите это Big Data разработчикам, лол
15 августа 2020
С kotlin познакомился ещё в 2017 году и его синтаксический сахар оказался очень вкусным, так что рекомендую, кто ещё не познакомился с этим языком программирования! )))
Roman Beekeeper Уровень 35
14 августа 2020
Личный вывод из этой статьи: чтобы подготовиться на новую джаву, нужно выучить котлин)
Роман Уровень 24
13 августа 2020
"и новый оператор switch, который по сути является оператора when в Kotlin." В предложении пропущено слово "копией".
Fischerski Уровень 22
13 августа 2020
Ладно, убедили, а то были мысли начинать учить Kotlin)