10 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Первый контакт с «var» в Java 10

Soft, интернет, безопасность: новости, статьи, советы, работа

Избранное сообщение

Фетісов В. С. Комп’ютерні технології в тестуванні. Навчально-методичний посібник. 2-ге видання, перероблене та доповнене / Мои публикации

В 10-х годах я принимал участие в программе Европейского Союза Tempus “Освітні вимірювання, адаптовані до стандартів ЄС”. В рамк.

понедельник, 8 января 2018 г.

Первый контакт с «var» в Java 10 / Хабрахабр / Программирование на Java

Java 10 будет выпущен 20 марта 2018 года , и все фичи, которые должны быть в этом релизе, уже объединены в основную ветку разработки. Одним из самых интересных нововведений Java 10 безусловно является вывод типа локальной переменной ( JEP 286 ). Это дает вам возможность сократить объявления переменных используя новое ключевое слово var :

И это все, спасибо за внимание!

Нет, я уверен, что вам интересно узнать больше. Под катом я расскажу, где применяется var , а где нет, как это влияет на читаемость кода и что произошло с val .

Замена объявлений типа с помощью var

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

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

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

Начиная с Java 10 у разработчиков появится альтернатива — они могут позволить компилятору вывести тип с помощью var :

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

Как вы видите, это экономит несколько символов при наборе текста, но, что более важно, он дедуплицирует избыточную информацию и аккуратно выравнивает имена переменных, что облегчает их чтение. Стоимость очевидна: некоторые типы переменных, например connection, не сразу очевидны. IDE могут, конечно же, показывать их по требованию, но это не помогает ни в какой другой среде (например, при просмотре кода в браузере — на stackoverflow или даже в этой статье — прим. перев.) .

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

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

  • хм, это Java или JavaScript?
  • где я могу это использовать?
  • не ухудшится ли читаемость кода?
  • почему не val или let?

Давайте рассмотрим их подробней.

Нет, это не JavaScript

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

Например, вот результат декомпиляции IntelliJ (фактически Fernflower) файла класса с примером URL:

Это байт в байт тот же результат, как если бы я сам объявил типы. Фактически вывод типов существует только во время компиляции и никак не влияет на итоговый байт-код, что также означает отсутствие какого-либо влияния на производительность. Так что расслабьтесь, это не Javascript, и никто не собирается превращать 0 в бога .

Если вы все еще обеспокоены тем, что отсутствие явных типов делает код хуже, у меня есть вопрос для вас: вы когда-нибудь писали лямбда-выражения, не определяя типы аргументов?

Где использовать var (и где не нужно)

Название JEP 286, «вывод типа локальной переменной», немного намекает на то, где var можно использовать: для локальных переменных. Точнее, для «локальных объявлений переменных с инициализаторами», так что следующий код работать не будет:

Код должен быть таким: var foo = ”Foo” . Даже тогда это распространяется не на все случаи, так как var не будет работать с так называемыми «poly expressions», такими как лямбда-выражения и ссылки на методы, тип которых компилятор определяет в отношении ожидаемого типа:

Единственное подходящее место, помимо локальных переменных — это цикл for :

Это означает, что поля, сигнатуры методов и выражения catch все еще требуют ручного объявления типа.

Читать еще:  Мобильный телефон lenovo vibe z k910. Обзор Lenovo Vibe Z - скорострельный флагман

Устранение ошибок «Действие на расстоянии»

То, что var может использоваться только локально, является не техническим ограничением, а конструктивным решением. Конечно, было бы неплохо, если бы он работал так:

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

В качестве примера рассмотрим следующее:

Пока что всё идёт… Я не хочу говорить «хорошо», но вы знаете, что я имею в виду. Я уверен, что вы видели такой код. Теперь добавим эту строку:

Что произойдет? Это не риторический вопрос, подумайте об этом.

Ответ заключается в том, что if-условие вызывает ошибку, потому что id больше не будет int и поэтому не может сравниться с 100 . Эта ошибка находится на довольно большом расстоянии от изменения, вызвавшего ее. Кроме того, это непредвиденное следствие простого присваивания значения переменной.

С этой точки зрения, решение ограничить вывод типа до непосредственного объявления имеет смысл.

Почему не могут быть выведены типы полей и методов?

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

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

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

Предпосылки появления var

Давайте посмотрим за кулисы и узнаем, почему был введен var , как он должен повлиять на читаемость и почему нет val (или let ), сопровождающего его. Если вас интересует наиболее подробная информация, посмотрите дискуссии JEP 286 , часто задаваемые вопросы и список рассылки Project Amber .

Но зачем?!

Java склонна быть довольно многословной, особенно по сравнению с более молодыми языками, это является одним из слабых мест языка и общей темой для критики новичками и опытными разработчиками Java. Project Amber , в рамках которого был разработан var , направлен на «изучение и инкубацию небольших, ориентированных на продуктивность разработки функций Java-языка», и цель состоит в том, чтобы в целом сократить рутину, связанную с написанием и чтением кода на Java.

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

Помимо упрощения объявлений это также делает их более податливыми. Что я имею в виду? Объявления могут быть довольно уродливыми, особенно если речь идет о названиях обобщённых классов в корпоративных приложениях.

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

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

Короче говоря, var — это про сокращение многословия и рутины, а не об экономии символов.

А что относительно читаемости?

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

Таким образом, var сразу приносит нам недостаток читаемости и должен компенсировать это. Один из способов — выравнивание имен переменных:

Имена типов важны, но имена переменных могут быть важнее. Типы описывают общую концепцию в контексте всей экосистемы Java (для классов JDK), общий вариант использования (библиотека или фреймворк) или бизнес-домен (приложение) и, следовательно, всегда будут иметь общие имена. Переменные, с другой стороны, определены в конкретном и очень малом контексте, в котором их имя может быть очень точным.

Читать еще:  Как восстановить удаленную учетную запись (профиль, аккаунт) пользователя Google

С var имена переменных выходят на первый план и выделяются так, как раньше этого не делали, особенно если подсветка кода отмечает ключевое слово и, таким образом, позволяет инстинктивно игнорировать его. Я какое-то время проводил час или два в день, читая Kotlin, и я тут же привык к этому. Это может значительно улучшить читаемость.

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

Поиск стиля

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

Брайан Гетц (Brian Goetz), архитектор языка Java в Oracle и ответственный за Project Amber, дал первую эвристику:
Используйте конструкцию var, когда она делает код более понятным и более кратким, и вы не теряете существенную информацию. В связи с этим я надеюсь, что IDE не будут вообще предупреждать нас, если объявление типа может быть заменено на var . Это не универсальная конструкция, как лямбда-выражения.

Почему нет val/let?

Многие языки с var также предлагают дополнительное ключевое слово для неизменяемых переменных. Обычно это называется val , иногда let , но Java 10 не имеет ни того, ни другого, и вместо этого мы должны использовать final var . Вот несколько причин:

  • неизменяемость важна, но для локальных переменных она важна в меньшей степени
  • начиная с Java 8 у нас есть концепция эффективного final, уже и без того приближающая нас к неизменяемым локальным переменным
  • там, где var получил всеобщее одобрение (74% категорически, 12% умеренно) ответная реакция как на var / val, так и на var / let была весьма неоднозначной

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

Чтож, возможно в будущем… До тех пор мы должны использовать final var .

Подводя итоги

При объявлении локальных переменных вы можете использовать var вместо имени класса или интерфейса, чтобы позволить компилятору вывести тип. Это работает только в том случае, если переменная немедленно инициализируется, например, как в var s = “” . Индексы для циклов также могут быть объявлены с помощью var . Тип, выводимый компилятором, помещается в байт-код, поэтому во время выполнения ничего не меняется — Java все еще является статически типизированным языком.

Помимо локальных переменных, например в полях и сигнатурах методов, var не может применяться. Это было сделано, чтобы избежать ошибок «действия на расстоянии» и сохранить место использования выведенной переменной рядом с местом объявления, что смягчает опасения, связанные с читабельностью.

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

Первый контакт с «var» в Java 10

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

Это не то что мы хотим. Тут слишком сложно отследить ошибку, поскольку код, содержащий часть forEach (), не находиться рядом с кодом, в который были внесены изменения. Чтобы увеличить скорость поиска и исправления ошибок, гораздо лучше писать код, использующий переменную stack, как можно ближе к объявлению этой переменной.

Лучше всего это делать так:

Мы можем использовать разные типы операндов в правой части тернарного оператора.

При явном указании типов следующий код не скомпилируется:

Из этих примеров не следует, что тип var определяет типы объектов во время выполнения. Это не так!

И, конечно, тип var будет корректно работать при одинаковых типах обоих операндов:

Читать еще:  Почему не активируется imessage на iphone 5s?

Мы легко можем заменить явное объявление типов в циклах for на тип var.

Изменение явного типа int на var:

Очень просто использовать var из Java 10 с потоками (stream), которые появились в Java 8.

Вы можете просто заменить явное объявление типа Stream на var:

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

«Жизнь после Java 10»: какие изменения принесет Java 11

Буквально недавно, в конце марта, вышел Java 10. Но в связи с тем, что компания Oracle внесла изменения в релизный цикл (новый релиз каждые полгода), к выходу готовится 11-я версия.

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

Java 10: краткая сводка

Нововведениями десятой версии стали: локальный вывод типов с помощью var, улучшения в процессах «сборки мусора» и возможность использовать Graal как основной JIT-компилятор.

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

Однако решение ввести var получило неоднозначные отзывы участников сообщества. Кто-то высказывался за нововведение и говорил, что дедупликация повышает читабельность кода. Но были и те, кто отмечал, что теперь ряд типов переменных (например, connection) не будут очевидными. И хотя IDE теперь смогут показывать их по требованию, в других средах будут возникать проблемы.

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

Что касается нового JIT-компилятора, то он направлен на улучшение производительности JVM. Прежняя версия JVM была написана на C++, однако в рамках проекта Metropolis большую часть JVM перепишут на Java. Экспериментальный компилятор является первым шагом на пути к этой цели.


/ фото Betsy Weber CC

Возможные нововведения в Java 11

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

Часть разработчиков недовольна тем, как быстро меняется язык. Один из резидентов Hacker News сказал: «Java превращается в совершенно новый язык. Одна из причин, почему я раньше использовал Java — это обратная совместимость. Если придется учить новый язык программирования каждые 6 месяцев, я выучу что-нибудь другое».

Но есть и те, кто отмечает, что Java наконец-то обзаводится функциями, которых ему не хватало, и которые уже давно были реализованы в других ЯП. Еще один пользователь HN пишет: «Я не использовал Java с начала нулевых и удивлен, что они так долго вводят фичи, которые давно существуют в других языках». Вот некоторые из них.

Изменения в локальном выводе типов

Java 10 уже предоставил возможность использовать var для обозначения типа локальных переменных, перекладывая эту задачу на плечи компилятора. Однако Java 11 идет дальше и делает так, что var можно использовать при объявлении формальных параметров неявно типизированных лямбда-выражений.

За подробным руководством о том, когда и как использовать var, можно обратиться к этой статье на OpenJDK.

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

Это еще одно дополнение, над которым сейчас ведется работа. В необработанной строке каждый символ читается «как есть», включая символы разрыва. Например, такой строкой может быть разметка HTML или SQL-запрос:

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

Для обозначения необработанной строки используется обратный апостроф (`). Если вам нужно прописать апостроф внутри самой строки, то в этом случае для маркировки её границ используются двойные (или тройные, четверные и т. д.) обратные апострофы:

Появятся switch-выражения

Сейчас оформление switch выполняется следующим образом:

С появлением switch-выражений, конструкция сократится:

При этом если в case встречается только break, возможно использовать упрощенную нотацию:

Добавление switch expressions — это шаг вперед на пути к появлению метода сопоставления с образцом.

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

голоса
Рейтинг статьи
Ссылка на основную публикацию
Статьи c упоминанием слов: