Groovy (произнася се грууви) е обектно ориентиран програмен език, който върви под Java платформата (JVM).
Езикът е динамичен и има сходни черти с други скриптови езици, като Python, Ruby, Perl и Smalltalk. Езикът може да се използва като скриптов език за Java платформата. Езикът се компилира динамично до байт кода на виртуалната машина на Java (JVM), което му позволява да се използва с друг Java код и Java библиотеки. Синтаксисът на езика е сходен с този на Java (с къдрави скоби). Почти всеки код написан на Java е синтактично валиден Groovy код, макар че семантиката може да е различна.
Версия 1.0 на Groovy е официално публикувана на 2 януари 2007 г. Версия 2.0 е публикувана през юли 2012 г. Новата версия на езика предстои да бъде публикувана до края на 2015 г. Новата версия ще поддържа нов Мета обектен протокол (Meta Object Protocol). След версия 2.0 езикът предлага статично компилиране, подразбиране на типовете и бързодействие което е доста близо до Java. Версия 2.4 е последната основна издадена версия, издадена под спонсорството на Pivotal Software, което приключва през март 2015.
История Джеймс Страчан пръв споменава за разработка на „Groovy“ в своя блог през август 2004 г. Няколко версии са публикувани между 2004 и 2006. След стартирането на стандартизацията на JCP, начинът на номериране на версиите се променя и затова на 2 януари 2007 г. версията е 1.0, след което всички разработки по езика се поставят под версия 1.1. На 7 декември 2007 г. 1.1-Final е публикувана и имплементирана, но скоро след това е преименувана на версия 1.5, поради големите промени направени от предишната версия.
През 2007 г., Groovy печели първа награда за иновация на JAX 2007. През 2008 г. Grails, което е Groovy базиран уеб фреймуърк печели втора награда за иновация JAX 2008.
През ноември 2008 г. SpringSource се сдобиват с компаниите на Groovy и Grails (G2One). През август 2009 г. VMWare закупуват SpringSource.
През юли 2009 г. Strachan написва в блога си: „Мога да кажа честно, че ако някой ми беше показал книга на Martin Odersksy, Lex Spoon и Bill Venner „Програмиране със Scala“ през 2013, вероятно никога нямаше да създам Groovy“. Strachan напуска проекта година преди издаването на версия 1.0 на Groovy през 2007 г.
През март 2004 г. Groovy е публикуван за одобрение чрез процеса на общността на Java (Java Community Process) като JSR 241 и е приет чрез гласуване. След 8 години на бездействие, Ръководител Спецификации (Spec Lead) променя статуса на латентен през април 2012.
На 2 юли 2012 Groovy 2.0 е публикуван с нови характеристики, включително статична компилация и механизъм за статична проверка на типовете.
Когато EMC и VMWare създават съвместното предприятие Pivotal през април 2013 г. Groovy и Grails влизат в продуктовото портфолио на компаниите. Pivotal спира спонсорирането на Groovy и Grails през април 2015. Същия месец Groovy променя своята управленска структура от Codehaus хранилище на Project Management Committee (PMC) в Apache Incubator.
Характеристики Повечето валидни Java файлове са валидни Groovy файлове. Въпреки че двата езика са доста сходни, кода на Groovy може да бъде по-сбит, защото не изисква всички необходими компоненти и не е стриктен за всички правила на Java. Това позволява на Java програмистите много лесно и неусетно да научат Groovy като започнат с познат Java синтаксис преди да започнат да използват повече Groovy идиоми.
Някои от свойствата на Groovy, които не са достъпни в Java, са статично и динамично задаване на типове (с ключовата дума def), пренаписване на оператори, вграден синтаксис за листове и асоциирани масиви (associative arrays, също известни като карти – maps), вградена поддръжка за регулярни изрази, итерация на полиморфни типове (polymorphic iteration), изрази, съдържащи се в символни низове, допълнителни помощни методи за работа с данни, и оператори за проверка за null стойности на методи (например variable?.method(), или variable?.field).
Считано от версия 2, Groovy поддържа модулност (могат да бъдат публикувани библиотеките, които се използват за проекта, което намалява размера на библиотеките на Groovy), проверка за типове на данните, статична компилация, Project Coin подобрение на синтаксиса, обработка на грешки от едно ниво, според специфичния случай (multicatch blocks) и подобряване на бързодействието посредством викане на динамични инструкции от JDK7.
Groovy има вградена поддръжка на различни езици за описание на данни (markup languages) като XML и HTML, което се постига посредством вграден DOM синтаксис. Това позволява дефиницията и манипулирането на много типове хетерогенни данни със сходни характеристики, точен синтаксис и методология на програмирането.
За разлика от Java, файлът с програмен код на Groovy може да бъде изпълнен като некомпилиран скрип, ако има код, който е извън дефинициите на който и да е клас или е клас с метод main, или е runnable, или GroovyTestCase. Един код на Groovy се изчита напълно, компилира и генерира преди да бъде изпълнен (като при Perl и Ruby). Това се случва във виртуалната машина и компилираната версия не се записва. König 2007, pp. 37 – 8
GroovyBeans / Атрибути GroovyBeans е Groovy еквивалента на JavaBeans. Groovy безусловно генерира компоненти за достъп на информацията и методи за достъп (mutator methods). В следващия код, setColor(String color) и getColor() са безусловно генерирани, а последните два реда, които на пръв поглед извикват Color директно, всъщност викат безусловно генерираните методи.König 2007, pp. 38 – 9class AGroovyBean { String color }
def myGroovyBean = new AGroovyBean()
myGroovyBean.setColor('baby blue') assert myGroovyBean.getColor() == 'baby blue'
myGroovyBean.color = 'pewter' assert myGroovyBean.color == 'pewter'Groovy предлага лесен, естествен и постоянен синтаксис за работа с листове и асоциирани масиви (lists и maps), сходен на Java синтаксис за масиви.König 2007, pp. 41 – 3def movieList = ['Dersu Uzala', 'Ran', 'Seven Samurai'] //изглежда като масив, но е лист assert movieList == 'Seven Samurai' movieList = 'Casablanca' //добавя елемент към листа assert movieList.size() == 4
def monthMap = [ 'January' : 31, 'February' : 28, 'March' : 31 ] //декларация на map assert monthMap['March'] == 31 //достъп до елемент monthMap['April'] = 30 //добавяне на елемент assert monthMap.size() == 4
Метапрограмиране Groovy дава възможност и за мета програмиране (metaprogramming), чрез ExpandoMetaClass, разширения (само в Groovy 2), Categories и DelegatingMetaClass.
ExpandoMetaClass предлага DSL, за да изрази лесно как се променя класът, това много напомня на концепцията за отворен клас на Ruby:Number.metaClass { sqrt = { Math.sqrt(delegate) } }
assert 9.sqrt() == 3 assert 4.sqrt() == 2Groovy може да променя кода си посредством метапрограмиране, което не са виждат от Java, защото всеки атрибут или метод се вика през регистър на metaclass. Промененият код може да се открие от 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 = { String property -> def stringColor = delegate if (property == 'hex') { Color.values().find { it.name().equalsIgnoreCase stringColor }?.hex
assert „WHITE“.hex == „#FFFFFF“ assert „BLUE“.hex == „#0000FF“ assert „BLACK“.hex == „#000000“ assert „GREEN“.hex == nullВ Grails фреймуърк се използва изключително много метапрограмиране, за да позволи работата с GORM dynamic finders, динамични филтри, като User.findByName('Josh') и други.
Точка и скоби Синтаксисът на Groovy позволява да се заменят скобите и точките в някои ситуации. Следния groovy код take(coffee).with(sugar, milk).and(liquor)може да бъде написан катоtake coffee with sugar, milk and liquorкоето позволява на програмиста да създава Domain-specific languages (DSLs) които могат да приличат на английска реч.
Функционално програмиране Въпреки че Groovy е основно обектно ориентиран език за програмиране, има няколко функционални свойства.
Closures Според документацията на Groovy: „Затварянията (closures) в Groovy работят подобно на методите-указател, което позволява кода да бъде писан и да бъде изпълняван в по-следващ момент“. В Groovy, този компонент поддържа и свободни променливи, т.е. променливи, които не са подадени изрично като параметър, но съществуват в контекста на декларацията, частично прилагане (partial application, което Groovy нарича „currying“„Does groovy call partial application 'currying'“. 10 Aug 2013), делегация, параметри по подразбиране, с или без тип.
Когато се работи с колекции от определен тип, типът на затварянето, подаден на операцията може да бъде определен по подразбиране:list = [1, 2, 3, 4, 5, 6, 7, 8, 9]
/* * Не-нулеви числа се подразбират за true, така че действието (четно число) % 2 == 0, ще бъде прието за false. * Типът на променливите може да бъде подразбран като Integer от IDE-то. * Може да се запише и като: * list.findAll { Integer i -> i % 2 } * list.findAll { i -> i % 2 } */ def odds = list.findAll { it % 2 }
assert odds == [1, 3, 5, 7, 9]Група изрази могат да бъдат записани в блок, който няма връзка с имплементация, като съдържащия ги обект може да бъде деклариран впоследствие чрез делегат:// Този блок съдържа изрази, без да има връзка с някаква имплементация def operations = { declare 5 sum 4 divide 3 print }
/* * Този клас ще съдържа операции, които могат да бъдат ползвани в closure-а по-горе. По-късно можем * да декларираме друг клас, имащ същите методи, но ползващ калкулации за уеб-сървър, например. */ 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
// Тук дефинираме кой ще отговаря за изразите в closure-а най-горе operations.delegate = new Expression() operations()
Curry Обикновено наричано partial application, това свойство Groovy позволява параметрите на затварянията да бъдат назначени стойности по подразбиране във всеки от аргументите си, създавайки ново затваряне със свързаните стойности. Ако зададете един аргумент на метода curry() ще фиксирате първия аргумент. Ако подадете N на брой аргументи ще има от 1 до N фиксирани аргументи.def joinTwoWordsWithSymbol = { symbol, first, second -> first + symbol + second } assert joinTwoWordsWithSymbol('#', 'Hello', 'World') == 'Hello#World'
def concatWords = joinTwoWordsWithSymbol.curry(' ') assert concatWords('Hello', 'World') == 'Hello World'
def prependHello = concatWords.curry('Hello') // def prependHello = joinTwoWordsWithSymbol.curry(' ', 'Hello') assert prependHello('World') == 'Hello World'Curry може да бъде използван и в обратна посока (фиксирайки аргументи от N до N-1), използвайки rcurry. def power = { BigDecimal value, BigDecimal power -> value ** power }
def square = power.rcurry(2) def cube = power.rcurry(3)
assert power(2, 2) == 4 assert square(4) == 16 assert cube(3) == 27Groovy поддържа също и мързеливо оценяване (lazy evaluation), намаляване/сгъване, безкрайни структури, непроменимост и други.
XML и JSON Обработка За обработката на XML и JSON, Groovy използва Builder pattern, като прави обработката на данни по-лаконична и не толкова многослойна. Например този XML:<languages> <language year="1995"> <name>java</name>