Ни для кого не секрет, что java - это объектно-ориентированный статически-типизированный язык программирования.
Достигается это за счет двух простых принципов
В Java все это объект (и класс, и метод, и поле, и ошибка, и поток, и система, и рантайм)
Все типы необходимо явно прописывать в исходниках и их проверка осуществляется компилятором
Статическая типизация это прекрасно
Сочетание этих двух принципов заставляет нас хорошенечко постараться при написании кода:
Сформировать правильную композицию классов/объектов
Сформировать контракты
Продумать систему типов и их иерархию
Позаботиться обо всех приведениях типов
Позаботиться об обработке исключений и их иерархии
и тд
Зато это позволяет нам писать большими командами огромные проекты, которые поддерживаются и развиваются десятилетиями. Потому что:
Все загоняется в достаточно узкий стандарт, который понимают все
Большинство проблем отсекается компилятором
В больших проектах особенно остро стоит понятие "пишем один раз - читаем много", и трудозатраты, которые 1 разработчик вкладывает в чистоту кода, окупаются за счет экономии времени других разработчиков при чтении этого кода.
То что все типы прописаны явно, позволяет при чтении кода держать в голове меньше контекста и абстрагироваться от реализации на максимум.
Возьмем самый базовый пример:
public static void main(String[] args) {
CalculationResult result = calculate(args);
}
Тут я сразу вижу что за объект result мне вернулся, и что я могу с ним сделать. По большому счету мне даже не важно откуда он взялся и как устроен метод caclulate.
Альтернативой можно использовать динамический тип var
public static void main(String[] args) {
var result = calculate(args);
}
В этом случае уже придется понажимать кнопок для того чтобы понять что это за объект в среде разработки и, вероятно, даже провалиться в другой файл. А на код ревью, когда мы смотрим это в браузере такой роскоши нет.
Таким образом секундная экономия времени для разработчика пишущего код превращается в минутное приключение для каждого разработчика, который читает этот код при каждом прочтении + необходимость держать это в голове.
А если мы возьмем совсем динамические языки типа pyton, groovy или JS, то там просмотром сигнатуры метода не ограничится, придется листать реализацию метода до конца, потому что и в возвращаемом значении будет def/var.
Конечно среда разработки забирает на себя часть работы по выводу типов, но не панацея и на код ревью ее как правило нет.
В то же время среда разработки прописывает типы за нас, экономя время разработчика при написании кода.
Зачем же тогда нужна динамическая типизация?
Не энтерпрайзом едины.
Для разных задач свои инструменты и код коду рознь:
Написать скрипт - тут важно не обременять код избыточным контекстом.
Динамическая типизация здесь более чем оправдана. Вся необходимая статическая мишура будет занимать больше места чем полезная нагрузка и только снизит понятность.Написать код, исполняемый каким то другим воркером.
Тут важно абстрагироваться от типов, чтобы воркер не был этим связан, и мог использовать свои внутренние оптимальные механизмы.Написать движок задач по принципу черного ящика.
Здесь так же динамическая типизация оправдана, потому что система типов находится на стороне потребителей АПИ, и бороться внутри с типами дело сложное и неблагодарно.Написать бизнеслогику - тут уже явная типизация становится важной, потому что код должен не только быстро писаться и исполняться, но и читаться как книга (быть сам себе документацией).
Написать прототип за дешево - тут важно максимально ускорить разработку и удешевить проверку гипотезы.
Микросервисы - для небольших проектов, которые разработчик знает наизусть, а новому разработчику разобраться во всем проекте потребуется совсем немного времени, проблема явности не стоит так остро.
Почему большинство этрепрайзов пишется на статически типизированных языках?
Очевидно, потому что для них есть много готовых решений и большое комьюнити.
Но как так вышло?
Ответ: естественный отбор.
Почему у людей 2 ноги? Не потому что это идеальное количество ног, а потому что люди с другим количеством ног справлялись хуже с задачами которые перед ними были.
Динамическая типизация очень мощный инструмент, но по достижении определенного объема кода, поддерживать и развивать его становится слишком сложно, в то время как проекты со статической типизацией жили дольше и оставляли потомства больше в своей нише.
Итог
И если вернуться к названию статьи, то появление var в java (и прочего синтаксического сахара) это великолепно, потому что открыло для нее новые двери и увеличило область ее применения, что ускорит ее развитие, ведь развиваются только востребованные продукты.
Но брать и заменять везде явное указание типа на var только потому что это теперь компилируется, это идея, которая больно аукнется.
Именно это я и подразумевал под фразой "стрельнуть себе в ногу".
Тот факт, что в статически типизированные языки пытаются привнести динамики, а в динамические контроль типов, говорит о том, что золотой крайности нет. Нужно всегда четко понимать что и для чего мы делаем, выбирая подходящие инструменты.
Комментарии (31)
mantiscorp
12.06.2025 12:45var result = calculate(args);
а как насчёт чего-нибудь вроде
String s = calculate(args).toString()?
Тут тоже нет никаких явных типовdstarakozhev Автор
12.06.2025 12:45Так я и не говорю, что неявные типы это плохо.
Я говорю о том, что нужно позаботиться о том, чтобы код было удобно читать.
Иногда удобно записать все в одну строку и опустить типы,
иногда необходимо явно подсветить какой тип у нас есть на определенном этапе.
С появлением var перед разработчиком вариативности как писать стало больше.
Мое мнение, что писать везде var вместо полноценного типа только потому, что так позволяет компилятор и это короче - не верно.mantiscorp
12.06.2025 12:45Я говорю о том, что нужно позаботиться о том, чтобы код было удобно читать
ну, иногда удобне читать
var result
вместоOptional<Map<String, List<Object>>> result
...dstarakozhev Автор
12.06.2025 12:45все так)
я и не призываю отказывать от var,
но если развить этот пример, то альтернативным решением может быть придумать нормальный тип вместо Optional<Map<String, List<Object>>>, что сделает контракт метода не отвратительным, а не просто заметать под var
вся статья исключительно про эту идеюmantiscorp
12.06.2025 12:45может быть придумать нормальный тип вместо Optional<Map<String, List<Object>>>
например,
class OptionalMapOfStringAndListOfObject extends Optional<Map<String, List<Object>>>
?
panzerfaust
12.06.2025 12:45придумать нормальный тип вместо Optional<Map<String, List<Object>>>, что сделает контракт метода не отвратительным, а не просто заметать под var
Вся история развития ЯВУ это заметание сложности под половичок. Любая либа или фреймворк заметают под половичок на 100 порядков больше всего, но мешает вам именно вывод типов.
santjagocorkez
12.06.2025 12:45чтобы код было удобно читать
Для этого достаточно всего лишь пользоваться IDE вместо редактора для медленных терминалов (vi) или notepad.exe. Навёл мышкой — показало тип.
mirwide
12.06.2025 12:45Называется неявная статическая типизация. В JEP 286: Local-Variable Type Inference есть объяснение зачем. Scala, Kotlin, Go liked this.
dstarakozhev Автор
12.06.2025 12:45У меня нет сомнений, что это нормальная фича.
Статья про то, что ее нужно использовать осознанно, как и любой другой инструмент.
eandr_67
12.06.2025 12:45Динамическая типизация, это когда одной и той же переменной можно присваивать значения совершенно разных типов. Вот если бы в Java можно было написать:
var x = 12; x = "12345";
это была бы динамическая типизация.
Но нет, такое в Java невозможно. И конструкция:
var x = 12;
создаёт переменную целого типа, которой можно присваивать только целочисленные значения.
Var - не динамическая типизация, а всё та же статическая. Вся разница только в том, что вместо явного прописывания имени типа используется тип значения инициализирующего выражения, однозначно определяемый в момент компиляции. Это называется "выведение типа": оно используется во многих статически типизированных языках и не имеет никакого отношения к языкам с динамической типизацией.
dstarakozhev Автор
12.06.2025 12:45В статье нигде и не написано, что java стала динамическим языком от этого.
Но фишка с выведением типов появилась, потому что опыт динамических языков показал, что так писать может быть удобно в некоторых случаях. По этому подобный сахар принесли во многие статические языки.eandr_67
12.06.2025 12:45Вы в своей статье преподносите var как доказательство факта:
в статически типизированные языки пытаются привнести динамики
и это не соответствует реальности.
В var нет динамики. Ни в каком виде нет. Динамика - это когда что-то делается в процессе выполнения кода. Но var работает на этапе компиляции и только компиляции: статика в чистом виде.
Ваше предположение, что var появился в статически-типизированных языках под влиянием динамически-типизированных, абсолютно ошибочно. Между статическим выводом типов переменных в C#, Go, Java и полным отсутствием типов переменных в JavaScript, Python нет ничего общего.
dstarakozhev Автор
12.06.2025 12:45Спасибо за конструктивный коммент.
То, что под капотом динамики нет, я осведомлен)
Видимо фраза "привнести динамики" оказалась слишком абстрактной. Под ней я как раз имел ввиду некоторые заимствования из динамических языков.
Если я все нашел правильно,
1. Первый динамический язык LISP появился в 1958 году.
2. Первый статический язык с выведением типов Meta Language появился в 1973
Но вот чем именно вдохновлялись разработчики определенных языков, наверняка уже не узнать, к сожалению, или к счастью)aikuaiven
12.06.2025 12:451. Первый динамический язык LISP появился в 1958 году.
Но вот чем именно вдохновлялись разработчики определенных языков
Язык IPL 1956 и лямбда-исчисление Черча.
И вообще-то, ANSI Common Lisp 2ed 1991 описывает форму declare с одной из спецификаций - type, указывающей на то, что переменные в связываниях будут принимать значения только указанного типа. И это не делает Common Lisp менее динамически типизированным, а цитируя стандарт: "...носят рекомендательный характер, и могут использоваться Lisp системой для создания дополнительных проверок ошибок или более производительного скомпилированного кода. Декларации также являются хорошим способом задокументировать программу. Следует отметить, что нарушение декларации рассматривается, как ошибка (как, например, для декларации type), но реализация может не замечать этих ошибок (хотя их обнаружение, где это возможно, поощряется)."
panzerfaust
12.06.2025 12:45идея, которая больно аукнется
Так как и где оно аукается? Примеры есть? Не путайте "не знакомо/не привык" с "плохо/мешает/стреляет в ногу".
dstarakozhev Автор
12.06.2025 12:45Но брать и заменять везде явное указание типа на var только потому что это теперь компилируется, это идея, которая больно аукнется
Предложение звучит полностью так.
Сам по себе var не плохой. Плохая идея использовать его бездумно везде.
Как это аукнется:
Меньше контроля за контрактами. За счет того что типы скрыты, на возникает меньше поводов задуматься о правильности контрактов и композиции.
В своей практике часто замечал проблемы в коде, именно когда на глаза попадался сомнительный тип переменной в контексте метода.
+ Общее замедление ревьюpanzerfaust
12.06.2025 12:45Мне все же кажется, что вы ищете проблемы там, где их нет, чтобы оправдать нежелание принять новый концепт. Самое-то ироничное, что рядом живет котлин, где могут быть огромные функции без единого объявление типов - все чисто на type inference. Я этот код ревьюю каждый день, и может быть в 1 случае из 100 я вижу какой-то сильно накуренный кусок, где явные типы внесли бы ясность. Чаще как раз наоборот: если убрать бесконечные повторения String, Int, JsonObject и т.д, то взгляд меньше спотыкается, и ты читаешь именно идею кода, а не всю эту лапшу. Естественно, вразумительный нейминг обязателен.
Я еще раз рекомендую вам обдумать идею, что такое "плохо" и что такое "незнакомо".
dopusteam
12.06.2025 12:45Тут я сразу вижу что за объект result мне вернулся, и что я могу с ним сделать
Расскажите, что вы можете сделать с объектом CalculationResult)
9lLLLepuLLa
12.06.2025 12:45Как минимум перейти по ссылке на него и посмотреть что он из себя представляет.
Sigest
12.06.2025 12:45Var полезная штука, как выше сказали, никакой динамики она ни грамма не дает. Но удобно очень не копипастить огромные конструкции типов, что очень распространено в java. Вы попробуйте объявить переменную типа Record из jooq с дженериковскими скобками в 20 полей. А понять что за переменная перед вами всегда можно наведя на саму переменную курсор, ну если вы не в блокноте кодите конечно. Не понимаю претензии к var.
gsaw
12.06.2025 12:45В intellj есть галочка, если ее установить, то в редакторе будет добавляться тип переменной.
Я часто пользуюсь var. Меньше писать, компактнее код визуально. Если не обзывать переменную типа var retval =, как это некоторые делают, а писать понятное, что то вроде var calcResult = , то и читать легче. И потом если вдруг поменялся тип возвращаемый функцией, не надо переписывать вызовы.
Некоторые коллеги тоже жалуются, "не видно сразу, что за тип, надо мышкой наводить". Лайфхак с галочкой помог разрядить обстановку. :)
Sigest
12.06.2025 12:45Да, да. В последних редакциях IDEA подсказки о типах и названиях параметров появляются где надо и где не надо. Так что var вообще стал незаметным на фоне всего этого
tenzink
12.06.2025 12:45Прямо вспоминились обсуждения, когда добавлении
auto
в C++. И ничего - всё устаканилось.firehacker
12.06.2025 12:45Людям свойственно смиряться с проблемой, побухтев некоторое время. Это не значит, что проблема решена.
tenzink
12.06.2025 12:45Или означает, что проблема была надуманной. Про реальные проблемы плюсов регулярно не забывают писать, но про auto всё тихо
Не знаю как в java, но в C++, auto не только позволяет писать более чистый код, но и фиксит целый класс ошибок при итерации по ассоциативным контейнерам
Pubert
12.06.2025 12:45Дорогие комментаторы
Автор был не очень точен в формулировке. Безусловно, он имел ввиду "неявную статическую типизацию". Не хейтите его - он понял всё верно)
Статья, не считая этого косяка, очень даже дельная: не стоит использовать var на каждом шаге. Стоит использовать либо в реально очевидных местах, либо вместо монструозных типовых конструкций, либо в сприптах. Но на самом деле сильно переживать не стоит, ведь обо всём напишут в кодостайле и выскажут на ревью :)
Sigest
12.06.2025 12:45Я сейчас больше работаю с Котлин, чем с Java. В Котлине var и val с самого начала существования языка. И я хочу сказать, что никогда не было проблем с отсутствием типов в коде текста. Никогда не леплю еще и тип в дополнении при объявлении переменной. Хотя в начале плевался на такой подход с непривычки (как и на nullable ?). Но это настолько очищает код, что сейчас считаю это очень хорошей практикой. И в java программирую редко, но делаю то же самое, и очень надеюсь что эта практика скоро будет повсеместной.
elusiveavenger
К динамической типизации var не имеет никакого отношения. Он не "привносит динамики" в java.
dstarakozhev Автор
"в статически типизированные языки пытаются привнести динамики",
фраза написана так.
я не говорю что java становится от наличия var динамически типизированным языком.
Но этот синтаксический сахар в работу с java привносит одну особенность из динамических языков. Если я объявил переменную, я могу менять ее значение при рефакторинге на любой тип, не меня объявление переменной.
Либо просто не задумываться о типе переменной при ее создании.
В java так изначально не было. Подсмотрели это в динамических языках.
aamonster
Такими темпами у вас Хаскель (у которого статическая типизация настолько строгая, что Яве и не снилось) окажется динамически типизированным языком.