Рубрики
Без рубрики

Новейшая Java – Улучшенное переключение и вывод локальных типов

Вступление Большинство предприятий и компаний, использующих Java, все еще работают на Java 7 или 8… Помеченный java, jep, функциями.

Вступление

Большинство предприятий и компаний, использующих Java, все еще работают на Java 7 или 8.

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

Это также означает, что запуск в Java 8 (который был выпущен во всем мире в марте 2014 года – это почти 6 лет назад) постепенно становится “слишком” устаревшим, и все же, благодаря внедрению API Streams, он выглядит намного современнее по сравнению с Java 7, он позволяет командам и разработчикам согласовывать более функциональный дизайн внутренней работы своих объектов, и это было столь необходимое улучшение языка, который великолепен и используется во всем мире, номер 1 в индексе TIOBE, и все же, был встречен все большим количеством критики и скептицизма пользователями конкурирующих технологий, таких как Kotlin и Scala, например.

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

Вывод типа локальной переменной

Эта функция связана с JEP 286 – Вывод типа локальной переменной и JEP 323 – Синтаксис локальной переменной для лямбда-параметров и это позволяет использовать новое зарезервированное ключевое слово var для выполнения вывода типа локальной переменной.

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

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List someNames = getSomeNames();
        System.out.println(someNames);
    }

    public static List getSomeNames() {
        return new ArrayList<>(Arrays.asList("Ann","John","Shelby"));
    }
}

Итак, мы видим, что когда мы объявляем переменную некоторые имена внутри нашей основной функции, нам нужно явно указать тип переменной как Список<Строка> . Идеи с их функциями автозаполнения также автоматически установят тип переменной как Список<Строка> .

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

В данном конкретном примере переменная должна иметь тип Список<Строка> потому что функция, возвращаемое значение которой присваивается этой переменной, относится к этому типу.

Что предлагает JEP 286, так это то, что для локальных переменных (и расширенных до лямбда-параметров) мы можем заставить компилятор выполнять вывод типа, т.Е. выводить тип для нас из контекста таким образом, чтобы теперь мы могли писать:

public class Main {

    public static void main(String[] args) {
        var someNames = getSomeNames();
        System.out.println(someNames);
    }

    public static List getSomeNames() {
        return new ArrayList<>(Arrays.asList("Ann","John","Shelby"));
    }
}

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

Как только мы попытаемся добавить новый элемент в список, вот что покажет автозаполнение в IntelliJ:

Итак, мы видим, что все доступные методы являются частью интерфейса List , который в точности соответствует типу возврата функции! Вывод типа работает.

Синтаксис локальной переменной для лямбда-параметров

Этот синтаксис также был расширен до параметров лямбда, чтобы обеспечить совместимость с выводом типа локальной переменной, описанным ранее.

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

Optional z = someNames.stream().reduce((a, b) -> a + b);

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

var z = someNames.stream().reduce((var a, var b) -> a + b);

Неявно типизированное лямбда-выражение должно использовать var для всех своих формальных параметров или ни для одного из них. Кроме того, var разрешен только для формальных параметров неявно типизированных лямбда-выражений — явно типизированные лямбда-выражения продолжают указывать типы манифеста для всех своих формальных параметров, поэтому некоторым формальным параметрам не разрешается иметь типы манифеста, в то время как другие используют var. Следующие примеры являются незаконными:

(var x, y) -> x.process(y)         // Cannot mix 'var' and 'no var' in implicitly typed lambda expression
(var x, int y) -> x.process(y)     // Cannot mix 'var' and manifest types in explicitly typed lambda expression

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

Улучшенный переключатель

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

Предложение по улучшению JEP 325: Выражения переключения (предварительный просмотр) значительно упростит работу с оператором switch за счет устранения “сквозного” поведения и обеспечения поддержки нескольких меток, разделенных запятыми, в одной метке переключателя.

В “старой Java” вот как мы могли бы написать оператор switch , чтобы сообщить нам об определенных днях недели:

public static void daysOfWeek(int day){
        switch (day) {
            case SATURDAY:
            case SUNDAY:
                System.out.println("weekend");
                break;
            case MONDAY:
                System.out.println("oh no! Monday");
                break;
            case FRIDAY:
            case TUESDAY:
            case THURSDAY:
            case WEDNESDAY:
                System.out.println("gotta work");
                break;
        }
    }

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

В новой Java вот как мы можем написать это:

public static void daysOfWeek(int day){
        switch (day) {
            case SATURDAY, SUNDAY -> System.out.println("weekend");
            case MONDAY -> System.out.println("oh no! Monday");
            case TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> System.out.println("gotta work");
        }
    }

Как мы видим, мы можем использовать новую форму метки переключения, написанную “регистр L ->”, чтобы указать, что только код справа от метки должен выполняться, если метка совпадает.

Это обеспечивает гораздо более компактную инструкцию переключения, более легкую для чтения и более близкую по дизайну к соответствию шаблону!

Мы также можем назначать выражения переключения переменным, таким как:

public static String daysOfWeek(int day){
        return switch (day) {
            case SATURDAY, SUNDAY -> "weekend";
            case MONDAY -> "oh no! Monday";
            case TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> "gotta work";
            default -> "";};
    }

Обратите внимание, что нам нужна рука соответствия по умолчанию в случае, если пользователь вводит целое число, которое не распространяется на другие случаи. Это очень похоже на конструкции сопоставления с образцом, такие как _ -> языки, такие как, например, Haskell.

И это все!

Вывод

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

PS: Если вам это понравилось, я могу просмотреть будущие JEPs!

Оригинал: “https://dev.to/brunooliveira/bleeding-edge-java-improved-switch-and-local-type-inference-1do7”