Java.next: Общие принципы языков нового поколения Это первая часть серии статей о Java.next. В первой части я собираюсь рассмотреть общие принципы, которые разделяют языки Java.next. Я выбрал четыре языка, которые вместе назвал «Java.next»: Clojure, Groovy, JRuby и Scala. На первый взгляд эти языки совершенно разные.
Clojure — это Лисп.
Groovy — это «почти Java».
JRuby сочетает в себе красоту Ruby и мощь Rails. Scala, в отличие от других языков, настаивает на необходимости статической типизации.
Как вы понимаете, постоянно идут споры о том, какой из этих языков лучше для тех или иных целей или какой вообще лучше.
В этой дискуссии как-то забывается тот факт, что у этих языков много общего.
Все они развивались на основе одного и того же языка: Java. На их дизайн постоянно влияло изучение того, что хорошо работает в Java, а что нет. В этой статье я продемонстрирую два важных принципа, общих для этих языков:
- За последнее десятилетие, когда мы писали код на объектно-ориентированных языках, основанных на виртуальных машинах, мы многое узнали о написании выразительных и удобных в сопровождении приложений.
Языки Java.next воплощают эти знания, исповедуя принцип «суть превыше церемонии».
- Решения относительно проектирования языков, которые принимались под влиянием принципа «по существу, прежде чем церемониться», привели к очень серьёзным изменениям в программировании.
Ментальный сдвиг при переходе от Java к Java.next намного значительнее, чем предыдущий сдвиг между C/C++ и Java.
- Все является объектом
- Простота объявления свойств
- Мощные коллекции
- Функциональное программирование
- Переопределение операторов
- Простота поддержки исключений
- Добавление пользовательских методов к существующим объектам
- Создание собственных языковых конструкций
Все является объектом
В Java нам каждый день приходится сталкиваться с разницей между объектами и примитивами.Это поднимает три практические проблемы:
- Приходится дублировать API: один метод для объектов, другой для примитивов.
Или, что еще хуже, один метод для объектов и один метод для нескольких примитивных типов.
- Числовые типы по умолчанию имеют ограниченный диапазон.
Если выйти за его пределы, программа волшебным образом сломается.
- Вы не можете использовать интуитивные математические операции (+, - и т. д.) со специальными точными числовыми типами.
Вы можете вызывать методы любого типа, используя один и тот же синтаксис.
; clojure
(.
1 floatValue)
1.0
// groovy
1.floatValue()
===> 1.0
# ruby
1.to_f
=> 1.0
// scala
1.floatValue
res1: Float = 1.0
Простота объявления свойств
В Java, чтобы создать свойство, вы должны определить поле, метод получения, метод установки и (довольно часто) конструктор, а также включить повсюду правильные модификаторы доступа.В Java.next все это можно определить за один шаг.
; clojure
(defstruct person :first-name :last-name)
// groovy
class Person {
def firstName
def lastName
}
# ruby
Person = Struct.new(:first_name, :last_name)
// scala
case class Person(firstName: String, lastName: String) {}
Если вам нужно переопределить определенный метод получения, установки или конструктор для класса, вы можете сделать это без необходимости утомительно вводить код для всех других стандартных случаев.
И это еще не все! Все эти языки придерживаются принципа «Существует более чем один способ сделать это» (TMTOWTDI), поэтому существует несколько вариантов реализации показанных выше приемов.
Мощные коллекции
Языки Java.next предлагают удобный синтаксис для наиболее важных типов коллекций: массивов и карт. Кроме того, вы можете объединить несколько операций с коллекциями, передавая функции в качестве аргументов, что устраняет необходимость в итераторах и циклах.
Например, чтобы найти все нечетные квадраты значений от одного до десяти, можно сделать следующее: ; clojure
(filter (fn [x] (= 1 (rem x 2))) (map (fn [x] (* x x)) (range 10)))
(1 9 25 49 81)
// groovy
(1.10).
collect{ it*it }.
findAll { it%2 == 1} ===> [1, 9, 25, 49, 81] # ruby (1.10).
collect{ |x| x*x }.
select{ |x| x%2 == 1} => [1, 9, 25, 49, 81] // scala (1 to 10).
map(x => x*x).
filter(x => x%2 == 1)
res20: Seq.Projection[Int] = RangeMF(1, 9, 25, 49, 81)
Аналогичные удобства предусмотрены и для работы с парами «ключ-значение», или, другими словами, хеш-таблицами или словарями.
Функциональное программирование.
Удобство коллекций, о которых мы только что говорили, — это частный случай более общей идеи: функционального программирования.
Java.next поддерживает функции как объекты первого класса, позволяя передавать их в качестве аргументов, определять функции, создающие новые функции, и использовать замыкания.
В качестве простого примера рассмотрим создание функции, которая добавляет некоторое значение, определенное во время выполнения: ; clojure
(defn adder [x] (fn [y] (+ x y)))
// groovy
adder = { add -> { val -> val + add } }
# ruby
def adder(add)
lambda { |x| x + add }
end
// scala
def sum(a: Int)(b: Int) = a + b
Переопределение операторов
В Java вы не можете переопределять операторы.
Для таких типов, как BigDecimal, математические операции выглядят следующим образом: // Java math
balance.add(balance.multiply(interest));
Языки Java.next позволяют переопределять операторы.
Это позволяет создавать новые типы, которые обрабатываются так же, как и встроенные.
Те.
вы можете создавать типы ComplexNumber или RationalNumber, поддерживающие операторы +, -, * и /.
; Clojure
(+ balance (* balance interest))
// Groovy
balance + (balance * interest)
# JRuby
balance + (balance * interest)
// Scala (See [1])
balance + (balance * interest)
Простота поддержки исключений
Проверенные исключения оказались неудачным экспериментом.Из-за них Java-код только раздувается, особо не способствуя улучшению обработки ошибок.
Хуже того, поддержание проверяемых исключений на границе между уровнями абстракции — настоящая головная боль.
Введение новых типов исключений не должно приводить к перекомпиляции! Языки Java.next не требуют объявления проверенных исключений или явной обработки проверенных исключений, поступающих из другого кода.
Хотя тот факт, что другие языки умеют игнорировать некрасивые проверяемые исключения языка Java, говорит о неожиданной гибкости Java как платформы.
Добавление пользовательских методов к существующим объектам
В Java вы не можете добавлять методы к существующим типам.
Это приводит к проблемам в объектном моделировании, когда разработчикам приходится создавать служебные классы, нарушающие принципы ООП: // Java (from the Jakarta Commons)
public class StringUtils {
public static boolean isBlank(String str) {
int strLen;
if (str == null || (strLen = str.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((Character.isWhitespace(str.charAt(i)) == false)) {
return false;
}
}
}
В языках Java.next к существующим типам можно добавлять методы: ; Clojure
(defmulti blank? class)
(defmethod blank? String [s] (every? #{\space} s))
(defmethod blank? nil [_] true)
// Groovy
String.metaClass.isBlank = {
length() == 0 || every { Character.isWhitespace(it.charAt(0)) }
}
# Ruby (from Rails)
class String
def blank?
empty? || strip.empty?
end
end
// Scala
class CharWrapper(ch: Char) {
def isWhitespace = Character.isWhitespace(ch)
}
implicit def charWrapper(ch: Character) = new CharWrapper(ch)
class BlankWrapper(s: String) {
def isBlank = s.isEmpty || s.forall(ch => ch.isWhitespace)
}
implicit def stringWrapper(s: String) = new BlankWrapper(s)
Создание собственных языковых конструкций
В Java есть язык и библиотеки.Они принципиально разные: вы можете создавать новые библиотеки, но не можете создавать новые языковые конструкции.
В языках Java.next грань между языком и библиотеками более размыта.
Вы можете создавать новые выражения, которые будут работать так, как если бы они были встроены в язык.
Например, Clojure содержит функцию и : ; clojure
(and 1 2) => 2
Но возможно ваша проблема не так проста.
Вам нужна функция большинство , который возвращает true, если большинство аргументов имеют значение true. В Clojure такой функции нет, но вы можете создать ее самостоятельно: ; clojure
(most 1 2) => true
(most 1 2 nil) => true
(most 1 nil nil) => false
Реальный вопрос здесь не в том, нужен ли моему языку условный оператор.
большинство .
Возможно, и не нужен.
Ключевым моментом является то, что разные варианты использования требуют разных возможностей.
В языках Java.next граница между языком и библиотеками минимальна.
Вы можете адаптировать язык к своим потребностям, вместо того, чтобы искать обходные пути.
Или вот еще пример.
Давайте посмотрим на синтаксис атрибутов в Ruby: # Ruby
class Account
attr_accessor :name
dsl_attribute :type
end
attr_accessor встроено в язык.
dsl_attribute это библиотечный метод, который я написал.
Это позволяет вам опускать символ «=" для присвоения значений.
Те.
# normal attributes
account.name = "foo"
# equals-free attributes
account.type checking
Заключение
Языки Java.next имеют много общего.Хотя для демонстрации я использовал небольшие отдельные примеры, реальная сила заключается в совместном использовании всех этих функций.
Когда они объединяются в языках Java.next, это приводит к совершенно другому стилю кодирования.
- Вам больше не нужно писать код защитно, прибегая к фабрикам, шаблонам и внедрению зависимостей, чтобы ваш код был тестируемым и легко изменяемым.
Вместо этого вы создаете минимальное решение, а затем развиваете его.
- Вместо написания кода непосредственно на языке Java.next вы можете создать свой собственный предметно-ориентированный язык, который лучше всего подходит для вашей предметной области.
Многие люди ждут «следующего большого языка».
Этот язык уже здесь.
Только это не один язык, а набор идей, которые я перечислил (плюс, возможно, некоторые, которые я пропустил), выраженные на языках Java.next. Заслуживает ли Java.next слова «крутой»? Несомненно.
По моему опыту, переход от Java к Java.next во всех отношениях столь же крут, как и предыдущие тектонические сдвиги в отрасли, как с точки зрения кривой обучения, так и с точки зрения роста производительности.
Поскольку мы работаем в сфере разработки, нам нужно поднять планку и начать изучать Java.next. Затем мы сможем обсудить различия между этими языками.
Я постараюсь осветить уникальные возможности языков Java.next в будущих статьях этой серии.
От переводчика: Я решил чаще использовать английские термины в скобках, потому что предпочитаю их.
Иногда я вообще не перевожу термин, если не знаю хорошего варианта.
Дайте мне знать, подходит это вам или нет. И будьте снисходительны к моим ошибкам.
;) Теги: #java #Groovy #scala #jruby #clojure #Разработка сайтов
-
Атомный Веб-Дизайн
19 Oct, 24 -
Разрушители Мифов Против Заговора Молчания
19 Oct, 24 -
Умение Рассчитывать
19 Oct, 24 -
Новый Блог От Intellin
19 Oct, 24 -
77 Полезных Ссылок Для Email-Маркетологов
19 Oct, 24