24 марта 2016 в 13:39

Ключевое слово «var» в Java: пожалуйста, только не это из песочницы

Ключевое слово var

Прошедшее 8-е марта для разработчиков Java выдалось особенно насыщенным. Причиной тому послужил новый JEP 286: Local-Variable Type Inference, который предлагает ввести ключевое слово var, избавляя нас от необходимости явно указывать тип локальной переменной:

var unbufOut = NetUtils.getOutputStream(sock);

вместо

OutputStream unbufOut = NetUtils.getOutputStream(sock);

А на днях подоспели и результаты опроса разработчиков, которые недвусмысленно показали — var в Java быть. Хорошо это или плохо?

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

No god please no

Я решил разобраться, почему этот JEP вызывает у меня отторжение.

Почему «нет»


Java всегда была и остается достаточно консервативной платформой. Иногда этот консерватизм реально ограничивает пользователей. Нашумевшая история с выпиливанием Unsafe, проникновение которого во многом есть результат игнорирования нарастающей потребности в низкоуровневом API, — ярчайший тому пример.

Консервативность языка, напротив, давала Java ряд преимуществ. Во-первых, это низкий порог вхождения. Базовый синтаксис языка очень компактен, и прост в изучении. Во-вторых, это экспрессивность. Языки, напичканные всевозможными фишечками, вроде Scala и C#, позволяют писать совершенно нечитаемые конструкции. Смешайте лямбды, type inference и имплицитный return, и читателям вашего кода придется хорошенько напрячься. В Java написать нечитаемый код значительно сложнее.

Отсюда и главная претензия к var — риск снижения читабельности. На практике мы «понимаем» код во многом благодаря трем составляющим: типы переменных, имена переменных, и имена методов. Повсеместное (а в худшем случае — бездумное) использование var, уничтожит первую из них. Для поддержания читабельности на том же уровне, придется больше внимания уделять именам методов, так как их вклад в восприятие кода значительно возрастет.


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

Люди пишут в опроснике:
Scope is small, so will only give more confussion to new developers. The typing of the boiler plate is tackled by decent IDEs.
We have IDEs so I don't care

В комплексе все это делает преимущества type inference достаточно сомнительными.

Особенно непросто придется любителям разработки «в блокноте». Существует мнение, что данный аргумент высосан из пальца, так как все пользуются IDE, а условный «notepad» — это удел фриков, неадекватных работодателей и джуниоров, пишущих свой первый «Hello, world!». Это не совсем так. IDE — это инструмент работы с кодом. Но сам код находится в других местах: в файлах, в mail-листах, в баг-трекерах, на форумах, и так далее. Когда вы открываете JIRA-тикет с куском кода, Вы сначала читаете его в браузере, верно? Поэтому чтение кода вне среды разработки — совершенно нормальная и распространенная практика, которой занимаются едва ли не все разработчики. Есть вполне обоснованные опасения, что var этот процесс затруднит.

I'm not sure if it will not increase the difficulty of code review
I code both in Java and C# and sometimes and need to work with C# code where people have used var. It makes it a lot harder to see the type of a variable for no or very little gain.

Почему «да»


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

Для аналогии вспомним ООП. При правильном использовании это невероятно полезный и мощный инструмент. Поэтому ООП везде. При этом код инженера, который только-только закончил читать Gang Of Four, лучше обходить стороной. Он будет чрезмерно сложным и перегруженным. И только через некоторое время, после того, как человек набьет руку в проектировании, ООП начинает давать свои плоды.

С развитием языка ситуация ровно та же. Появляется новый инструмент. Какое-то время люди учатся, притираются, делают ошибки. Появляются новые тренды и подходы, которые находят своих сторонников и противников. Наконец, образуются устоявшиеся практики, которые применяют в конкретных проектах.

Поэтому до начала массового использования var, достаточно сложно сказать, насколько много проблем и неудобств оно принесет. Но мы можем обратиться к языкам, которые уже имеют type inference — C++, C#, Scala… давайте иначе — а в каком известном вам мейнстримовом языке этого нет? Лично у меня нет информации о том, чтобы какой-то язык серьезно пострадал от type inference. Кто-то пользуется, а кто-то нет, кому-то нравится, а кому-то нет, вот и все.

Ради эксперимента я походил по кодовой базе Akkа и Spark. Намеренно искал места, в которых было бы сложно разобраться конкретно из-за type inference. Субъективно — не нашел. В подавляющем большинстве мест смысл переменной был легко понятен из контекста благодаря именам переменных и методов. По моим ощущениям, хороший код не пострадает. А вот плохой код может стать еще хуже. Ну и бог с ним.


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

Мне всегда было достаточно сложно понять мотивацию больших и сложных проектов, использующих JVM-based языки. Например, что получили Akka и Spark от использования Scala? Издержки очевидны — дополнительный барьер между продуктом и миллионами Java-разработчиков. А польза? Добавление новых фич, начиная с такой важнейшей вещи, как лямбды, и заканчивая относительно бесполезным var, позволит прекратить разброд и шатания, и вновь сконцентрирует комьюнити вокруг непосредственно Java. Это безусловный плюс.

Thanks so much! This will remove yet another death-by-a-thousand-cuts issues w Java that drive people to seek alternatives
Please simplifiy the Java language (and JavaEE in general)! Type inference is a great step into the right direction.

Итог


Исключительно субъективно: с точки зрения разработчика это «никакая» фича. Пользы мало, вреда мало. Но в целом для языка это однозначный шаг вперед. Один из многих, которых мы с нетерпением ждем:
Is there way to add union and intersection types in Java?
Could you consider the introduction of case classes (like in Scala)?
when do you expect primitive types be allowed in generics?
Remove getters and setters.
When will we have async/await feature in Java ( like c# and f# ) ?

Но лично я пользоваться var не хочу. Блокнот сподручнее.
Владимир Озеров @devozerov
карма
34,0
рейтинг –0,8
Пользователь
Самое читаемое Разработка

Комментарии (326)

  • +18
    В вашем примере, безусловно, использование var неуместно:
    var unbufOut = NetUtils.getOutputStream(sock);
    Но вот пример, в котором ему самое место:
    FileOutputStream fos = new FileOutputStream("t.tmp");
    В C# так сделано и это удобно.
    • –15
      А мне нравится использовать полные типы в строках вида
      SomeClass something = new SomeClass();
      
      потому что после того, как я написал левую половину, автодополнение дописывает за меня правую — мелочь, а приятно.
      • +12
        Наверное надо еще потребовать обязательного явного приведения типов :), чтобы вы писали
        Window windows = new
        А IDE вставляло еще больше избыточного кода
        Window window = (Window) new Window()
        • +3
          В IDE 4 опции:
          1) Отображать var v=new T(); как T v=new T();
          2) Автоматически преобразовывать var в типы
          + две обратные покроют
          все необходимые пожелания всех и каждого.

          Другое дело, что почти никто в настройки IDE не полезет, а вот на хабре холиварить будет часы напролет. И да. Я тоже так сделаю ;)
        • 0
          А это зачем? Не понял вашей логики.
          • +6
            Ну если человек испытывает удовольствие от того, что IDE дописывает избыточный код, который можно вообще не писать, язык должен предоставить ему больше удовольствия — требовать больше тупого дубрирования
      • +6
        Пишите: new SomeClass().var жмякаете таб — ИДЕ генерирует
        var something = new SomeClass(); с фокусом на названии переменной которую можете изменить.
        • 0
          Это ReSharper.
          • +2
            Только что проверил, Idea так же делает.
            • +3
              Так контора-разработчик одна.
        • 0
          Можно даже проще — нажать Ctrl+Alt+V сразу после выражения ("extract variable").
        • 0
          Это гениально. Я о таком даже не предполагал. Спасибо.
        • 0
          new SomeClass(); а потом Ctrl + Alt + V
          • +1
            Раскорячивать пальцы проще, чем написать var? :)
            • 0
              Так ведь Idea/Resharper довольно адекватные имена переменным дают.
      • +1
        А какой смысл, если вы уже написали левую половину (т.е. само имя класса и имя переменной)? С var вы напишите примерно столько же...
      • +1
        А я вообще люблю писать
        List<SomeClass> list = new ArrayList<SomeClass>();

        И var из той же оперы.
        • +2
          а var в этом случае будет List или ArrayList?
          • 0
            ArrayList
            • –1
              Ну вообще-то и List-ом, собственно, он тоже будет, не?
              • +1
                Будет, но выведется конкретный тип ArrayList. Если пытаться выводить до интерфейсов, то так можно дойти до вывода в Object.
                • +1
                  Ну это то понятно. Тем не менее неспроста (канонично) слева пишется List, а справа ArrayList. Т.к. ArrayList — это по сути указывается конкретная реализация контракта. Это было к "var из той же оперы" в основном сказано.
                  • 0
                    Как часто вам в локальном скопе метода важно сокрытие реализации контракта?
                    Если метод настолько большой, что это играет роль, то мне кажется, explicit/implicit тут уже не спасёт.
                    • 0
                      Как часто вам в локальном скопе метода важно сокрытие реализации контракта?
                      В локально скопе — не так уж часто. Я потому и написал про «канонично». Но я лично всегда так пишу и считаю хорошим тоном.
      • 0
        Если вы используете IntelliJ то вы делаете это неправильно — сначало нужно писать правую часть, нажать alt enter и enter(первый пункт всплывающего меню будет — introduce local variable).
      • 0
        Согласен тем, что при простом вызове конструктора проще использовать var. Ведь если писать полное имя типа в объявлении переменной IntelliSence всё равно будет подсказывать с нуля и придётся половину имени типа набирать.
        Если вспомнить, то var появился в C# 3.0 вместе с лямбдами и LINQ. И первую очередь он нужен именно там, чтобы не писать моструозные конструкции вроде: IEnumerable result =…
        В C++11 auto в целом тоже для тех же целей добавили (с ужасом смотрю на все эти шаблонные итераторы).
        • +2
          Нет. var в первую очередь нужен для работы с анонимными типами, к-ые логично появляются в LINQ при операции проекции (Select)
          • 0
            Да, согласен. Про проецирование я что-то забыл. В этом случае уже без var даже написать полное имя типа нельзя. Не знаю есть ли такое в Java, но с var может и оно появится )
    • 0
      Да, пожалуй случай когда NetUtils возвращает FileOutputStream это действительно весьма странный кейс, когда было бы неплохо увидеть, что тип переменной таки FileOutputStream.
      Но вообще для меня видится довольно странным заявление, что var приносит мало пользы и больше вреда. Это где-то аналогичное тому, что говорить что понижение типа это вредно (типа так: OutputStream unbufOut = NetUtils.getOutputStream(sock);). Зависит от случая к случаю.
      Вообще, в строке приведенной автором для примера я вижу две проблемы корректного именования и проблему того, что зачем-то метод возвращает максимально специфичный класс. Видать джависты не умеют в корректный нейминг и ООП.
      • 0
        Но вообще для меня видится довольно странным заявление, что var приносит мало пользы и больше вреда.

        В статье написано:
        Пользы мало, вреда мало.
    • +6
      Когда я вижу такое:
      var unbufOut = NetUtils.getOutputStream(sock);
      То мне не очень надо знать, какой именно тип представляет обой unbufOut (кстати, обясните, пожалуйста, кто дал такое имя переменной и какомй naming convention оно следует).
      Я уже вижу что это именно stream, скорее всего полученный по сокету. Для общего понимания алгоритма это должно быть не важно. Если мне понадобится знать тип, я просто наведу курсор на переменную.
      А если мне понадобится знать, что именно делает getOutputStream, я нажму f12 и не потребую к каждому вызову метода приписывать полный текст его реализации прямо в исходнике.
      • –6
        Если мне понадобится знать тип, я просто наведу курсор на переменную.
        А если мне понадобится знать, что именно делает getOutputStream, я нажму f12 и не потребую к каждому вызову метода приписывать полный текст его реализации прямо в исходнике.

        ТО есть часть статьи про "много работы ведется вне IDE" — вы проигнорировали.
        Я вот на днях закончил работу по протированию на Андроид 44 плагинов для проекта с исходниками примерно на 600 файлов. Все из которых я вынужден был редактировать в Notepad++ в силу специфики рабочего окружения.
        Куда мне в Notepad++ навести мышку чтобы узнать тип и где нажимать F12?
        • +2
          Тогда да, вам нужно объявлять типы (вместо наведения мышки) и рядом каждым вызовом функции писать ее полный текст в комментах (вместо F12).
          А что за особенности окружения?
          • –4
            "Мне" надо?
            Неужели вы думаете, что программисты только со своим кодом работают?
            • 0
              Ну значит вам нужно чтобы все так делали :)
              • 0
                А здесь только я с кодом работаю не только в IDE?
                • –1
                  Я не говорил вообще ничего про остальных
                  • +1
                    А это не только к вам вопрос, на самом деле.
                    Минусующих меня за утверждение, про разработку вне IDE — достаточное количество и под постом что я выше написал и в карме. Так что я делаю вывод, что программистов работающих в идеальном мире где всегда есть IDE "которая подскажет" — больше чем тех, кто с реальными проектами работает в реальных условиях. :))
                    Ситуация о которой я ниже писал — это только личный пример и исключение. Но на своей практике я таких исключений уже, наверное, с сотню видел. Когда приходится работать с кодом в некомфортных условиях за пределами такой удобной IDE. И мне странно что есть люди, которые с этим еще не сталкивались...
          • 0
            Особенности окружения:
            Плагин испольуземый разработчиками для ведения проекта при сборке и деплое проекта выводит модальное окно, которое блокирует работу с IDE(Видимо чтобы пользователь-идиот не сохранил какой нибудь файл во время сборки не сломал сборку). А еще этот же плагин(чтоб его разработчики в аду горели) при добавлении или удалении файла в проекте инициирует его ПОЛНУЮ пересборку.
            Наверно плагин прекрасно себя показал при работе с мелкими проектами… Но когда проект на несколько тысяч строк…
            Пока один проект с одним модулем собирается и деплоится — портирование другого ведется в блокноте, чтобы время не терять.
            • 0
              А как от отличает блокнот от IDE? Нельзя ли сделать чтобы плагину не было видно IDE и он его не блокировал? Это плагин для чего?
              • 0
                Можно просто открыть второй инстанс IDE и в нем работать. Благо плагин не блокирует доступ к файлам.
                Но по причинам которые я в сообщении ниже написал — это не имеет смысла. IDE все равно кастрированная, и не даст преимущество перед блокнотом.
                Плагин — собственно отвечает за сборку и деплой проекта под Андроид.
                • 0
                  нельзя ли генерировать проект отдельно для плагина или наоборот из проекта плагина отдельно генерировать проект для IDE? Т.е. отвязать вообще IDE от плагина, как от блокнота.
                  • 0
                    Думаю что нет. Плагин призван дать возможность писать в MSVS под Андроид и без него студия вообще не умеет Java код понимать.
                    В целом знакомство мое было с этой системой не долгим и уже закончилось, надеюсь и не возобновится. :)
                    Так что я не могу ответить на такие вопросы, чтобы еще свежую травму не бередить. :))))
          • –1
            Ах, еще один прекрасный момент этого плагина:
            Он не переваривает большие проекты. Поэтому большая часть исходников прописана в мейкфайле, но отсутствует в самой IDE.
            Хорошо IDE их хотя бы при дебаге открывает. А так — даже кликнуть по переменной нельзя, чтобы по исходникам побродить. IDE просто не найдет куда перейти.
            Можно сказать: не пользуйте странные плагины…
            Ну так я и не использую. Заказчик использует. А я работаю с тем, что дают. Как и большинство разработчиков.
            • +1
              Э… И вы хотите чтобы язык приспосабливался к идиотизму вашего заказчика? А если я буду разрабатывать под досом, можно мне ограничение чтобы все файлы были 8.3?
        • 0
          > я вынужден был редактировать в Notepad++
          почему это вынужден?
          вас ктото заставлял редактировать именно в Notepad++? ваш внутренний голос?
          • 0
            А где надо было?
            • 0
              Надо было идти пить чай/кофе. Если такая среда разработки — требование клиента, то и платить за такую радость должен клиент.
              • 0
                Так он и платит.
                Я ему не говорил что меня что-то не устраивает и не планирую. Потому что есть работа, есть ее оплата. А комфорт и прочие вещи — это моя проблема, а не клиента.
                Это пример вполне рядовой. Обычно всё не так экстремально, но работа с кодом вне IDE — это обычное дело. И это надо учитывать.
                • 0
                  Нет, ну если тебе нравится этот геморрой — то пожалуйста. Фишка-то как раз в том, что рынок за программистов (не во всех сферах, но в большинстве существенных). Да и в любом случае — комфорт очень важен при программировании: меньше потенциальных ошибок, лучше погружение в задачу.

                  Поэтому я предпочитаю использовать особенности рынка для своей пользы — мне вот даже на одномониторной станции некомфортно… Что уж говорить о работе вне IDE… хотя совсем таковая не исключается — различные сниппеты в интернете, код-ревью вне IDE и просмотр коммитов вынуждают пользоваться только подсветкой синтаксиса… но ведь в этом режиме и глубокого погружения, обычно, не требуется.
                • 0
                  Еще вопрос, почему можно было установить Notepad++ но нельзя было установить Eclipse ?
            • 0
              в vim — очевидно же
        • +1
          > ТО есть часть статьи про «много работы ведется вне IDE» — вы проигнорировали.

          Нет, это вы проигнорировали, что это не важно в 146% случаев.

          Если вы хотите сказать иное, то сначала озвучивайте конкретный кейс, который вы почему-то делаете вне ide. Потом уже можно будет обсуждать ценность такого кейса.

          Например, если вам нужен тип на ревью — вам не нужен тип, вам нужно джуниору всучить «clean code».
        • +1
          А много ли меняется вне IDE?
          Одно только имя типа ничего не дает. Вы все равно видите только тот его интерфейс, который выражен в читаемом коде. Если вам нужно узнать что-то большее — вам придется искать объявление типа по проекту, ведь «не IDE» не умеет переходить к типу, по имени или без него.
          Конечно, если есть документация в которой легко находится тип по имени — то тут проще. Но этим же способом можно найти саму функцию, в описании которой скорее всего есть прямая ссылка на возвращаемый тип. Тем более, что если нам неизвестен возвращемый тип, то и остальные знания о функции неплохо бы освежить/получить, так что нам даже по пути.
          В итоге, не такая уж большая разница получается, зато пользователям IDE (которых большинство) — профит.
    • 0
      После того, как var разрешат, вы уже не заставите разработчиков явно указывать типы в таких местах (var unbufOut = NetUtils.getOutputStream(sock); )
      Более того, на данный момент Решарпер в студии подчеркивает явное объявление типа переменной и предлагает использовать var.
      Вот если бы var ввели и разрешили использовать только в случаях, как во втором примере (FileOutputStream fos = new FileOutputStream(«t.tmp»); )
      • +1
        Ну да, египетские скобки в джаве можно заставить не писать, а var нельзя? Точно так же административными мерами решается, через внутренние стайлгайды, в них и пропишете что можно использовать только во втором случае.
  • +26
    Поначалу в C# тоже все плевались и были консервативны.
    Потом постепенно начли менять на var ОченьДлинныеИменаКлассов, потом начали менять всё кроме примитивов (int на var не экономит даже буквы), а сейчас все успокоились и полюбили var, вот и в жаве так же будет.
    P.S.: в плюсах я тоже везде леплю auto, ибо нефиг ;)
    • +2
      А мне нравится использовать полные типы в C#. Я их даже раскрашиваю разными цветами.
    • +2
      То, что везде пихают — не есть хорошо. И не надо слушать толпу, а то можно сойти на дискуссии про миллионы мух и JavaScript.
      ИМХО var, как и auto, уместны только при замене неприличных названий классов для временных переменных. Вроде тех же итераторов, которые на плюсах могут перерождаться во что-то, о чём пишут культисты в своих книгах. В остальных случаях всё же не стоит скатываться в php, да не обидятся на меня адепты синего слоника…
      • +8
        учтите небольшую разницу между php/js и c#/c++: в первых внутри var может оказаться что угодно, во вторых — это вполне конкретный тип, просто мы его не называем.
        • +1
          У меня на работе был случай, когда приложение складывалось по банальной причине: автоматический вывод типа отрабатывал лучше, чем люди. И причина была банальной, в пылу копипасты, как и положено, сделали опечатку. А в итоге вызывалась не та перегрузка метода фабрики и всё, заверте.

          Я не спорю с тем, что то был быдлокод, ибо копипаста — не метод, тем не менее ошибки бы не было, если бы вместо «auto type = foo()» был «int type = foo()». И от этого не застрахованы даже лучшие из нас.
      • +4
        Да ладно вам. Типизация от этого никуда не денется, а шума в коде меньше. Доверить веведение типов компилятору — правильная вещь. Вообще, эта фича во многих современных языках. Можно посмотреть на тот же Kotlin, на сколько оно становится компактнее. При чтении кода обычно незачем знать тип каждой переменной, при необходимости всегда можно навести мышкой на переменную и посмотреть тип.
        • +1
          Если вы про

          var worker = new MyVeryFreakingAwesomeSuperSlowAndStupidMultithreadAsynchrousSQLWorker.HisCoolResult(kill,this,guy,please);

          , то я за. Если вы про

          int lososni(int);
          byte lososni(byte);
          tuna lososni(short);

          var item = lososni(1);

          , то, пожалуйста, Расмус Лердорф, перелогиньтесь.
          • 0
            Кстати говоря, я очень часто импортирую inner-classes. Вы спокойно можете сделать
            import my.superpuperpackage.MyVeryFreakingAwesomeSuperSlowAndStupidMultithreadAsynchrousSQLWorker.HisCoolResult;
            
            ...
            
            HisCoolResult worker = new HisCoolResult(kill,this,guy,please);
            • 0
              Чукча не писатель, чукча — читатель. В том смысле, что я перевожу пару проектов с Java на плюсы в свободное от рукоблудства время.
            • 0
              Публичные вложенные классы — дурь последняя. Почти всегда — или нарушение принципов инкапсуляции или неудобный механизм использоваться. И статические импорты таких классов — всего лишь костыль для этого непотребства.
              И да, я знаю, что этим болеет и несколько классов в JDK.
              • 0
                На мой взгляд это вполне нормальная группировка классов и интерфейсов по пространствам имён, когда пакет — слишком крупная единица группировки. Это никак не связано с инкапсуляцией. Импорт таких классов не требует слова static, вряд ли его можно назвать «статическим импортом». С точки зрения пользователя такой класс несильно отличается от класса в соответствующем пакете, только имеется напоминание, что он более тесно связан с другими классами в данном окружающем классе.
                • 0
                  Ладно, в JDK это могло быть проблемой, но в кастомной библиотеке/приложении вложенные публичные классы какую роль должны играть? С учётом того, что слишком большой пакет — это тоже не очень хорошо (я бы даже сказал — плохо… но с JDK понятно — там сложно было осуществить качественную пакетную детализацию… да при сохранении обратной совместимости).
                  • 0
                    Вот одна из причин. Если модули (Jigsaw) использовать пока нельзя, толстый пакет удобнее для управления видимостью. Из других пакетов можно использовать только public-методы и классы, тогда как из текущего пакета можно использовать package-private. При разработке библиотек большие куски кода не хочется выставлять наружу, но при этом хочется их переиспользовать в разных частях библиотеки. Поэтому раздутый пакет часто единственная альтернатива. И для дополнительной группировки используются классы. С Java-9 будет легче жить. Эта же проблема, кстати, важна для JDK: у них огромное количество package-private классов (и это очень хорошо), но при этом есть костыли для межпакетного доступа (типа SharedSecrets, это, конечно, плохо).
    • НЛО прилетело и опубликовало эту надпись здесь
  • –14
    Отсюда и главная претензия к var — риск снижения читабельности

    .
    Вот! Святые слова! Именно так! Подобные штуки валят дескриптивность кода наповал. Главное, когда я доказываю знакомым плюсовикам, что аналогичная штука в C++ (auto) это зло злющее — они меня не понимают и говорят что это одна из крутейших фич в С++11.
    .
    Ну ладно плюсы, там есть пятиэтажные жуткие конструкции на шаблонах и итераторах в библиотеках и можно понять желающих скрыть эту жесть. Но Java — язык прикладной, не системный. Зачем?! Так трудно написать тип? Просто лени ради?
    .
    На мой взгляд var (auto, и все иже с ними) — волшебная палочка в руках ленивого говнокодера, с которой ему теперь даже не нужно утруждать себя обозначать типы. Берегитесь! var превращает карету вашего кода в тыкву нечитабельного ужаса.
    .
    П.С.: Приношу свои извинения за оффтоп с плюсами, просто накипло.
    П.П.С: Что-то странное с разметкой в Хабре — съедаются энтеры (заменил точками в посте). В чём может быть дело?
    • +3
      Сам по себе var может быть удобен, если его использовать правильно и только в случаях когда точно понятно что за тип у переменной. Проблема с ним в том, что его сувать будут куда ни попадя, а там уже сиди и гадай — что ж за тип возвращается в той или иной функции. А если она ещё и интерфейс возвращает вместо конкретного типа…
      Лично я не очень его жалую, и не использую обычно, потому что читабельность реально снижается.
      • +1
        Проблема с ним в том, что его сувать будут куда ни попадя

        Вот-вот. Мне кажется, синтаксис языка должен быть в чём-то подобен хорошо спроектированной программе — в нём должна быть защита от дурака. Да и просто защита от человека, который прототипирует код. Я сам поддавался греху и использовал эту фичу как проектировал код. Типа: "а, поставлю-ка пока var, пусть будет — там точный тип проставлю". А потом: "так, ладно. Вот var, которому мы присваиваем… var. А, чтоб тебя!"
        • +1
          Так это и начинается :) Я тоже его пробовал использовать. Когда проект пишешь, то мысль "нужен тут var или нет" не является приоритетом, и получается лепишь его везде где можно.
          • 0
            Когда проект пишешь, то мысль «нужен тут var или нет» не является приоритетом, и получается лепишь его везде где можно.

            Если с предыдущим вашим постом я согласен, то в данном случае это проблема разработчика, а не самой возможности. Посмотрел в своих проектах использование var:
            1. Тип переменной указан при присвоении(using(var sw = new StreamWriter(path)), т.е. убираем дублирование информации);
            2. Тип переменной известен из имени переменной (cancelButton, аналогично убираем дублирование информации);
            3. При получении промежуточного звена LINQ выражения, если оно будет следом использовано для извлечения требуемых данных (т.е. информация о данном типе не имеет значения, т.к. это короткоживущая переменная, созданная по техническим причинам и используемая 2-3 раза на текущем экране кода).

            В итоге VAR позволяет убрать дублирование информации или скрывает ненужную информацию, что не отражается на читаемости кода. Во всех остальных случаях обязательно использование имен типов, а порой и с пространством имен, если важно акцентировать внимание на библиотеку, из который используется данный класс (например, если мы хотим явно указать, что используем NLog в качестве логгера).
            • +5
              Я не противник var вообще, но вот пример из Tox:
              public ToxData GetData(string password)
              {
                     ThrowIfDisposed();
              
                     var data = GetData(); //как выглядят эти самые данные?
                     byte[] encrypted = ToxEncryption.EncryptData(data.Bytes, password);
              
                     return ToxData.FromBytes(encrypted);
              }

              или
              var key = salt == null ? ToxEncryption.DeriveKey(passphrase) : ToxEncryption.DeriveKey(passphrase, salt);

              Не очень-то и читаемо. Да, не проблема пойти в функцию, узнать что оно там возвращает, и потом пойти в тот самый класс и смотреть что в нём. А можно было сразу написать тип и не делать лишних движений.
              А так конечно есть случаи когда его удобно использовать :) Только надо помнить что человек — не компилятор, и способности к инференции типов у него ограничены :)
              • +3
                А так конечно есть случаи когда его удобно использовать :) Только надо помнить что человек — не компилятор, и способности к инференции типов у него ограничены :)

                Именно это я и имел в виду
                var key = salt == null? ToxEncryption.DeriveKey(passphrase): ToxEncryption.DeriveKey(passphrase, salt);

                А за такое использование я бы точно убил.
                • 0
                  Убивать людей не стоит, но автор кода точно хотел написать на Scala с экспрешен семантик :)
                • +1
                  А за такое использование я бы точно убил.
                  Достаточно немного переформатировать код и не будет нужды кого бы то ни было убивать — возвращаемый тип прекрасно виден. Никогда не понимал, почему люди недолюбливают операцию тернарной альтернативы.
                  var key = (salt == null)
                  ? ToxEncryption.DeriveKey(passphrase)
                  : ToxEncryption.DeriveKey(passphrase, salt);
                  • –3
                    Но ведь в данном случае достаточно было указать тип переменной и сразу код бы стал более читаемым, так как уже нет особой нужды смотреть на реализацию. Да и результат DeriveKey не особо понятно какого типа: может строка, а может специальный тип. Но это уже скорее личные придирки.
                    А в целом это все дела личных предпочтений каждого разработчика.
              • 0
                Я не знаю что такое Tox. Судя по коду приведенный кусок получает откуда-то данные и шифрует. Я ожидаю, что у data скорее ксего тип ToxData
    • +32
      То есть код вида:
      NetUtils.getOutputStream(sock).write("hello");

      • вас не смущает, а эквивалентный:

      var unbufOut = NetUtils.getOutputStream(sock);
      ounbufOut.write("hello");

      • адский ад? Может и первый вариант запретим? Там же не понятно какой тип возвращается! В одной строке должно быть не более одного вызова метода!
      • +2
        Хм… А ведь справедливо. Не задумывался о подобной аналогии с цепочечным вызовом методов. Спасибо, подумаю об этом.
      • +1
        В первом варианте нам не требуется держать в голове контекст, так как возвращаемое значение используется сразу же, по цепочке, во втором же случае — нам нужно помнить тип unbufOut до самого конца области видимости.
      • 0
        В джепе кстати такой же пример в качестве аргумента за:
        var path = Path.of(fileName);
        var fileStream = new FileInputStream(path);
        var bytes = Files.readAllBytes(fileStream);
        так и бряки приятнее ставить
        • 0
          Согласен, привязка брейкпоинтов к строкам, а не ленсемам — это боль.
    • +40
      По опыту: если у вас var снижает читаемость, значит у вас гораздо большие проблемы с кодом, чем читаемость.
      • +3
        Проблема скорее не в написании своего кода, а в получении чужого в наследство за три недели до релиза, куда нужно добавить новую фичу
    • +1
      Если б вы не сказали — не заметил бы точки;) в остальном плюсую.
    • +1
      На мой взгляд экзепшоны — волшебная палочка в руках ленивого говнокодера, с которой ему теперь даже не нужно утруждать себя написать и проверить возвращаемое значение.
      На мой взгляд функции — волшебная палочка в руках ленивого говнокодера, с которой ему теперь даже не нужно утруждать себя написать ещё одну реализацию сортировки.
    • 0
      Что ж. Вывод из всего случившегося на будущее мне и иже с ними: нужно быть осторожнее при высказывании категорических субъективных и непроверенных суждений в трендовых постах… Вроде было очевидно — но попался. Спасибо сообществу за урок.
  • +2
    А как быть если мне нужно в возвращаемом значении иметь не реализацию класса, а его интерфейс?
    И вообще это "замена вместо" или "дополнительная фича"?
    • +1
      Дополнительная. Какие сомнения в этом?
      Слишком часто надо явно задавать тип переменной, чтобы его везде можно было заменить на var.
      Это надо по сути другой язык делать.
    • 0
      Конечно же фича.
  • +2
    У var есть польза, но я понимаю людей которые не могут ревьювить шарповый код с обилием varов. Банально разница в том, к какому подходу привык человек. Есть подход, основанный на концепции "важен код, т.е. действия, которые мы совершаем" и есть подход, основанный на концепции "важны типы, т.е. то, с чем мы работаем". Оба подходы имеют право на жизнь и более того, разные подходы по разному ложатся на разные задачи.
    Но прикол в том что отсутствие varа и тех же лямбд (ранее) мешал следовать первому подходу. Тогда как в грамотных руках var и лямбды делают код более читабельным, а не наоборот.
    Можно сравнить код с статьями/книгами. Слишком много воды — трудно уловить суть. Слишком мало воды — мозг либо отвык, либо просто не может слишком долго концентрировать на важных вещах. Оптимальный баланс найти трудно.
    • –6
      А можете рассказать как раскрывается информация о типах когда мы, например, записываем результат функции? Например, вот такой вот код:
      .
      var theStream = openStream();

      .
      Что именно за поток возвращает функция?
      .
      Ясно что есть контекст, но он может разрываться тем, что тебя отвлекли от кода или пришёл тикет на фикс какой-то другой срочной баги… Я уже не говорю о случаях, когда код был порефакторен кем-то другим (например, человек заменил значение, которое openStream() возвращает — а var остался).
      .
      Ясно также, что по-хорошему нужно точнее именовать метод. Но, на мой взгляд, подобные вещи будут приводить к тому, что имена переменных и функций начнут включать в себя ту самую "воду", которая до этого обозначала тип. Особенно когда речь идёт о больших проектах.
      .
      П.С.: Извиняюсь за точки — выше писал, какая-то фингя с проставлением энтеров между строками на хабре.
      • +5
        Что именно за поток возвращает функция?

        Зачем именно это знать? Можете привести пример кода для понимаения которого недостаточно знать, что это поток, а нужно знать конкретный его тип?
        • –7
          Ну, пример навскидку. Например, у нас есть адова прорва разных потоков, но некоторые реализации имеют особые методы и в коде был как раз тот случай. Что-то в духе:
          .

          NewSpecificWebStream theStream = createStream();
          _IPCache = theStream.getIP();

          .
          Если мы меняем NewSpecificWebStream на var, то в случае рефакторинга (например, смены типа, возвращаемого из createStream() ) могут полезть ошибки — да, времени компиляции, но от этого всё равно не особо внятные. Таким образом, var не будет бить по голове только там, где возвращаются интерфейсные классы — да и то, очередной рефакторинг всё равно может привести к печальным последствиям.
          • +1
            Какие не особо внятные, какой рефакторинг, приведите конкретный пример
            • 0
              Ну, например, есть вот такой вот код:
              var theStream = createStream();
              _IPCache = theStream.getIP();

              createStream() возвращал NewSpecificWebStream. А потом решил заменить возвращаемое значение на просто WebStream, у которого нету метода getIP() или этот метод называется по-другому. И рефакторинг при этом провели не мы, а кто-то другой в столюдной компании. При сборке в случае если бы вместо var был бы тип NewSpecificWebStream, ошибка возникла бы в строчке вызова createStream() — несовместимость типов. А с var ошибка возникнет в месте вызова метода, и придётся прыгать к декларации переменной, а потом ещё и смотреть тип, возвращаемый createStream().
              Возможно, пример немного надуманный — если честно, у меня достаточно небольшой опыт работы с var — но когда я впервые услышал об этой фиче, мысли вроде такой заставили меня очень осторожно смотреть на var.
              • 0
                Вы поменяли тип возвращаемого значения, вам показали то место, где использовался тот факт что тип другой. Если бы там, например стояла декларация типа createStream явно, то возможно getIP мог бы не использоваться, но при этом все равно ругань была бы. Вам бы пришлось проанализировать все такие места — действительно ли он использует что-то из NewSpecificWebStream. Мне кажется, с учетом того, что надо делать маленькие методы, предпочтительней var
              • 0
                Хуже было б если у него был getIP, но делал что-нить нечто иное.
          • +4
            Я не понимаю, почему ошибки не полезут, если мы оставим тип явно. Я также не понимаю, почему ошибки для кейса var будут менее понятными, чем ошибки для кейса createStream().getIP() (т.е. когда мы объединяем цепочку вызовов).
            • –3
              Если тип будет прописан явно, то ошибки полезут тоже, естественно. Но когда мы глянем декларацию переменной, для вызова которой возникла ошибка — то мы увидим в коде не невнятный var, а конкретный тип, для которого выскочила ошибка.
              Про вызов методов один за другим отписались выше, это справедливое замечание… Правда, чуть поразмыслив, я вспомнил, что в таких случаях — особенно если код незнакомый — приходится-таки прыгать по декларациям методов, чтобы смотреть возвращаемые функциями типы, что раздражает, и не хотелось бы получить подобный эффект ещё и для локальных переменных.
            • +1
              Если сравнивать именно читаемость, то такой подход хорош только в случае, если важно именно получение IP, а создание потока не имеет логической ценности для дальнейшего кода. Так, мы знаем только лишь, что здесь получаем IP из некого потока. Но если потом мы хотим использовать поток и далее, к примеру написать еще пару функций с его использованием, то нам нужно знать тип потока. Читая чужой код вы, не узнав тип, не сможете правильно его использовать, а, значит, придется либо разбираться в коде, либо посмотреть через подсказки IDE. Просто попробуйте модифицировать чужой код и сразу поймете чем он плох)
              PS: в принципе, var вообще можно убрать и писать что-то вроде: IP = createStream().getIP();. Только вот это какой-то скриптовый язык получится.
      • +2
        Что именно за поток возвращает функция?

        А зачем вам это знать? Я правда не понимаю, объясните
        Я уже не говорю о случаях, когда код был порефакторен кем-то другим (например, человек заменил значение, которое openStream() возвращает — а var остался).

        И что случится плохого, если другой человек поменял возвращаемый тип метода openStream?
        Вы, кстати, не думали о таком концепте: иногда необходимо, чтобы тип переменной был жестко связанной с типом выражения? Например в c++ есть decltype.
        Ясно также, что по-хорошему нужно точнее именовать метод. Но, на мой взгляд, подобные вещи будут приводить к тому, что имена переменных и функций начнут включать в себя ту самую «воду», которая до этого обозначала тип. Особенно когда речь идёт о больших проектах.

        Т.е. по вашему лучше определение переменной в видеFileInputStream fos = ... нежели var inputStream = ...?
        • +2
          Справедливости ради.
          А зачем вам это знать? Я правда не понимаю, объясните

          Ага, я тоже так в первый момент подумал. Только вот это InputStream или OutputStream?
          • 0
            А если у вас две переменные (одна InputStream, другая OutputStream), вы как их различать будете? По имени или будете каждый раз бегать глазами к определению переменной?
            • 0
              Так я же не отрицаю что имя отвратное. Я лишь о том, что в данном конкретном говнокоде явный тип бы помог. Хотя, на самом деле, там все равно парой строчек ниже скорее всего будет read или write.
              • –2
                Ну так научитесь именовать чтоль переменные тоже правильно, а не только типы. Или вы аппелируете к тому, что разработчики стандартной либы более правильно именуют типы, чем разработчики вашего проекта переменные?
                • 0
                  Как известно, с именованием всегда проблемы. На самом деле, я ни к чему не апеллирую. Более того, сам в опросе проголосовал за var + val. Т.к. считаю что должен быть простой способ делать final переменные (забавное словосочетание) чтобы провоцировать подход "final by default". Свой же первый коммент я написал исключительно
                  Справедливости ради.

        • –2
          Т.е. по вашему лучше определение переменной в видеFileInputStream fos =… нежели var inputStream = ...?

          Нет. На мой взгляд имя типа и имя переменной несут разные смысловые нагрузки. Тип говорит о том, чем вообще является переменная, имя переменной говорит о том, какое смысл она несёт в контексте места её использования. Если говорить про идеальное именование — то хорошим именованием, на мой взгляд, было бы что-то вроде FileInputStream theSavingStream =… (например, если вызов в рамках какой-то функции для сохранения данный на жёсткий диск).
          • +4
            И все же джависты не умеют в корректный нейминг
            FileInputStream theSavingStream

            Теперь я гораздо более хорошо понимаю почему вы считаете, что var это плохо
            • –1
              Оу, да. Описался. Справедливо. Ну, считайте, там theLoadingStream и метод для загрузки чего-нибудь
  • 0
    Мое суждение очень локально. Я занимаюсь разработкой под Android уже более 5ти лет. Все мы знаем что нативный язык — это Java. Но в последнее время стал писать на Kotlin. Так там как раз такой синтаксис (val/var). Так что никакого отчуждения нет.
  • +1
    var — очень годная, полезная и нужная вещь. Java все-таки прогрессирует и медленными шажками идет в правильном направлении.
    После года ежевечернего использования Scala объявление переменных с множеством дженериков в Java кажется сущим адом.
    Программируя на Scala, почти никогда не использую явное объявление типов. Всегда понятно по имени переменной, какой у нее тип. И Idea конечно же подсказывает при автокомплите.
  • –38
    Прощай, проверка времени компиляции.
    Здравствуй, ошибка времени выполнения, "внезапно" уронившая прод.
    • +15
      Если оно будет реализовано как в C#, то var можно использовать только в тех местах, где тип известен во время компиляции.
    • +13
      Прочитайте про то, чем отличается вывод типов в статической типизации от динамической типизации.
      Ознакомьтесь с каким-нибудь языков, где выводов типов еще больше. (Haskell, F#)
      • –9
        Читал, знаком, и что? В Haskell статическая типизация. Он у вас даже не запустится, если тип нельзя было узнать во время парса.
        Или вы хотите сказать что инференция типа во время компиляции — это динамическая типизация?
        • +7
          Перечитайте то, на что я отвечал и мой ответ. Что-то из этого вы не до конца поняли.
          • +2
            Не разобрался, подумал ответ мне :)
      • 0
        вывод типов в статической типизации от динамической типизации
        Верно заметили. Вот вспомнил Haskell и сразу понял.
    • 0
      Пример приведите пожалуйста, что именно вы собираетесь ронять в рантайме?
      На мой взгляд, единственный сильный контраргумент против var — это общепринятость использования интерфейсов в Java. Например:

      List<String> names = new ArrayList<>();
      Map<Long, String> map = new HashMap<>();

      А дженерик-параметры уже в Java 8 не нужно дважды указывать, поэтому в приведенном примере минимум дублирующей информации.
      С другой стороны, это же всего лишь локальная переменная — пусть будет классом, все честно. А в сигнатурах методов никто не мешает так и оставлять интерфейсы.
      • –2
        уже в Java 8
        diamond operator еще в 7 появился.
        Да, там выше написали про вывод типов.
      • +1
        По факту контраргумент — вопрос привычки. За пределы метода ArrayList всё равно не вылезет, а внутри метода вам большой разницы нет, особенно когда вы этого типа перед глазами не видите. Наоборот, если вы формируете список в методе и возвращаете его наружу, вам может захотеться в конце вызвать какой-нибудь trimToSize() для экономии памяти, поэтому более специфичный тип внутри метода может пригодиться.
    • +6
      Как всегда в подобных обсуждениях var/auto находятся люди только что вылезшие из бункера и не ознакомившиеся с описанием фичи, считающие что их любимый ЯП собираются испортить динамической типизацией из PHP, JS и т.п. :)

      • –3
        Этих людей стоит успокоить: динамическая типизация в джаве давно есть, только синтаксис адский :) Если на JS было бы
        var a = "abc";
        var b = a.replace("a", "b");

        То на Java будет
        Object a = "abc";
        Object b = a.getClass().getMethod("replace", String.class, String.class).invoke(a, "a", "b");

        Динамическая типизация в чистом виде!
        • +2
          Где в данном примере динамическая типизация? Здесь её как раз нет совершенно.
          • 0
            Ну-ка, объясните, в чём разница между динамической типизацией и reflection?
            • +1
              Хм, в определениях? Я может не понимаю вопроса, но не могу придумать контекста, где это было бы одним и тем же или хотя бы чем-то похожим.
            • –1
              В том, что код:
              var item = new { Age = 18, Name = «Ivan», LastName= «Ivanov» };
              Console.WriteLine(item.Age);
              Console.WriteLine(item.Name);
              Console.WriteLine(item.LastName);

              Будет преобразован компилятором в:
              AnonymousClass_666 item = new AnonymousClass_666() { Age = 18, Name = «Ivan», LastName= «Ivanov» };
              Console.WriteLine(item.Age);
              Console.WriteLine(item.Name);
              Console.WriteLine(item.LastName);

              А теперь сравните его с рефлекшеном.
              • 0
                Это детали реализации, которые никого не волнуют в заданном контексте. В рефлекшне JVM тоже может сгенерировать нативные методы, если конкретный метод часто вызывается.
                • 0
                  Вы в этом точно уверены? Да и руководство прямо говорит об обратном:
                  Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
                  docs.oracle.com/javase/tutorial/reflect/index.html

                  Если бы проблемы с Reflection не было, то и не было бы такой библиотеки, как ReflectASM.
                • 0
                  Более того, приведенный XAHOK пример вообще не является динамической типизацией.
  • +17
    Просто смешно от консерватизма явистов. Никто не заставляет писать var везде — пишите там, где явно понятен тип из выражения справа, типа
    SomeClass.SomInternalClass<String, Integer> foo = new SomeClass.SomInternalClass<~>();
    var снижает читабельность? да у меня глаза кроваточат от строки выше.
    А вообще зачем этот динозавр когда есть котлин.
    • 0
      static import com.some.SomeClass.SomInternalClass;
      Котлин сыроват и после java выглядит набором свистелок. Вот тут о его проблемах написано подробнее.
    • +4
      Даже это по факту мелочи. А вот когда используешь функциональный стиль на всю катушку, возникают типы шире экрана (например, BiFunction<BiPredicate<String, Integer>, String, BiPredicate<String, Integer>>). При этом он нужен реально в пределах ограниченного скоупа.
      По факту автоматический вывод типов уже работает в восьмёрке для аргументов лямбд. Кто использует функциональное программирование на всю катушку, у того больше половины переменных — по факту параметры лямбд, и у подавляющего большинства тип выводится автоматом. По факту этот JEP — логичное распространение существующего механизма, а не что-то новое.
      Меня больше парит, что предложенные var и val визуально похожи. Я при заполнении анкеты предложил оставить var, а вместо val использовать const (благо это уже ключевое слово), но ко мне вряд ли прислушаются.
  • +1
    Интересно
    Есть код скажем такой
    var somevar = somevar2.getSome();
    И есть конструкция
    Some somevar = somevar2.getSome();

    Как в первом случае узнать какой реально тип я получаю для дальнейшей работы?
    И как в первом случае Ide найдет мне в контекстной подсказке список функций которые возвращают именно тот тип что объявленная мной переменная?
    • –1
      найти где объявлено somevar2 получить ее тип. Найти у типа getSome, получить тип результата он и будет типом somevar
      • 0
        Ну то есть лишние телодвижения при работе с чужим кодом (или со своим который писал достаточно давно что бы уже забыть детали)
        • +1
          Если вы разработчик IDE, то да, если пользователь, то IDE это сделает для вас
          • +1
            Что ide сделает за меня?
            Я смотрю на код с var и пытаюсь понять что я получил в итоге вызвав эту функцию и не вижу этого.
            • +1
              посмотрите, как выглядит работа с ide kotlin, например,
              Как только вы вводите переменную сразу же подсказка с типом, еще обычно можно наводить просто мышкой и тебе расскажут все про идентификатор под курсором.
    • +3
      По типу результата метода getSome(), очевидно. В чем проблема?
      Разница только в том, что если вы напишете

      AnotherType somevar = somevar2.getSome();

      Вы поймаете ошибку компиляции, что тип Some не может быть приведен к типу AnotherType. Как раз потому, что компилятор сравнит результат метода getSome() и объявленный тип переменной.
      Больше никакой разницы нет.
    • +2
      И как в первом случае Ide найдет мне в контекстной подсказке список функций которые возвращают именно тот тип что объявленная мной переменная?

      При парсинге кода IDE посмотрит, что возвращает somevar2.getSome() и var somevar будет именно этого типа.
      • –1
        Вы не поняли меня. Я про контекстную подсказку написал.
        • +1
          Это и контекстных подсказок тоже касается. Тип переменной x, объявленной в виде var x = getSome() выведется из типа возвращаемого значения getSome().
          • +2
            Еще раз

            Я пишу int x = obj.*******
            Вместо звездочек мне ide покажет список функций которые возвращают int

            Если я вместо int пишу var то ide начнет мне отображать уже список всех доступных функций которых будет значительно больше
            • –4
              Нет, возьмите нормальную IDE нормальный язык, там все работает https://blogs.msdn.microsoft.com/fsharpteam/2012/04/04/f-intellisense-improvements-in-visual-studio-11-beta/
              • +2
                Я работаю под линуксом…
                Можете словами объяснить какой там алгоритм?
                • 0
                  Считывание нейроимпульсов, не иначе. Я не вижу другого способа угадать, какой же метод/переменная потребуется в var. По той ссылке также ничего полезного не увидел (да и не смог бы).
                  • 0
                    Я просто недостаточно внимательно прочитал описание проблемы, извините. См. ниже обсуждение, как это можно сделать сконвертировав в var после набора и непонятнку как отличить ситуацию когда надо int x = y.IntMember и int x = y.StringMember.Length.
            • 0
              В таком случае согласен, отфильтровать методы по типу не получится.
              Хотя лично я предпочитаю написать obj.getSomeValue(), а потом сделать Introduce local variable, получив final SomeType someValue = obj.getSomeValue();
            • 0
              Извините не понял. То есть вы совершенно точно знаете тип, но не знаете ни одной части имени члена?
              В таком случае да, набираете int x = y. выбираете член, потом можно автоматически переконвертировать int на var.
              Еще вопрос. Как IDE узнает, что когда вы набираете int x = y. вы хотите написать целый член x а не например x.ToString().Length?
              • +1
                1) Я знаю что мне нужно получить и исходя из этого уже выбираю нужную мне функцию.

                2) ну тут сложнее для ide и она уже видя что я набираю значение которое не подходит под ее шаблон начинает использовать мой шаблон
                • 0
                  У вас есть реально IDE которая фильтрует так intellisense?
                  • 0
                    Да )))
                    AndroidStudio на база IntejIdea так делает
                    Eclipse вроде тоже
                    • 0
                      Ну так укажите тип переменной и пользуйтесь этой фичей. В чем проблема то?
                      Код чужой, но это же не запрещает вам указывать типы (если конечно у вас не драконовские стайлгайды, но это уже другой вопрос).
                      • 0
                        Это понятно
                        Вопрос в другом
                        Я пытаюсь понять насколько удобной будет новая фича что бы ее можно было использовать
                    • 0
                      А как оно узнает, хочу ли я сделать:
                      int x = object.IntMember()
                      или
                      int x = object.StringMember().IntMember()
                      Выводит ли оно StringMember()?
  • +5
    var прекрасен когда дело доходит до рефакторинга. Когда у вас есть методо который раньше возвращал конкретный класс, а потом вы решили, что он должен возвращать абстрактный класс или же вовсе интерфейс.
    с var проблем не будет, если сигнатуры методов остались теже.
  • +6
    о, теперь не Борщ борщ = new Борщ();, а просто var борщ = new Борщ();
    уже лучше

    • 0
      Ну хоть не как в ПХП
      if (борщ > 12)
      {
      echo "а борща то нет, без декларирования живем";
      }
  • 0
    Интересно, почему var, а не auto?
    • +8
      Судя по результатам опроса (ссылка в статье), с большим отрывом победил вариант «var and val» как в Scala, а не просто «var», как в С#. «auto» занял предпоследнее место.
      • +1
        Извините, не удержался
        а не просто «var», как в С#
        Мы не станем рабами (с)
    • –3
      Ну, думаю, по аналогии с js.
      • +2
        Скорее с C#, с ним они более близки.
    • 0
      Демократия так решила :)
  • +4
    То, что старушка Java активно взялась перенимать фичи из современных языков программирования, не может не радовать. Как ни крути, на Java пишет огромное количество людей, и через такие вещи как лямбды, REPL, автовывод типов, все эти люди приобщаются к современным подходам к разработке. Надеюсь, что разработчики языка найдут способ внедрить еще хотя бы case classes и pattern matching. Конечно, это не сделает из Java конфетку, но хотя бы базовые идиомы и обычный код на Scala не будут выгляеть для Java-разработчиков полной дикостью.
    • 0
      И кортежей ещё очень не хватат.
  • +9
    Странный спор. Во всех современных языках программирования есть var/val/let, который применяется практически везде. А вы спорите, полезен он или нет. Этот спор уже давно и однозначно разрешён.
    • 0
      var и let это разные вещи
      var x =… говорит — это переменная x, тип которой выведен из выраженния справа
      let x =… говорит — это выражение значение которого можно получить по имени х
  • +3
    Просто var научит вас использовать говорящие имена переменных, которые подразумевают их тип, что сделает код еще более чистым и читаемым...
    • НЛО прилетело и опубликовало эту надпись здесь
  • +34
    Да ладно, не такое и серьезное изменение, если вдуматься. Ну теперь в плохом Java-коде разобраться станет чуть сложнее, а в хорошем… проще. Но, конечно, чуточку жаль, ведь теперь вместо канонического:
    for (Map.Entry<MyTrickyWrapper<String>, MyDomainObject<WithGenericType<AndSubtype>>> e : m.entrySet()) { ... }

    Можно будет написать
    for (var e : m.entrySet()) { ... }

    Бедные пользователи notepad, ну как же им будет сложно понять такой код...
    • +3
      Напомню, что уже сегодня можно писать
      m.forEach((key, value) -> {...});

      Есть некоторые ограничения, но всё-таки. Заметьте, что здесь уже выводятся автоматически типы key и value и никто не жужжит, все пользуются.
      • +1
        Тише, тише!
        А то сейчас прознают про это и поднимут на change.org петицию "Уберите в Java автовывод типов для аргументов лямбд"!
        • 0
          А заодно и лямбды тоже уберите, ага. А то знаю лично некоторых консерваторов, говорящих о том, что лямбды не нужны. Это какая-то клиническая форма консерватизма уже.
  • +4
    Да боже мой, даже ежу понятно, что var user = new User() в 100 раз удобнее и читаемее чем User user = new User().
    Господа консерваторы, Вы бы посмотрели на текущие реалии — во всех новых языках сейчас так.
    Java развивается, меняется и это хорошо, радоваться надо, а не ныть.
    • +1
      Наличие "новой" функции в языке не делает её автоматически хорошей. Плохой собственно тоже. А удобство — личное дело каждого, зачем навязывать своё удобство другим людям?
      • 0
        Не видел еще ни одного человека, который бы попробовал синтаксис Scala, Kotlin, Swift, Go, Nim etc. и сказал бы «не ребят, вообще не удобно». Не зря же сейчас многие новые языки именно так дизайнятся.
        • 0
          Есть разница в дизайне языка где инференция типов вот таким образом предусмотрена изначально (Haskell), и там где это делают после факта в качестве примочки, что (вероятно) влечёт за собой кучу проблем с читаемостью и пониманием кода.
    • 0
      Вопрос не в нытье
      Вопрос в том как лучше адаптироваться в новой реальности ))
      • 0
        Ну сейчас стадия где-то между отрицанием и торгом, до принятия ещё пару шагов.
    • 0
      Автор прав тем что java чисто консерваторский язык, и то что многим другим программистом кажется очевидно и просто для джависта вызовет когнитивный диссонанс.
  • +1
    Вообще-то, var в C# был добавлен не ради краткости, а прежде всего для поддержки анонимных типов, на которых (в числе прочего) базируется LINQ.
    • 0
      Все таки LINQ базируется на перечислителях, а анонимные типы немного из другой истории, хотя и используются преимущественно с LINQ. И VAR в данном случае не более чем средство для удобной работы с ними, т.к. все анонимные типы не более чем техническая прослойка с временными переменными, тип которых не несет полезной информации.
      Хотя, порой хочется бить шлангом за использование анонимных типов где не надо
      • +4
        Не для "удобной работы", а для какой бы то ни было работы с анонимными типами необходим var!
        • 0
          Исключительно из-за строгой типизации языка и особенностей работы VAR. Но слава богу, что не ввели тогда dynamic!
          PS. Согласитесь, что VAR и анонимные типы это 2 разных фичи, хоть и связанных в использовании между собой. И VAR может эффективно использоваться и без анонимных типов, а вот анонимные типы без VAR уже практически невозможно. А в целом это спор о курице и яйце получился))
  • –4
    Сходил по ссылке в опрос разработчиков. Ладно еще var. Но большинство за val+var. А на третьем месте предлагают var и let. Это же ужас. Например, открываете программу, а там
    10| let a = 7;
    20| let b = 5;
    Вот сейчас было особенно тепло и лампово, но вырвиглазно. И слегка бейсиковато. И даже если номера строк отключить. Это же теплый ламповый ужас, какое счастье что подобное они не сотворят, а var просить им можно. Хотя, если сделают var, то скорей всего сделают и val, и если они это сделают, то это будет значить, что за этим стояли скалисты.
    Но вообще, тогда лучше уж и лаконичней так:
    User u = new ("вася")
    Хотя new со скобками тоже тут не очень нужно, но без него уже другие приколы будут, так что это был бы оптимум. А вот с NetUtils.getOutputStream(sock) хуже — не всегда понятен тип возвращаемый, с другой стороны иногда тип понятен, и когда он понятен, то действительно, писать его не хочется.
    • 0
      let это скорее из clojure: https://clojuredocs.org/clojure.core/let
      • 0
        Я на Бейсике использовал let (точнее LET), когда ни Clojure, ни Java не было вообще.
      • 0
        Ага, из лиспов, ML'ей и кучи всего.
      • –1
        На старых бейсиках оно было.
        Потом даже в бейсиках более новых от него отказались. С тех пор, как видишь let, это ассоциируется с древним бейсиком. Конечно новички это так не воспринимают, и для них это ничего не значит. Я подозреваю, что заминусовали меня новички.
        Зачем в clojure решили использовать именно let, загадка. Думаю, от этого он потерял некоторое количество почитателей.
    • 0
      В лиспах с первых версий тоже есть конструкция с именем LET. Так что не факт, что не факт, что её ввели в BASIC.
  • +4
    Классный опросничек в начале статьи приведён. За вариант "может сделем var как в C#" — 80% народу за или не против, а по поводу варианта "может сделаем auto как в С++" 70% людей категорически против. А чем же, скажите мне, принципиально отличается var в шарпе от auto в плюсах?
    • +4
      А кто голосовал против C++ наверное и сами не знают как оно в C++ работает.
    • 0
      Может просто потому, что var более естественно выглядит, чем auto, не?
      auto — это какой-то уж слишком общий термин (Помню, как сам сильно удивился выбору такого ключевого слова в плюсах, я понимаю логику такого названия, как программист, но с точки зрения простого обывателя такое впечатление, что все делается для того, чтобы код мог читать только специалист. Зачем бесконечно изобретать велосипеды даже в таких простых вопросах, когда уже все давно придумано, принято и много лет успешно используется? Специально, чтобы не как у других? Чтобы выделиться? Ну, это глупость! Это только снизит переносимость и повысит порог вхождения!), а переменная (var) — она и в Африке переменная, поймет даже ребенок, вполне говорящее и читаемое ключевое слово, используемое явно и неявно (var1, var2,… Да, быдлокод, но через это проходили все, в процессе обучения.) начиная от истоков IT, с которым знаком каждый школьник. И короче на символ! :D
      • +5
        В плюсах это обусловлено было обратной совместимостью — auto всегда было зарезервированным ключевым словом, а введение var поломало бы старые программы, где были переменные с именем var.
        • 0
          Как я и написал выше, я понимаю логику такого выбора, но мне кажется, что можно было бы обойтись меньшей жертвой в угоду читаемости, при необходимости пофиксив на месте старые проги, коих, я думаю, было бы не так много (тем более, что это явный говнокод), приняв var, чем теперь иметь auto навеки… Для старых прог это всего лишь исправление имени переменной, а не тотальная смена семантики, it's not a big deal… И не думаю, что такого кода на жабке сильно меньше, тем не менее это не помешало принять правильное решение… Более того, если старые проги до сих пор компилируются современными компиляторами, а не просто крутятся где-то на забытых пентагоновских серверах десятки лет, то считай, что они развиваются, поэтому не будет проблемой провести мелкий рефакторинг перед следующей компиляцией...
  • +5
    var — простой сахар, не хотите — не используйте. Не стоит придумывать себе проблему там, где её нет.
  • +2
    проходили уже все это в C#, тоже было много гнева и воплей как появился var, но потом все привыкли, оказалось удобно. мое субъективное мнение, в том, что вывод типов рулит и чем меньше мне их придется писать явно руками, тем лучше.
  • +4
    Когда начал осваивать Java (после использования C#) очень удивило отсутствие var.
    Даже в С++ уже добавили auto.
    Отсюда и главная претензия к var — риск снижения читабельности
    Это Вы разработчикам на python'e и т.п. расскажите как отсутствие типа снижает читабельность.
  • НЛО прилетело и опубликовало эту надпись здесь
  • +3
    Голосовалки не хватает.
  • –5
    А «Object» чем плох?
    • 0
      Тем, что это имя класса. А var — обозначение любого типа. Object x = 4 сейчас создаёт объект Integer, а мне не нужен объект.
      • –5
        Object x = 4 нельзя написать. Я уверен, что Ваш любимый "var" просто станет обёрткой "Object" в красивом виде и всё. Компилятор сам тип приведёт и всё.
        • 0
          Нет. Будет именно int.
          • 0
            UPD: буду обновлять комментарии...
        • 0
          UPD: можно, сглупил с утра.
  • –1
    var будет удобен в Java лишь в объявлении переменной с длинным названием типа.
    • +2
      Нет. На самом деле с любой длиной в названии типа.
      Вы делаете var x = someFunction();
      И уже больше никогда не паритесь, если вам нужно будет на этапе проектирования поменять тип, возвращаемый someFunction(); (не надо будет по всему коду менять типы переменных).
      • –1
        И словите большой привет, когда разные перегрузки станут по ошибке возвращать разные типы. И хорошо, если эти типы будут несовместимы, об этом сругнётся компилятор, а если это разные потомки одного базового класса, то баги можно искать неделями и совершенно в других местах.
        • +1
          overloaded methods, возвращающие РАЗНЫЕ типы? В Яве (и в C++) такое невозможно.
          • 0
            Лол.
            https://habrahabr.ru/post/280075/#comment_8819995
            • 0
              Ну сдуру можно...
              • 0
                Можно сдуру. А можно по невнимательности. А ещё можно специально. Кейсы бывают разные, и, например, такие перегрузки очень лаконично и правильно входят в идеому математических библиотек, где оператор может давать результат, мягко говоря, отличный от операндов тип.
                • 0
                  ну и чем мешает var?
                  хочешь явно тип переменной — указывай по-старому
                  если у тебя обобщённый алгоритм — пиши var и не парься
          • 0
            • 0
              А, ну если так. Если кто-то так пишет, ему var вообще не нужен.
              • 0
                Очевидный пример работы.
  • –2
    «По моим ощущениям, хороший код не пострадает. А вот плохой код может стать еще хуже. Ну и бог с ним.»
    Ню — ню)…
    К сожалению далеко не все пишут ХОРОШИЙ код, а вот насчёт «Ну и бог с ним.» — это наврядли получится… с этим ПЛОХИМ кодом, тоже рано или поздно придётся кому — то работать, фиксить его, рефакторить, дописывать, и он уж точно тогда эти VAR не похвалит))
  • +3
    Не вносить в язык синтаксический сахар из-за страха, что им неверно воспользуются и нагородят нечитабельный код, вероятно, исходит от тех людей, которым нравится переписывать одинаковые разной степени монструозные конструкции из раза в раз.
  • +3
    Мда, прочитав комментарии становится понятно почему java так медленно развивается. Добавили отличную фичу, причем ей не заставляют пользоваться в обязательном порядке. Но все равно есть недовольные
  • +2
    А почему вместо val не использовать final, либо зарезервированный const? А так за.
    • 0
      Var можно менять
    • –1
      Вариант const предлагали, и я за него голосовал. Но почему-то большинство против. Демократия, чтоб её. У final для локальных переменных уже есть семантика, тут пришлось бы навешивать дополнительную. Не уверен, что это хорошо.
  • –4
    Объясните тупому, в чём отличие
    var smt;
    от
    Object smth;
    • +2
      первое не скомпилируется.
      А вот если будет
      var x = "y"; (то же самое что и String x = "y")
      Object z = "y";
      То x.Length скомпилируется, а z.Length не скомпилируется
    • 0
      Первое нельзя написать.
      Но можно var smt = someInstance.someMethod().someOtherMethod();
      при этом smt автоматически получит конкретный тип, являющийся типом всего выражения. Не Object.
    • 0
      В дополнение к сказанному: Object не является всеобъемлющим типом. Он не супертип для примитивов.
      • 0
        C autoboxing на это разве нельзя закрыть глаза?
        • +2
          Вот после этого все и кричат, что Java тормозит. А по факту тормозят те, кто глаза закрывает.
  • +2
    var – не просто сокращение записи, не просто повышение читаемости кода.
    Это новый уровень обобщения. Позволяет не фокусироваться на конкретном типе переменной, а сосредоточится на алгоритме.
    var a = streamFactory.openForWrite();
    a.write(1);
    var b = a.bufferedCopy();
    b.write(2);
    Код не привязан к конкретным типам.
    Я могу поменять первую строку, остальное останется без изменений (если алгоритм совместим с выведенными типами).
    При всей лаконичности динамических языков у нас остаются все прелести строгой статической типизации.
    • +1
      Так и до плюсовых шаблонов недалеко, с чем вас и поздравляю, серьёзно. Может когда-нибудь.
  • –6
    Ну не нааадо! Если я захочу всяких финтов и сокращений, я чонить новое, модное и хипстерское возьму. Оставьте мне мою тихую гавань в покое!
    • +9
      А заодно уберите свои хипстерские дженерики! Так?
      • –2
        А заодно и лямбду и еще половину языка обрежем. Мыж максималисты, если резать, то резать все и без разбору!
        Я знаю что у многих языков есть Var, чем он так хорош для Java я честно не понял.
        В Rust он для сокращения текста, что соответствует их политике, в C# (как говорит сударь чуть ниже) для анонимных типов.
        А для чего тут? Чтобы перезаписывать ее разными данными?
        Нууу не знаю, у меня с фантазией на имена переменных никогда проблем не было.
        А вот когда читаю чужой код с чемнубдь типа этого:
        SomeAnswer sa = obj.someFunc(); — я сразу вижу какие данные он возвращает. (Собственно чем мне Java и нравится. Длинно но четко и ясно)
        var sa = obj.someFunc(); — тут же надо будет делать дополнительные движения, чтоб узнать что она делает.
        Вобщем ИМХО: для меня минус этого нововведения больше чем плюс.
        PS милости просим минусовать, заплючовать вы меня все равно не сможете.: р
        • –6
          Просто некоторые хотят превратить java в javascript/php.
        • +1
          В Rust он для сокращения текста, что соответствует их политике, в C# (как говорит сударь чуть ниже) для анонимных типов.

          В rust вообще let и у него сильно другая семантика, близкая ко всяким ML'ям. Это биндинг. В частности, тип биндинга может меняться в новом скоупе без изменения его имени. Т. е.
          let param = "-123";
          let param = param.parse::<i32>().unwrap();
          println!("{}", param + 3); // -120
        • 0
          В Rust он для сокращения текста, что соответствует их политике, в C# (как говорит сударь чуть ниже) для анонимных типов.
          А для чего тут? Чтобы перезаписывать ее разными данными?
          Эту переменную нельзя будет перезаписать «как угодно». Типизация остается все также статической.
          SomeClass a = new SomeClass();
          a = new SomeClass(); // скомпилируется
          a = new OtherClass(); // не скомпилируется
          var a = new SomeClass();
          a = new SomeClass(); // скомпилируется
          a = new OtherClass(); // не скомпилируется
          var sa = obj.someFunc(); — тут же надо будет делать дополнительные движения, чтоб узнать что она делает.
          Нужно будет просто навести курсор на var и ide скажет какого типа эта переменная.
  • +2
    Читаю весь этот холивар и удивляюсь… Я не знаю Java, но знаком с C# с бета-версии первого .NET Framework и довольно часто пишу что-то «для себя» (для автоматизации рутины). Ключевое слово var появилось в C# не для того, чтобы программистам было необходимо меньше печатать — для этого Microsoft развивает IntelliSense в Visual Studio. И не для того, чтобы код выглядел красиво — для этого есть гайды.

    Ключевое слово var было добавлено в C# одновременно с анонимными типами и в первую очередь для их поддержки. Какой тип вы укажите у переменной в следующей конструкции:
    var point = new { X = 1, Y = 2, Z = 3, T = 4};

    А анонимные типы появились для того, чтобы можно было их использовать в LINQ-запросах и лямбда-выражениях, поскольку описывать отдельный класс на каждый чих, который нужен только в одной-двух строчках программы, да и то в качестве промежуточных результатов — это захламление проекта. Пример реального кода:
    var list = json["data"].Select(row => new { Address = row["i"].Value<String>(), Port = row["p"].Value<String>() });
    foreach (var item in list) {...}

    PS Поздно увидел комментарий lasalas, который, в общем-то, говорил о том же самом. Уступаю пальму первенства.
  • 0
    Не в обиду Oracle, но я жду jigsaw, aot и прочее, а не новый сахар.
    • +1
      Возрадуйтесь: jigsaw точно будет в девятке, а var не факт. Насчёт aot ещё неизвестно, благо ли это.
      • 0
        Тагир, тут вопрос не в каком релизе будет, а когда будет этот самый релиз. Да и у Oracle хватает интересных задач, не хотелось бы чтобы они тратили ресурсы на сахарный var.

        • 0
          Как я понимаю, фича оказалась неожиданно несложной, поэтому решили её поковырять. Type inference уже был сделан нормально в восьмёрке. А когда будет релиз — известно, 23 марта 2017, меньше года осталось.
          • 0
            Не факт что опять не сдвинут.
  • +1
    А я вот не понимаю, в чём проблема. Даже если var введут, то ни кого же не заставляют им пользоваться. Вон в C# сколько уже var присутствует, но во многих проектах его вообще не используют, а указывают тип явно.
    • +1
      Это значит — реально var не нужен.
      • 0
        В C# var придумали не для неявного указания типа. Он там нужен для анонимных типов.
        • 0
          Ясно. Я не шарпист. Значит, философия использования var в шарпе не та, поэтому напрямую с шарпом сравнивать нельзя. Наверное, мой вывод стоило бы записать как "Это значит — реально var в шарпе не нужен". Но делать выводы вроде "раз он в шарпе не нужен — значит и в java тоже не нужен" — некорректно.
          • 0
            Для неявного указания типа его тоже можно использовать.
            Посмотрите мой комментарий внизу
            https://habrahabr.ru/post/280075/#comment_8829954
  • 0
    Интересно, а как много проектов сейчас используют var как имя переменной или класса?
    • 0
      Много. Но авторы JEP учли это. Переменные var/val никто не запрещает (сломаются только типы, если у вас объявлен class var). А так вы сможете писать без проблем:
      var var = 0;
      val val = var;
      • 0
        И это не сломает читабельность кода, нет-нет. Извините, но если код var var = Var.var(); будет валидным, это ж просто варварство будет. /хотя он и сейчас валиден, лол/

        Не, с одной стороны это меньшее из зол, согласен. С другой, это всё равно дерьмовое решение. В С++ использовали auto как раз потому, что коллизий с существующим кодом практически не было, в отличии от var или let. Также не самое приятное решение, хотя мне чисто по смыслу перевода нравится куда больше всех этих var, val и let. Написали «тип — автоматически выведеный» и не соврали. А с «пусть» или «переменная» уже непонятки. Но да кого моё мнение волнует?
        • 0
          Ну писать новый код в таком стиле явно не стоит. Это сделано, чтобы старый не сломался.
  • –2
    Если они уберут объявление типов и вообще его вырежут, никто не мешает остаться на версии, где оно еще присуствует.
    Для меня var — это взрыв мозга.
    • +1
      Вы не заметили до сих пор, что большинство кода, написанного в эпоху Java 1.0, до сих пор компилируется, а скомпилированный, как в те годы, так и сейчас, успешно выполняется? Джава — не тот язык, из которого могут просто взять и убрать что бы то ни было. За это её и любим.
  • +2
    Вообще, это посто ввод var. В таком случае никто не мешает использовать стиль по старинке. Паника off.
  • +4
    Из этого JEP мне не столько интересен var, сколько val. Потому как писать "final T v = new T();" мне совсем не нравится, слово final замусоривает код, при этом подчеркнуть что переменная финальная — полезно. Как говорится "Make val, not var"
    • –1
      Ребят, кто любит использовать финальные переменные в локальном скоупе, можете мне наконец объяснить — зачем? Ну ведь реально — просто замусоривание кода.
      Неизменность переменных в локальном скоупе? Зачем? Нет, если вы пишите методы по 100-200 строк — тогда да… но разумный-то размер метода вписывается в 10-30 строк, и там пользы от этого нет!
      • 0
        В основном (придётся немного покапитанить) это подсказка IDE и компилятору и ограждение себя от случайного затирания значения переменной значением другого выражения. Про предварительное облегчение передачи значений в методы анонимных классов говорить не буду ибо компилятор и так заставит.
        Так же радует, что у вас основной аргумент против не именно необходимость переиспользования переменной, а всего лишь "замусоривание кода".
        Ну а когда всё же реально потребуется изменяемая переменная, она будет единственной изменяемой, и её изменяемость и необходимость её изменять будет явно заметна.
        Неизменяемость переменной, на мой взгляд — того же типа хинт тем, кто читает программу (особенно с помощью IDE), как и статическая типизация, хотя, конечно, более слабый.
        Да, и кстати — я сам никогда не набираю слово "final" руками, для того, чтоб его вставить, всегда использую только подсказки и опции IDE, так что оно не добавляет мне работы.
        • 0
          Про предварительное облегчение передачи значений в методы анонимных классов говорить не буду ибо компилятор и так заставит.

          А в лямбды не заставит, т. к. там достаточно effectively final.
  • 0
    С одной стороны круто, с другой не особо, в том плане, что чем медленнее ява будет обрастать фичами, тем скорее другие языки под jvm станут не какой-то экзотикой, а равноправными жителями. И мне кажется, разрабам jvm стоило бы больше обращать внимания на них.
    Всё-таки у явы много проблем, и большинство из них по соображениям совместимости не получится уже пофиксить.
    Если хочется более фичастого и стройного языка, когда-то придется сползать с явы по-любому.
    Пока мне больше всего цейлон нравится.
  • +1
    Кстати
    Гораздо интереснее а можно ли будет объявлять метод с возвращаемый типом var?

    • +2
      Нет.
  • +1
    В C# без var нельзя обойтись в анонимных типах.
    collection.Where(x=>x.IsFlag).Select( new { x.F1, x.F2 });
    потом в методе уже можно оперировать анонимным типом в скоупе метода.
    В остальном не более синт. сахара, беда в том, что программисты понатыкают эти вары где надо и где не надо.
  • +2
    Вывод типов уже есть в джаве для лямбд. Логичный шаг — сделать для локальных переменных.
    Когда хорошо: когда тип переменной полностью ясен из правого выражения (new, Factory.create, присвоение поля, etc...). Когда плохо: когда тип не ясен без ползания в сторонние api (var out = manager.getOutput()), когда тип нужно привести к интерфейсу (Map<String,String> cache = new MyPersonalLocalCacheImplementation()).
    Ухудшится ли читаемость кода? Бесспорно. Однако, когда были введены лямбды, в которых встроен вывод типов, никто сильно не протестовал. Так что дело спасут умеренное использование и более выразительные названия переменных.

    P.S. опять разработчики джавы пытаются сэкономить буквы, но делают это не там. Уже давно пора ввести properties в джава и убрать весь этот уродский мусор с геттерами-сеттерами.
    • 0
      Насчёт геттеров-сеттеров — подозреваю, что всё тут сильно завязано на рефлексию и её подчёркнуто ограниченное использование. Нельзя в Java делать properties просто синтаксическим сахаром.
      • 0
        Как раз можно. Другие языки как Groovy, Scala, Kotlin генерируют без проблем Java-совместимые проперти. Единственное, что может дать проблемы — это JavaDoc, которому нужен исходник с геттерами-сеттерами.
    • 0
      Воспользуйтесь уже ломбоком и будет вам счастье с геттерами-сеттерами. Вот только иногда всё-равно приходится переопределять геттер/сеттер, если поле в итоге не просто проперти.
  • +1
    Ну в Java уже есть такая опция, которой принято не пользоваться, как объявление нескольких переменных одним оператором. Будет ещё одна...
  • 0
    Какой смысл писать
    List<int> a = new List<int>():

    Когда можно написать
    var a = new List<int>();

    Другой случай, когда пишется
    var a = function();

    Это неудобно, нужно заглядывать внутрь определения функции function, чтобы знать, что она возвращает.
    Таким образом пишите var тогда, когда и так понятно, какого типа должна быть переменная, никуда не ходя, и будет счастье.
    • 0
      После плюсов это была главная вещь, которая резанула глаза (и продолжает резать) в c#\Java. Все более-менее сложные объекты приходится создавать через new, но, при этом, на коде это никак не сказывается. То есть нельзя по какому-либо участку кода сказать, нужно ли переменную проверять на null или нет. В плюсах в этом плане куда более удобный для понимания синтаксис. Как минимум, понимаешь, в каком случае переменную нужно проверять на null и уточнять её тип, освобождать память и тп, а в каком — нет. И сейчас в меня какашкой бросят за такие слова.
      • 0
        Какашкой не бросим, но без примеров — пустословие какое-то получается.
        • 0
          Банальщина.
          @Nullable
          List a = null;
          List b = new List():
          int c = 0;
          /*...*/
          if (a != null)
          { a.append©; }
          b.append©;

          И ни единого способа узнать посреди кода о свойствах объектов без помощи IDE либо пролистывания кода. У плюсов всё подругому.

          std::list* a = new std::list();
          std::list b;
          int c = 0;
          if (a != nullptr)
          { a->append©; }
          b.append©;

          В плюсах b сравнивать просто не имеет смысла. А для a сразу видно, что нужно следить за памятью, как минимум, помнить, кто за неё в ответе. /* Надеюсь, обойдётся без мусорных холиваров. */

          И, да, я не гарантирую правильность Java-кода. Чукча не писатель.
          • +1
            Вы даже не представляете, какой осадок у меня выпал, когда я посмотрел на отхабренный комментарий… Это просто ©ча©тье какое-то!
          • +1
            Я, аналогично, не писатель c++ — можете пояснить фразу «В плюсах b сравнивать просто не имеет смысла»?
            С моей точки зрения (как это в c++ я не знаю) — b объявлено, но не инициализировано (в этом случае для локальных переменных в java сломается компиляция). Помимо этого я вижу, что b вроде как объект, а не ссылка на объект (но вот тут сознание буксует, чем это нам аукается — с не менеджед языками я не работал уже бог весть сколько).
            • 0
              b объявлено, но не инициализировано

              Нет, b тут будет как раз инициализировано.

              Как я понял, iCpu имеет в виду, что b не может быть null'ом вообще, а 'a' — может (потому что это указатель).
              • 0
                Ага, спасибо… Привык уже, что в java всё, кроме нативных типов, является ссылкой…
      • 0
        На null должен проверять компилятор https://kotlinlang.org/docs/reference/null-safety.html
        • –1
          Я не совсем в курсе, kotlin — это новое название Java или просто Another one bites to JVM? Я понимаю, что компилятор должен быть умным, но… Он был, есть и будет тупым. https://habrahabr.ru/post/164027/
          • 0
            Kotlin это новый язык от jetBrains/IntelliJ — произодителя idea.
            • –1
              Отлично. А причём тут Java?
              • 0
                1) Мы обсуждаем дизайн языков, в частности у вас проскочило сравнение C++, C# и Java — я высказал мнение как это должно быть
                2) Для Java программистов имеет смысл посмотреть н Kotlin так как там не только внесли новые фишки, но и смотрят на interoperability c Джавой
                Кстати, в C# 7 тоже планировали non-nullable types но вынесли похоже из последней редакции.
                • 0
                  1) Вводятся квалификатор типа "?" и оператор "?.". Казалось бы, причём тут "*" и "->"? К тому же интересно, как компилятору проверить то, что известно только в реалтайме?
                  2) Я сейчас выскажу достаточно противоречивую точку зрения, но… Чтобы нормально «посмотреть» ЯП, нужно не один день затратить. Иногда хорошая, казалось бы, идея на деле оказывается не самой удобной. К примеру с (1), в c++ можно сделать шаблоны, которые будут внедрять все эти фичи задёшего. Но что-то никто не торопится это делать. Необходимости нет.
                  Так вот, можно бегать и смотреть, какой из ЯП наиболее сладок для тебя. А можно не бегать, а выбрать один и изменять наиболее неприятные его места. Теорема Эскобара применима.
                  • 0
                    1) Вы почитайте — он не проверяет, то, что известно в рантайме, он требует от вас кода проверки, если ссылка nullable а вы ее используете не проверяя.
                    2) Давайте сделайте шаблон, чтобы
                    x -> SomeMethod() требовало бы проверки а
                    if (x!=NULL)
                    {
                    x-> SomeMethod()
                    }
                    компилировалось бы
                    3) Еще можно поверх Джавы проверять статическим анализом (что и делают IDE, но вам же нужно без IDE)
                    • 0
                      1) И не даёт нормально приводить типы между nullable и non-nullable. Где же здесь подвох?
                      2) Во-первых, «можно сделать» != «ща, за 3 минуты в комментах забацаю». Во-вторых, «внедрять все эти фичи» != «внедрять фичи с полным сохранением синтаксиса». Если мы это учитываем, то почему нет? Никто не запрещал ни перегружать оператор ->, ни добавлять функторы, ни писать макросы. Самое тупое и быстрое, что я могу придумать, это
                      #define call(a,b) if (a) a->b;
                      а в бустах давным давно лежит boost::optional. Да, написать шаблон, который оборачивает возвращаемые типы всех методов, не так просто, но возможно.
                      3) Как и плюсы точить vargrind'ом или PVS-studio.
                      • 0
                        1) Что такое "нормально"?
                        2) В котлине есть способ так же аннотировать окружающий Java код. Посмотрим, что из жтого получится.
                        3) Дада, только в Java есть уже стандартый nonnullable атрибут, насколько я знаю, а в ,NET часть FW уже аннотирована.
                        Есть разница между теоретической возможностью сделать что-то похожее, полноценным языком и поддержкой экосистемы.
                        • 0
                          1) operator=
                          2) Я, видимо, не понимаю, чего вы здесь от меня хотите или, наоборот, чего пытаетесь впихнуть.
                          3) MyClass class; //Nonnullable since long long ago in the days when ALGOL was still in some use
                          • 0
                            1) Non nullable так можно привести к nullable, а наоборот только со значком "я уверен в себе и разрешаю здесь случиться эксепшену"
                            2) Я в том смысле, что если вы и изобретете свои типы на C++ то надо еще будет обучить этому самому окружающие библиотеки — в котлине этот вопрос решен.
                            3) Я не очень понял, что вы хотите этим сказать. Если что можно написать коммент, то надо еще поддержать это в инструментах. Если это означает value тип в C++, тогда проблема переезжает в ссылки.
                            • 0
                              1) То есть, указатели с принудительной проверкой. Можно взять адрес, обратное — неверно.
                              2) Если под «этот вопрос решен» вы имеете в виду «с тех пор, как это вошло в стандарт, этим все пользуются», не вижу существенных отличий. Если же смысл в «библиотеки не придётся переделывать под новый синтаксис», то… Да ладно!
                              3) Единственный смысл ссылок — передавать в функцию объект, а не значение. Все побочные использования — синтаксический сахар, окромя move-семантики.
                              Я имею в виду простую вещь — любые попытки доказать плюсовику «а у нас можно создавать объекты, которые не обращаются в null» вызывают тупую реакцию «вы что, 20 лет шли к тому, чтобы создавать объекты на стеке?» Весь этот синтаксический сахар с короткими записями условий и автоматический возврат null при любом неверном чихе не меняет простой вещи: ваш язык упёрся в указатели. Притом. создатели ввели новый синтаксис, чтобы показать — это не указатели, но это чёртовы указатели. Они ведут себя, как указатели. Они пахнут как указатели. Они на вкус как указатели. Даже выглядят как чёртовы умные указатели, ведь в JVM нет способа заглушить сборщик мусора. Так почему мне пытаются втындюрить, что это не указатели, а манна небесная, и что все IDE их будут поддерживать, в отличие от плюсовых, в которых… всё отлично поддерживается? Или вся проблема в том, что компилятор плюсов при стандартных настройках — не истеричка?
                              • 0
                                1) Ненене, все указатели, можно сделать два указателя на один объект и они будут не nullable оба.
                                2) Не проверял, но есть возможность добавлять внешние аннотации.
                                3) Нет это не указатели, это именно ссылки — нет никакой арифметики. И non-nullable ссылки это ссылки то же. Две non-nullable ссылки могут указывать на один и тот же объект
                                • 0
                                  1) 3) А вы в курсе, что уже 21 век и что unique_ptr, shared_ptr и weak_ptr — это часть стандарта уже более 5 лет?
                                  2) Это, конечно, круто, но это просто ужасно. Вы понимаете, к чему ведёт размазывание определения поведения кода по большому числу разномастных файлов?
                                  • 0
                                    1) Тогда при чем здесь стек? (p.s. я про 21 век не в курсе, последнюю поделку на C++ ковырял лет 10 назад да и то неидеоматично)
                                    2) Это компромисс — вы можете выбрать или самому или с сообществом поддерживать внешнее описание при этом получить поддержку nullability или забить. Для typescript сообщество поддерживает, полные описания типов для распространненных javascript библиотек, например http://definitelytyped.org/
                                    • 0
                                      1) Технические подробности реализации. В 99,995% случаев для современных плюсовиков они не важны.
                                      2) Есть простая проблема: nullability требует специфического программирования. Как минимум, банальные проверки на null и выделение объектов. Конечно, в интерпретируемом языке такие проверки можно вносить извне на месте создания переменных, приравниваия или некоторых обращений, но это чистой воды костыль.
                                      Я не говорю, что в них нет нужды, это даже несколько удобнее классических подходов, тем не менее, поддержка подобных проверок — Ад и Израиль, которую таже тимлиду врага не пожелаешь.
                                      • 0
                                        2) В Котлине есть специальные операторы чтобы это делать было удобно. Это компилируемый язык.
                                        • 0
                                          2.2) Сойдёмся на термине «транслируемый». Либо так, либо тысячи модов на майн не существуют. (Спойлер: они существуют). И, да, мне могут возразить «майн не на котлине написан». Но мне всё равно. Все жабошлюшки одинаковы, когда видят мой твёрдый decompiler.
                                          2.1) Внешние аннотации подключаются к Java-коду, про Kotlin речи нет. Если в коде изначально нет защиты от null, её придётся вводить извне. И не важно, на стороне котлина или в дополнительных классах, резутьтат один.