Парадигма | Мультипарадигмальный : объектно-ориентированный , императивный , функциональный , аспектно-ориентированный , скриптовый |
---|---|
Разработано | Джеймс Страхан |
Разработчик | Гийом Лафорж (председатель PMC) Йохен Теодору (технический руководитель) Пол Кинг Седрик Шампо |
Впервые появился | 2003 ( 2003 ) |
Стабильный релиз | 4.0.25 [1] (21 января 2025 г. [±] ( 21 января 2025 г. ) | )
Предварительный релиз | 4.0.0-beta-1 / 6 сентября 2021 г. ( 2021-09-06 ) [2] |
Дисциплина набора текста | Динамичный , статичный , сильный , утка |
Платформа | Java SE |
Лицензия | Лицензия Apache 2.0 |
Расширения имени файла | .groovy, .gvy, .gy, .gsh [3] |
Веб-сайт | groovy-lang.org |
Основные внедрения | |
Gradle , Grails | |
Под влиянием | |
Java , Python , Ruby , Smalltalk | |
Под влиянием | |
Котлин |
Apache Groovy — это совместимый с Java синтаксисом объектно-ориентированный язык программирования для платформы Java . Это как статический, так и динамический язык с функциями, аналогичными функциям Python , Ruby и Smalltalk . Его можно использовать как язык программирования и как язык сценариев для платформы Java, он компилируется в байт-код виртуальной машины Java (JVM) и без проблем взаимодействует с другим кодом и библиотеками Java . Groovy использует синтаксис фигурных скобок, похожий на синтаксис Java. Groovy поддерживает замыкания , многострочные строки и выражения, встроенные в строки . Большая часть мощи Groovy заключается в его преобразованиях AST , запускаемых с помощью аннотаций.
Groovy 1.0 был выпущен 2 января 2007 года, а Groovy 2.0 — в июле 2012 года. Начиная с версии 2, Groovy может быть скомпилирован статически , предлагая вывод типов и производительность, близкую к производительности Java. [4] [5] Groovy 2.4 был последним крупным релизом под спонсорством Pivotal Software , которое закончилось в марте 2015 года. [6] С тех пор Groovy изменил свою структуру управления на Комитет по управлению проектами в Apache Software Foundation . [7]
Джеймс Страхан впервые рассказал о разработке Groovy в своем блоге в августе 2003 года. [8] В марте 2004 года Groovy был представлен в JCP как JSR 241 [9] и принят голосованием. Несколько версий были выпущены между 2004 и 2006 годами. После начала работы по стандартизации Java Community Process (JCP) нумерация версий изменилась, и 2 января 2007 года была выпущена версия под названием «1.0». После различных бета-версий и релиз-кандидатов с номером 1.1, 7 декабря 2007 года был выпущен Groovy 1.1 Final, который немедленно был перенумерован в Groovy 1.5, чтобы отразить множество внесенных изменений.
В 2007 году Groovy получил первую премию на конкурсе инноваций JAX 2007. [10] В 2008 году Grails , веб-фреймворк Groovy , получил вторую премию на конкурсе инноваций JAX 2008. [11]
В ноябре 2008 года SpringSource приобрела компанию Groovy and Grails (G2One). [12] В августе 2009 года VMware приобрела SpringSource. [13]
В апреле 2012 года, после восьми лет бездействия, руководитель проекта изменил статус JSR 241 на «спящий». [9]
Страхан молча покинул проект за год до выпуска Groovy 1.0 в 2007 году. [ требуется ссылка ] В октябре 2016 года Страхан заявил: «Я все еще люблю Groovy (конвейеры Jenkins такие классные!), Java, Go, TypeScript и Kotlin». [14]
2 июля 2012 года был выпущен Groovy 2.0, в который, среди прочих новых функций, были добавлены статическая компиляция и статическая проверка типов .
Когда в апреле 2013 года совместное предприятие Pivotal Software было отделено от EMC Corporation (EMC) и VMware, Groovy и Grails стали частью его продуктового портфеля. Pivotal прекратила спонсировать Groovy и Grails с апреля 2015 года. [6] В том же месяце Groovy изменила свою структуру управления с репозитория Codehaus на Комитет по управлению проектами (PMC) в Apache Software Foundation через свой инкубатор. [7] Groovy вышел из инкубатора Apache и стал проектом верхнего уровня в ноябре 2015 года. [15]
7 февраля 2020 года был выпущен Groovy 3.0. [16] Версия 4.0 была выпущена 25 января 2022 года. [17]
Большинство допустимых файлов Java также являются допустимыми файлами Groovy. Хотя эти два языка похожи, код Groovy может быть более компактным, поскольку ему не нужны все элементы, необходимые Java. [18] Это позволяет программистам Java постепенно изучать Groovy, начиная со знакомого синтаксиса Java, прежде чем приобретать больше идиом программирования Groovy . [19]
Функции Groovy, недоступные в Java, включают в себя как статическую, так и динамическую типизацию (с ключевым словом def
), перегрузку операторов , собственный синтаксис для списков и ассоциативных массивов (карт), собственную поддержку регулярных выражений , полиморфную итерацию, интерполяцию строк , добавленные вспомогательные методы и оператор безопасной навигации ?.
для автоматической проверки нулевых указателей (например, variable?.method()
, или variable?.field
). [20]
Начиная с версии 2, Groovy также поддерживает модульность (поставляет только те jar
s, которые использует проект, тем самым уменьшая размер библиотеки Groovy), проверку типов, статическую компиляцию, улучшения синтаксиса Project Coin, блоки multicatch и постоянное улучшение производительности с использованием invokedynamic
инструкций, представленных в Java 7. [ 21]
Groovy изначально поддерживает такие языки разметки , как XML и HTML , используя встроенный синтаксис Document Object Model (DOM). Эта функция позволяет определять и манипулировать многими типами гетерогенных активов данных с помощью единого и краткого синтаксиса и методологии программирования. [ необходима цитата ]
В отличие от Java, файл исходного кода Groovy может быть выполнен как (нескомпилированный) скрипт , если он содержит код вне любого определения класса, если это класс с основным методом или если это Runnable или GroovyTestCase . Скрипт Groovy полностью анализируется, компилируется и генерируется перед выполнением (аналогично Python и Ruby). Это происходит под капотом, и скомпилированная версия не сохраняется как артефакт процесса. [22]
GroovyBeans — это версия JavaBeans от Groovy . Groovy неявно генерирует геттеры и сеттеры. В следующем коде setColor(String color)
и getColor()
неявно генерируются. Последние две строки, которые, как кажется, обращаются к цвету напрямую, на самом деле вызывают неявно сгенерированные методы. [23]
класс AGroovyBean { Цвет строки } def myGroovyBean = новый AGroovyBean () myGroovyBean.setColor ( ' голубой' ) assert myGroovyBean.getColor ( ) == ' голубой ' myGroovyBean . color = 'оловянный' утверждать myGroovyBean . color == 'оловянный'
Groovy предлагает простой, последовательный синтаксис для обработки списков и карт , напоминающий синтаксис массивов Java . [24]
def movieList = [ 'Дерсу Узала' , 'Ран' , 'Семь самураев' ] // Выглядит как массив, но является списком assert movieList [ 2 ] == 'Семь самураев' movieList [ 3 ] = 'Касабланка' // Добавляет элемент в список assert movieList . size () == 4 def monthMap = [ 'Январь' : 31 , 'Февраль' : 28 , 'Март' : 31 ] // Объявляет карту assert monthMap [ 'Март' ] == 31 // Получает доступ к записи monthMap [ 'Апрель' ] = 30 // Добавляет запись в карту assert monthMap . size () == 4
Groovy предлагает поддержку расширения прототипа через , модули расширения (только в Groovy 2), категорииExpandoMetaClass
, подобные Objective-C, и . [25]DelegatingMetaClass
ExpandoMetaClass
предлагает предметно-ориентированный язык (DSL) для простого выражения изменений в классе, аналогичный концепции открытых классов Ruby :
Число.метаКласс { sqrt = { Математика . sqrt ( делегат ) } } утверждать 9 . sqrt () == 3 утверждать 4 . кврт () == 2
Изменения Groovy в коде через прототипирование не видны в Java, поскольку каждый вызов атрибута/метода в Groovy проходит через реестр метаклассов. Доступ к измененному коду из Java возможен только через реестр метаклассов.
Groovy также позволяет переопределять методы как getProperty()
, propertyMissing()
среди прочего, позволяя разработчику перехватывать вызовы объекта и указывать для них действие, упрощенным аспектно-ориентированным способом. Следующий код позволяет классу java.lang.String
реагировать на hex
свойство:
enum Color { BLACK ( '#000000' ), WHITE ( '#FFFFFF' ), RED ( '#FF0000' ), BLUE ( '#0000FF' ) String hex Color ( String hex ) { this . hex = hex } } String.metaClass.getProperty = { Свойство строки - > def stringColor = делегат if ( property == ' hex ' ) { Color.values ( ) . find { it.name ( ) . equalsIgnoreCase stringColor } ?. hex } } утверждать "БЕЛЫЙ" . hex == "#FFFFFF" утверждать "СИНИЙ" . hex == "#0000FF" утверждать "ЧЕРНЫЙ" . hex == "#000000" утверждать "ЗЕЛЕНЫЙ" . hex == null
Фреймворк Grails широко использует метапрограммирование для включения динамических поисковиков GORMUser.findByName('Josh')
, таких как и другие. [26]
Синтаксис Groovy позволяет в некоторых ситуациях опускать скобки и точки. Следующий код Groovy
принимать ( кофе ). с ( сахаром , молоком ). и ( ликёром )
можно записать как
взять кофе с сахаром , молоком и ликером
позволяя разрабатывать предметно-ориентированные языки (DSL), которые выглядят как обычный английский.
Хотя Groovy в основном является объектно-ориентированным языком, он также предлагает функции функционального программирования .
Согласно документации Groovy: «Замыкания в Groovy работают аналогично «указателю метода», позволяя писать и запускать код в более поздний момент времени». [27] Замыкания Groovy поддерживают свободные переменные, то есть переменные, которые не были явно переданы ему в качестве параметра, но существуют в контексте его объявления, частичное применение (которое он называет « каррингом » [28] ), делегирование, неявные, типизированные и нетипизированные параметры.
При работе с коллекциями определенного типа можно вывести замыкание, переданное операции над коллекцией:
список = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ] /* * Ненулевые числа приводятся к истине, поэтому, когда it % 2 == 0 (четное), это ложь. * Тип неявного параметра "it" может быть выведен как Integer средой IDE. * Его также можно записать так: * list.findAll { Integer i -> i % 2 } * list.findAll { i -> i % 2 } */ def odds = list . findAll { it % 2 } утверждать шансы == [ 1 , 3 , 5 , 7 , 9 ]
Группа выражений может быть записана в блоке замыкания без ссылки на реализацию, а отвечающий объект может быть назначен позднее с помощью делегирования:
// Этот блок кода содержит выражения без ссылки на реализацию def operations = { declare 5 sum 4 divided 3 print }
/* * Этот класс будет обрабатывать операции, которые могут быть использованы в замыкании выше. Другой класс * может быть объявлен имеющим те же методы, но использующим, например, операции веб-сервиса * в вычислениях. */ class Expression { BigDecimal value /* * Хотя Integer передается как параметр, он приводится к BigDecimal, как и было * определено. Если бы класс имел метод 'declare(Integer value)', он бы использовался вместо этого. */ def declare ( BigDecimal value ) { this . value = value } def sum ( BigDecimal valueToAdd ) { this . value += valueToAdd } def divide ( BigDecimal divisor ) { this . value /= divisor } def propertyMissing ( String property ) { if ( property == "print" ) println value } }
// Здесь определяется, кто будет отвечать на выражения в блоке кода выше. operations . delegate = new Expression () operations ()
Обычно называемая частичным применением , [28] эта функция Groovy позволяет устанавливать параметры замыканий на параметр по умолчанию в любом из их аргументов, создавая новое замыкание со связанным значением. Предоставление одного аргумента методу curry()
исправит аргумент один. Предоставление N аргументов исправит аргументы 1 .. N.
def joinTwoWordsWithSymbol = { символ , первый , второй -> первый + символ + второй } assert joinTwoWordsWithSymbol ( '#' , 'Привет' , 'Мир' ) == 'Привет#Мир' def concatWords = joinTwoWordsWithSymbol . curry ( ' ' ) assert concatWords ( 'Привет' , 'Мир' ) == 'Привет, мир' def prependHello = concatWords.curry ( 'Привет' ) // def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Привет') assert prependHello ( 'Мир' ) == 'Привет, мир'
Карри также можно использовать в обратном направлении (исправляя последние N аргументов) с помощью rcurry()
.
def power = { значение BigDecimal , степень BigDecimal -> значение ** степень } определение квадрата = мощность.rcurry ( 2 ) определение куба = мощность.rcurry ( 3 ) утвердить мощность ( 2 , 2 ) == 4 утвердить квадрат ( 4 ) == 16 утвердить куб ( 3 ) == 27
Groovy также поддерживает ленивые вычисления , [29] [30] свертки/свертки , [31] бесконечные структуры и неизменяемость , [32] и т. д. [33]
В JavaScript Object Notation ( JSON ) и обработке XML Groovy использует шаблон Builder , что делает создание структуры данных менее многословным. Например, следующий XML:
<languages> <language year= "1995" > <name> Java </name> <paradigm> объектно -ориентированный </paradigm> <typing> статический </typing> </language> <language year= "1995" > <name> Ruby </name> <paradigm> функциональный, объектно -ориентированный </paradigm> <typing> утиная типизация, динамический </typing> </language> <language year= "2003" > <name> Groovy </name> <paradigm> функциональный, объектно -ориентированный </paradigm> <typing> утиная типизация, динамический, статический </typing> </language> </languages>
можно сгенерировать с помощью следующего кода Groovy:
def writer = new StringWriter () def builder = new groovy.xml.MarkupBuilder ( writer ) builder.languages { language ( year : 1995 ) { name "Java" paradigm "object-oriented" typing " static " } language ( year : 1995 ) { name " Ruby" paradigm "functional, object-oriented" typing " duck typing, dynamic" } language ( year: 2003 ) { name "Groovy" paradigm "functional, object-oriented" typing "duck typing, dynamic, static" } }
и также может быть обработан потоковым способом через StreamingMarkupBuilder
. Чтобы изменить реализацию на JSON, MarkupBuilder
можно заменить на JsonBuilder
. [34]
Для его анализа и поиска функционального языка findAll
можно использовать метод Groovy:
def languages = new XmlSlurper ( ). parseText writer.toString ( ) // Здесь используется синтаксис регулярных выражений Groovy для сопоставления (=~), которое будет приведено к // логическому значению: либо true, если значение содержит нашу строку, либо false в противном случае. def functional = languages . language . findAll { it . paradigm =~ "functional" } assert functional . collect { it . name } == [ "Groovy" , "Ruby" ]
В Groovy строки можно интерполировать с помощью переменных и выражений с помощью GStrings: [35]
BigDecimal account = 10.0 def text = "Текущий баланс счета составляет $account" assert text == "Текущий баланс счета составляет 10.0"
Строки, содержащие переменные и выражения, должны быть объявлены с использованием двойных кавычек.
Сложное выражение должно быть заключено в фигурные скобки. Это предотвращает интерпретацию его частей как принадлежащих окружающей строке, а не выражению:
BigDecimal minus = 4.0 text = "Текущий баланс счета составляет ${account - minus}" assert text == "Текущий баланс счета составляет 6.0" // Без скобок для изоляции выражения это бы дало следующий результат: text = "Текущий баланс счета составляет $account - минус" assert text == "Текущий баланс счета составляет 10.0 - минус"
Вычисление выражения можно отложить, используя синтаксис стрелок:
BigDecimal налог = 0,15 текст = "В настоящее время на счете отображается остаток в размере ${->счет - счет*налог}" налог = 0,10 // Значение налога было изменено ПОСЛЕ объявления GString. Переменные выражения // связываются только тогда, когда выражение должно быть фактически оценено: assert text == "В настоящее время на счете отображается остаток в размере 9.000"
Согласно собственной документации Groovy, «Когда компилятор Groovy компилирует скрипты и классы Groovy, в какой-то момент процесса исходный код в конечном итоге будет представлен в памяти в виде конкретного синтаксического дерева, а затем преобразован в абстрактное синтаксическое дерево. Целью преобразований AST является предоставление разработчикам возможности подключиться к процессу компиляции, чтобы иметь возможность изменять AST до того, как он будет преобразован в байт-код, который будет запущен JVM. Преобразования AST предоставляют Groovy улучшенные возможности метапрограммирования во время компиляции, обеспечивая высокую гибкость на уровне языка без потери производительности во время выполнения». [36]
Примеры AST в Groovy:
среди прочего.
Тестовый фреймворк Spock использует преобразования AST, чтобы позволить программисту писать тесты в синтаксисе, не поддерживаемом Groovy, но затем соответствующий код преобразуется в AST в допустимый код. [37] Пример такого теста:
def "максимум #a и #b равен #c" () { expect: Math . max ( a , b ) == c где: а | б || в 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 }
Согласно документации Groovy, « Трейты — это структурная конструкция языка, которая обеспечивает: композицию поведений, реализацию интерфейсов во время выполнения, переопределение поведения и совместимость со статической проверкой типов/компиляцией».
Черты можно рассматривать как интерфейсы, несущие как реализации по умолчанию, так и состояние. Черта определяется с помощью ключевого слова trait:
черта FlyingAbility { /* объявление черты */ String fly () { "Я летаю!" } /* объявление метода внутри черты */ }
Затем его можно использовать как обычный интерфейс, используя ключевое слово implements
:
class Bird implements FlyingAbility {} /* Добавляет черту FlyingAbility к возможностям класса Bird */ def bird = new Bird () /* создает новый экземпляр Bird */ assert bird . fly () == "Я лечу!" /* класс Bird автоматически получает поведение черты FlyingAbility */
Черты характера открывают широкий спектр возможностей: от простого сочинения до тестирования.
Известные примеры внедрения Groovy включают в себя:
Многие интегрированные среды разработки (IDE) и текстовые редакторы поддерживают Groovy:
Существует одна альтернативная реализация Groovy: