Статьи

Можно ли сохранить Java?

Язык Java существует довольно давно, и, на мой взгляд, сейчас это застойный язык. Я не считаю это мертвымпотому что я верю, что это будет происходить, вероятно, десятилетиями, если не дольше. Но он, кажется, достиг своего пика эволюции, и не похоже, что он будет развиваться дальше. Это не связано с проблемами, присущими самому языку. Вместо этого кажется, что проблема заключается в стюардах Java (Sun и JCP) и их нежелании развивать язык, чтобы он оставался современным и современным, и что еще важнее — поддерживать обратную совместимость любой ценой. Не только Sun, но и кажется, что крупные корпорации с соответственно большими инвестициями в Java, такие как IBM и Oracle, не особо стараются улучшить Java. Я даже не знаю, думают ли они, что это вообще нуждается в улучшении. Серьезно,Ультраконсервативное отношение к изменениям и эволюции — это проблема с Java с моей, по общему признанию, ограниченной точки зрения.

Вот почему я не ненавижу Java. Но я ненавижу то, как к ним относятся люди, которым поручено его совершенствовать. Ясно, что многие в сообществе Java хотят такие вещи, как замыкания и синтаксис собственного свойства, но вместо этого мы получили Project Coin. Это мне грустно на самом деле. Жаль, что такие вещи, как замыкания и нативные свойства, не были рассмотрены в Java / JDK / как бы то ни было 7.

Почему бы и нет?

Я хочу знать, почему Java не может быть улучшена. У нас есть конкретные примеры того, что можно изменить основной язык основными способами. Даже способами, которые нарушают обратную совместимость, чтобы развиваться и улучшаться. Долой старое, новое. Microsoft с C # показала, что вы можете успешно развивать язык с течением времени в основных направлениях. Например, C # всегда имел синтаксис свойства, но теперь у него также есть много функций, присутствующих в динамически типизированных и функциональных языках, таких как вывод типов и, фактически, замыкания. С LINQ он представил функциональные концепции. Когда C # добавил дженерики, они сделали это правильно и сохранили информацию о типе в скомпилированном IL, тогда как Java использовала стирание типов и просто удалила типы из скомпилированного байт-кода. Здесь есть большая ирония: хотя C # начал жизнь примерно через пять или шесть лет после Java,она не только догнала, но и превзошла Java в большинстве, если не во всех отношениях, и продолжала развиваться, пока Java стала застойной.

C # не единственный пример. Python 3 является серьезной переработкой языка Python, и в него были внесены критические изменения, которые не являются обратно совместимыми. Я считаю, что они предоставляют инструмент миграции, который поможет вам, если вы захотите перейти с серии 2.x на версию 3 и выше. Microsoft тоже сделала такие вещи. Я помню, когда они привели Visual Basic в соответствие с платформой .NET и внесли некоторые довольно интенсивные изменения (в любом случае, для разработчиков VB), а также предоставили инструмент, помогающий переходу. Еще один недавний пример — Objective-C, который пережил всплеск важности главным образом из-за iPhone. Objective-C существует дольше, чем все Java, C #, Ruby, Python и т. Д. С 1980-х годов.Apple внесла улучшения в Objective-C и теперь предлагает способ определения и синтеза свойств и самых последних добавленных блоков (фактически замыканий). Если язык, предшествующий Java (кстати, Python также предшествует Java), может развиваться, я просто не понимаю, почему Java не может.

Хотя, безусловно, можно остаться на старых версиях программного обеспечения, принудительное обновление может быть хорошей идеей, поскольку оно гарантирует, что вы не получите «синдром КОБОЛ», где у вас не останется ничего, кроме двоичных файлов, которые должны работать на конкретная аппаратная платформа навсегда, и вы будете в ловушке, пока вы не переписать или уйти из бизнеса. Другая сторона этого, конечно, заключается в том, что организации не имеют бесконечного времени, денег и ресурсов для обновления каждого отдельного приложения. Иногда это тоже может быть хорошо, потому что это заставляет вас сортировать старые системы и, возможно, объединять или полностью исключать их, если они изжили свою полезность. Я считаю, что для облегчения больших переходов очень важно использовать инструменты, которые помогают автоматизировать процесс обновления, например,инструменты, которые анализируют код и, если возможно, исправляют его (сообщают обо всех изменениях в журнале) и предоставляют предупреждения и рекомендации, когда простое исправление невозможно.

Платформа JVM

Прежде чем приступить к изменениям, которые я внесу в Java, чтобы не было ощущения, что я разрабатываю с использованием простой рубашки, когда приходится набирать массу ненужного шаблонного кода, я хочу сказать, что JVM — это отличное место для быть. Очевидно, что сама JVM способствует разработке всех видов языков, о чем свидетельствует огромное количество языков, которые работают на JVM. Наиболее популярными и интересными в наши дни являются, вероятно, JRuby, Scala, Groovy и Clojure, хотя их, вероятно, сотни. Итак, я полагаю, вы могли бы аргументировать, что Java больше не нуждается в развитии, потому что мы можем просто использовать более современный язык, который работает на JVM.

Основная проблема, с которой я сталкиваюсь в этом аргументе, заключается в том, что там уже есть тонна Java-кода, и есть много организаций, которые просто не собираются допускать другие языки на основе JVM; они собираются придерживаться Java на долгое время, правильно или неправильно. Это означает, что есть хороший шанс, что даже если вам удастся убедить кого-то попробовать написать это блестящее новое веб-приложение с использованием Scala и его платформы Lift, JRuby on Rails, Grails или Clojure, шансы в какой-то момент вам тоже понадобятся поддерживать или улучшать существующие большие кодовые базы Java. Разве вы не хотели бы иметь возможность сначала обновить версию Java, которая имеет замыкания, собственный синтаксис свойств, дескрипторы метода / свойства и т. Д.?

Затем я выберу три лучших варианта, чтобы сразу улучшить Java.

Лучшие три улучшения Java

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

  • Удалить отмеченные исключения
  • Добавить замыкания
  • Добавить формальную поддержку собственности

Я думаю, что эти три изменения сделают кодирование на Java намного лучше. Посмотрим как.

Удалить отмеченные исключения

Удаляя отмеченные исключения, вы избавляетесь от тонны шаблонных предложений try / catch, которые ничего не делают, за исключением записи сообщения, переноса и повторного выброса в качестве RuntimeException, загрязнения интерфейса API пунктами throws повсеместно или худшего из всех пустых блоков catch, которые может вызвать очень тонкие и злые ошибки. За исключением непроверенных исключений, разработчики по-прежнему имеют возможность ловить исключения, которые они могут обработать. Было бы интересно посмотреть, сколько раз в типичной кодовой базе Java люди действительно обрабатывают исключения и что-то делают в точке исключения, или же они просто отстраняются от нее для обработки вызывающим абонентом, который, в свою очередь, также наносит удар и т.д. путь вверх по стеку вызовов, пока какой-нибудь глобальный обработчик не перехватит его или программа не выйдет из строя. Если бы я был игроком на пари, я бы поставил много денег, которые для большинства приложений,разработчики бьются в подавляющем большинстве случаев. Так зачем заставлять людей обращаться с чем-то, с чем они не могут справиться?

Добавить замыкания

Я специально перечислил удаление проверенных исключений первым, потому что для меня это первый шаг к возможности иметь синтаксис замыкания / блокировки, который не является абсолютно ужасным. Если вы удалите отмеченные исключения, то добавить замыкания будет гораздо проще, поскольку вам вообще не нужно беспокоиться о том, какие исключения могут быть выброшены, и, очевидно, нет необходимости объявлять исключения. Замыкания / блоки привели бы к лучшей способности обрабатывать коллекции, например, как в Groovy, но в Java у вас все еще были бы типы (обратите внимание, что здесь я также использую синтаксис буквального свойства):

// Find all people whose last name is "Smith"
List<Person> peeps = people.findAll { Person person -> person.lastName.equals("Smith");   } 

или же

// Create a list of names by projecting the name property of a bunch of Person objects
List<String> names = people.collect { Person person -> person.name; }

Не так чисто, как Groovy, но все же намного лучше, чем циклы for, которые традиционно требовались (или пытались внедрить функциональный стиль в Java, используя Jakarta Commons Collections или Google Collections ). Удаление проверенных исключений позволило бы, как упоминалось ранее, синтаксису блока не иметь дело с объявлением исключений повсеместно. Необходимость объявлять проверенные исключения в блоках делает синтаксис хуже, а не лучше, по крайней мере, когда я видел различные предложения по закрытию для Java / JDK / что угодно 7, которые не были включены. Требование типов в блоках по-прежнему раздражает, особенно если вы привыкнете к Ruby и Groovy, но это будет сносно.

Синтаксис собственного свойства

Третье изменение должно делать то же, что и Groovy для свойств, но должно вводить ключевое слово «свойство» (т.е. не полагаться на то, что кто-то случайно добавил туда модификатор доступа, как это делает Groovy). Синтаксис может быть очень чистым:

property String firstName;
property String lastName;
property Date dateOfBirth;

Компилятор может автоматически сгенерировать подходящий для вас метод получения / установки, как это делает Groovy. Это избавляет от необходимости вручную кодировать получатель / установщик. Как и в Groovy, вы должны иметь возможность переопределить одно или оба. Он чрезвычайно де-загромождает код и удаляет тонну строк глупого кода получения / установки (плюс JavaDocs, если вы все еще пишете их для каждого метода get / set). Тогда вы можете ссылаться на свойства так, как вы ожидаете: person.name — это «getter», а person.name = «Fred» — это «setter». Намного более чистый синтаксис, намного меньше стандартного кода. Кстати, если кто-то использовал слово «свойство» в своем коде, то есть в качестве имени переменной, переименовать рефакторинг не так сложно,особенно со всеми продвинутыми IDE в сообществе Java, которые делают подобные вещи во сне.

Конечно, можно было бы сделать много других вещей, но если бы только эти три были сделаны, я думаю, что Java была бы намного лучше, и, возможно, она даже вступила бы в 21-й век, как Objective-C. (См. Очень длинный, но очень хороший обзор Ars Technica Snow Leopard для получения информации о новой функции блоков Objective-C .)

Улучшения десерта

Если (как я подозреваю, они, безусловно, будут :-)) Sun / Oracle / кто-нибудь, кто примет мои предложения и внесет эти изменения и улучшит Java, то я уверен, что они захотят добавить еще несколько на десерт. После основного курса, который удаляет отмеченные исключения, добавляет замыкания и добавляет поддержку нативных свойств, десерт включает следующее:

  • Удалить тип-стирания и очистить дженерики
  • Добавить дескриптор свойства / метода
  • Строковая интерполяция
  • Тип вывода
  • Удалить «новое» ключевое слово

Очистить Дженерикс

Обобщения не должны просто удалять информацию о типе при компиляции. Если вы собираетесь использовать дженерики, делайте это правильно и не беспокойтесь о обратной совместимости. Сохраняйте информацию о типе в байт-коде, разрешите рефлексию и позвольте мне создать экземпляр «new T ()», где T — это некоторый тип, передаваемый, например, в фабричный метод. Я думаю, что улучшенная реализация дженериков может в основном копировать то, как это делает C #, и будет сделано.

Свойство / Методы

Свойство / метод ручки позволит вам ссылаться на свойство или метод непосредственно. Они сделали бы код, который теперь должен использовать строго типизированные строки и безопасный для рефакторинга (IDE, такие как IntelliJ уже знают, как искать в тексте и строках, но никогда не может быть идеальным), намного приятнее. Например, моя любимая мозоль, и я уверен, что многие другие разработчики пишут запросы Criteria в Hibernate. Вы вынуждены ссылаться на свойства как простые строки. Если свойство lastName изменено на фамилию, вам лучше убедиться, что вы перехватываете все места, на которые ссылается строка «lastName». Таким образом, вы можете заменить код следующим образом:

session.createCriteria(Person.class)
        .add(Restrictions.eq("lastName", "Smith")
        .addOrder(Order.asc("firstName")
        .list();

с помощью этого метода / свойства обрабатывает:

session.createCriteria(Person.class)
        .add(Restrictions.eq(Person.lastName, "Smith")
        .addOrder(Order.asc(Person.firstName)
        .list();

Теперь код строго типизирован и безопасен для рефакторинга. JPA 2.0 сильно пытается преодолеть наличие строк в новом API запроса критериев с его метамоделью. Но я нахожу довольно ужасным даже смотреть на то, что с необходимостью создавать или генерировать код отдельный класс «метамодели», на который вы ссылаетесь, например, «_Person.lastName» или каким-то подобным ужасным способом. Этот класс метамодели живет только для представления свойств вашего реального объекта модели с единственной целью сделать строго типизированные запросы критериев JPA 2.0. Это просто не стоит и является полным перебором. Фактически, это напоминает мне о дурных старых днях безудержной чрезмерной инженерии в Java (которая, очевидно, все еще жива и здорова во многих кругах, но я стараюсь избегать ее как можно лучше). Правильнее всего исправить язык,не изобретать что-то, что добавляет еще больше шаблонов и усложняет и без того слишком сложную экосистему.

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

Строковая интерполяция

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

log.error("The object of type  ["
    + foo.getClass().getName()
    + "] and identifier ["
    + foo.getId()
    + "] does not exist.", cause);

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

log.error("The object of type [${foo.class.name}] and identifier [${foo.id}] does not exist.", cause);

Вывод типа

Я бы также предложил добавить вывод типа, если только для локальных переменных, как в C #. Почему мы должны повторяться? Вместо того чтобы писать:

Person person = new Person();

почему мы не можем просто написать:

var person = new Person();

Я должен верить, что компилятор и все инструменты достаточно умны, чтобы вывести тип из «new Person ()». Тем более, что другие строго типизированные языки JVM, такие как Scala, делают именно такие вещи.

Elminate «новый»

Последнее, но не менее важное, и на самом деле не последнее, о чем я могу думать, но определенно последнее, о чем я пишу здесь, давайте избавимся от ключевого слова «new» и воспользуемся новым методом Ruby или синтаксисом конструктора Python, например, так:

// Ruby-like new method
var person = Person.new()

// or Python-like construction
var person = Person()

Это пришло ко мне недавно после того, как Брюс Экель выступил с прекрасной речью об эволюции языка и археологии. У него было множество действительно интересных примеров того, почему вещи такие, какие они есть, и как Java и другие языки, такие как C ++, произошли от C. Одним из примеров была причина «нового» в Java. В C ++ вы можете размещать объекты в стеке или куче, поэтому существует синтаксис конструктора на основе стека, который не использует «new», в то время как синтаксис конструктора на основе кучи использует оператор «new». Несмотря на то, что в Java есть только выделение объектов на основе кучи, в ней сохранено ключевое слово «new», которое не только является стандартным кодом, но и делает весь процесс создания объекта практически неизменным:Вы не можете ничего изменить в этом, и при этом вы не можете легко добавить хуки в процесс создания объекта.

Я не являюсь экспертом на все в деталях низкого уровня, и Брюс , очевидно , знает , что он разговаривает о пути больше , чем я, но я могу сказать , что я считаю , что синтаксис в Ruby и Python не только лучше , но более внутренне непротиворечивый, особенно в случае с Ruby, потому что там нет особой магии или соуса. В Ruby new — это просто метод в классе, как и все остальное.

Вывод на этот путь слишком длинный блог

На самом деле я не собирался писать блог, длина которого достойна блога Теда Ньюарда . Так получилось. (И мне действительно нравится читать длинные блоги Теда!) Кроме того, я обнаружил, что писать умозрительную беллетристику может быть довольно весело, поскольку я не думаю, что что-то из этого в скором времени превратится в Java, если вообще когда-нибудь, и я уверен, что в мире Java есть много людей, которые ненавидят такие вещи, как Ruby.

С http://www.nearinfinity.com/blogs/scott_leberknight