Один из часто задаваемых вопросов на No Fluff, панели экспертов Just Stuff, сводится к следующему: «Когда я должен сойти с поезда Java?» Там могут быть хорошие деньги для последнего живого программиста на COBOL, но большинству разработчиков Java, которых мы видим, все еще остается много лет в карьере, слишком много, чтобы планировать отгонять Java от заката.
Большинство участников дискуссии говорят о далеком будущем Java Platform, независимо от того, что происходит с Java Language. Умеренная. Я также считаю, что лучший выбор для молодого разработчика — придерживаться девиза бойскаута: будь готов. Продолжайте изучать новые языки и новые парадигмы программирования. Работайте в разных областях, стилях и архитектурах. Таким образом, независимо от того, что принесет будущее, подготовленный разработчик может перейти с одного поезда на другой.
После сегодняшнего дня я думаю, что мне нужно пересмотреть мой обычный ответ.
Когда разработчик Java должен перейти на новый язык? Сразу после JSR 308 становится частью языка.
Осторожно: это похоже на то, как Ктулу поднимается из глубокой души. Здесь есть внутренняя логика, но если вы не подготовлены мысленно, это может лишить вас здравомыслия, как холодный ветер через туманный болот. Я обещаю, что это последняя гиперголическая метафора. Кроме того, это был еще один пост .
Цель JSR 308 — сделать Java более точной системой типов и сделать систему типов произвольно расширяемой. Я признаю, что и понятия не имел, что это значит. К счастью, ведущий и доцент MIT Майкл Эрнст дал нам несколько примеров для рассмотрения.
Экспертная группа видит две проблемы, которые необходимо решить.
Первая проблема — это синтаксическое ограничение с аннотациями сегодня: они могут применяться только к объявлениям типов. Так, например, мы можем сказать:
@NonNull List<String> strings;
Если загружен правильный процессор аннотаций, это говорит компилятору, что строки никогда не будут нулевыми. Затем компилятор может помочь нам обеспечить это путем предупреждения о любом присваивании, которое может привести к тому, что строки получат нулевое значение.
Однако сегодня мы не можем сказать:
@NonNull List<@NonNull String> strings;
Это будет означать, что строки переменных никогда не примут нулевое значение, и что ни один из элементов списка, который он содержит, не будет нулевым.
Рассмотрим другой пример:
@NonEmpty List<@NonNull String> strings = ...;
Это список, элементы которого не могут быть нулевыми. Сам список не будет пустым. Компилятор — точнее, процессор аннотаций, используемый компилятором — поможет обеспечить это.
Они также добавят возможность аннотировать приемники методов:
void marshal(@Readonly Object jaxbElement, @Mutable Writer writer) @Readonly { ... }
Это говорит системе типов, что jaxbElement не будет изменен внутри метода, будет изменен писатель, и что выполняющийся маршал не изменит сам принимающий объект.
Предположительно, чтобы применить это последнее ограничение, маршалу будет разрешено вызывать только другие методы, которые компилятор может проверить как совместимые с @Readonly . Другими словами, применение @Readonly к одному методу начнет распространяться на другие методы, которые он вызывает.
Вторая проблема, которую решает группа экспертов, больше связана с семантикой, чем с синтаксисом. Компилятор удерживает вас от очевидных ошибок, таких как:
int i = "JSR 308";
Но это не мешает вам вызывать getValue (). ToString (), когда getValue () может вернуть значение null. В более общем смысле, нет никакого способа сообщить компилятору, что переменная не является нулевой, неизменной, интернированной или испорченной.
Их решение заключается в добавлении подключаемой системы типов к компилятору Java. Вы сможете комментировать типы (как при объявлении, так и при использовании) с помощью произвольных классификаторов типов. Они будут статически передаваться при компиляции и предоставляться подключаемым процессорам. Эрнст показал нам пример процессора, который может проверять и применять ненулевую семантику. (Доступно для загрузки по ссылке выше.) В примере базы исходного кода (приблизительно 5000 LOC) команда добавила 35 ненулевых аннотаций и подавила 4 предупреждения, чтобы обнаружить 8 скрытых ошибок NullPointerException .
Важно отметить, что Findbugs, Jlint и PMD все пропустили эти ошибки, потому что ни одна из них не включает в себя средство вывода, которое могло бы отслеживать все случаи использования аннотированных типов.
Это все звучит хорошо, правда? Поставь компилятор на работу. Пусть он выполняет утомительную работу, отслеживая расширенную семантику и сверяя их с исходным кодом.
Почему Лавкрафтовский тарабарщина тогда?
У каждого языка есть бюджет сложности . Java провалила это с помощью дженериков в Java 5. Теперь, серьезно, еще раз взглянем на это:
@NotEmpty List<@NonNull String> strings = new ArrayList<@NonNull String>();
Это даже похоже на Java? Этот сложный бюджет — просто смутное пятно в нашем зеркале заднего вида. Мы так заняты тем, чтобы компилятор был доволен, и мы полностью забудем, что это за проект.
Все это происходит в самое неподходящее время для языка Java. Сообщество по-настоящему взволновано динамическими языками. Вместо этих искажений мы могли бы просто сказать:
var strings = ["one", "two"];
А если серьезно, что бы вы предпочли написать? Правда, динамическая версия не позволяет мне заручиться поддержкой компилятора. Правда, мне нужно еще много юнит-тестов с динамическим кодом. Тем не менее, я бы предпочел, чтобы этот «низкий церемониальный» подход к глотку формализма выше
Итак, возвращаясь к этому основному Java-разработчику … похоже, есть только два варианта: более динамичный или более статичный. Более формальный и строгий или более ласково-дурацкий и лаконичный. JSR 308 будет абсолютно ускорять эту поляризацию.
И, кстати, если вы думаете, что Java язык может начать следовать движению сообщества в сторону динамических языков, Алекс Бакли, руководитель Sun по спецификации языка Java, дал нам ответ сегодня.
Он сказал: «Не ищите какие-либо ключевые слова var в Java».