Groovy (език за програмиране)

Groovy
Groovy-logo
ПарадигмаОбектно ориентиран, императивен, скриптов
Реализиране през2003; преди 21 години
АвторДжеймс Страхан
Софтуерен разработчикГилем Лафордж
Йохен Теодору
Пол Кинг
Седрик Шампо
Последна стабилна версия2.4.4 / 9 юли 2015
Типизация на даннитединамична, статична
Повлиян отJava, Python, Ruby, Perl, Smalltalk, Objective-C
ПовлияваKotlin
ПлатформаJava Virtual Machine
Софтуерен лицензApache v2.0
Уебсайтgroovy-lang.org
Groovy в Общомедия

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.[1]

История

Джеймс Страчан пръв споменава за разработка на „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.  [2]

През ноември 2008 г. SpringSource се сдобиват с компаниите на Groovy и Grails (G2One). През август 2009 г. VMWare закупуват SpringSource. [3]

През юли 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. [4]

Характеристики

Повечето валидни Java файлове са валидни Groovy файлове. Въпреки че двата езика са доста сходни, кода на Groovy може да бъде по-сбит, защото не изисква всички необходими компоненти и не е стриктен за всички правила на Java. Това позволява на Java програмистите много лесно и неусетно да научат Groovy като започнат с познат Java синтаксис преди да започнат да използват повече Groovy идиоми. [5]

Някои от свойствата на Groovy, които не са достъпни в Java, са статично и динамично задаване на типове (с ключовата дума def), пренаписване на оператори, вграден синтаксис за листове и асоциирани масиви (associative arrays, също известни като карти – maps), вградена поддръжка за регулярни изрази, итерация на полиморфни типове (polymorphic iteration), изрази, съдържащи се в символни низове, допълнителни помощни методи за работа с данни, и оператори за проверка за null стойности на методи (например variable?.method(), или variable?.field). [6]

Считано от версия 2, Groovy поддържа модулност (могат да бъдат публикувани библиотеките, които се използват за проекта, което намалява размера на библиотеките на Groovy), проверка за типове на данните, статична компилация, Project Coin подобрение на синтаксиса, обработка на грешки от едно ниво, според специфичния случай (multicatch blocks) и подобряване на бързодействието посредством викане на динамични инструкции от JDK7. [7]

Groovy има вградена поддръжка на различни езици за описание на данни (markup languages) като XML и HTML, което се постига посредством вграден DOM синтаксис. Това позволява дефиницията и манипулирането на много типове хетерогенни данни със сходни характеристики, точен синтаксис и методология на програмирането. 

За разлика от Java, файлът с програмен код на Groovy може да бъде изпълнен като некомпилиран скрип, ако има код, който е извън дефинициите на който и да е клас или е клас с метод main, или е runnable, или GroovyTestCase. Един код на Groovy се изчита напълно, компилира и генерира преди да бъде изпълнен (като при Perl и Ruby). Това се случва във виртуалната машина и компилираната версия не се записва. [8]

GroovyBeans / Атрибути

GroovyBeans е Groovy еквивалента на JavaBeans. Groovy безусловно генерира компоненти за достъп на информацията и методи за достъп (mutator methods). В следващия код, setColor(String color) и getColor() са безусловно генерирани, а последните два реда, които на пръв поглед извикват Color директно, всъщност викат безусловно генерираните методи.[9]

class 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 синтаксис за масиви.[10]

def movieList = ['Dersu Uzala', 'Ran', 'Seven Samurai'] //изглежда като масив, но е лист
assert movieList[2] == 'Seven Samurai'
movieList[3] = '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. [11]

ExpandoMetaClass предлага DSL, за да изрази лесно как се променя класът, това много напомня на концепцията за отворен клас на Ruby:

Number.metaClass {
  sqrt = { Math.sqrt(delegate) }
}

assert 9.sqrt() == 3
assert 4.sqrt() == 2

Groovy може да променя кода си посредством метапрограмиране, което не са виждат от 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') и други.[12]

Точка и скоби

Синтаксисът на 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 работят подобно на методите-указател, което позволява кода да бъде писан и да бъде изпълняван в по-следващ момент“.[13] В Groovy, този компонент поддържа и свободни променливи, т.е. променливи, които не са подадени изрично като параметър, но съществуват в контекста на декларацията, частично прилагане (partial application, което Groovy нарича „currying“[14]), делегация, параметри по подразбиране, с или без тип.

Когато се работи с колекции от определен тип, типът на затварянето, подаден на операцията може да бъде определен по подразбиране:

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,[14] това свойство 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) == 27

Groovy поддържа също и мързеливо оценяване (lazy evaluation),[15] намаляване/сгъване,[16] безкрайни структури, непроменимост [17] и други.[18]

XML и JSON Обработка

За обработката на XML и JSON, Groovy използва Builder pattern, като прави обработката на данни по-лаконична и не толкова многослойна. Например този XML:

<languages>
  <language year="1995">
    <name>java</name>
    <paradigm>Object oriented</paradigm>
    <typing>Static</typing>
  </language>
  <language year="1995">
    <name>ruby</name>
    <paradigm>Object oriented, Functional</paradigm>
    <typing>Dynamic, duck typing</typing>
  </language>
  <language year="2003">
    <name>groovy</name>
    <paradigm>Object oriented, Functional</paradigm>
    <typing>Dynamic, Static, Duck 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 Object oriented, Functional
    typing Dynamic, Duck typing
  }
  language (year: 2003) {
    name groovy
    paradigm Object oriented, Functional
    typing Dynamic, Static, Duck typing
  }
}

Също може да се създаде като поток, чрез StreamingMarkupBuilder. За да се смени имплементацията на JSON, само трябва да се смени от MarkupBuilder на JsonBuilder.[19] За да се изчетем всичко и да го намерим конкретна стойност може да ползваме метода findAll по този начин::

def languages = new XmlSlurper().parseText writer.toString()

// Тук използваме regex синтаксиса на groovy за съвпадение (=~). Изразът ще върне
// булева стойност: true, ако изразът съдържа нашия низ или false, ако не го съдържа.
def functional = languages.language.findAll { it.paradigm =~ functional }
assert functional.collect { it.name } == ["ruby", groovy]

Интерполация на символни низове

В Java, когато създаваме низ чрез конкатенация на литерал (string literal) с израз е необходимо да се терминира литерала и да се използва оператора за конкатенация (+). В Groovy можем да интерполираме низа чрез променливи и изрази от GStrings:[20]

BigDecimal account = 10.0
def text = Your account shows currently a balance of $account
assert text == Your account shows currently a balance of 10.0

Променливите и изразите, съдържащи GString стойност, трябва да бъдат декларирани с двойни кавички.

Сложен израз трябва да бъде ограден с къдрави скоби. Това предотвратява части от него да бъдат интерпретирани като принадлежащи на обграждащия низ, вместо на израза:

BigDecimal minus = 4.0
text = Your account shows currently a balance of ${account  minus}
assert text == Your account shows currently a balance of 6.0

// Без къдравите скоби, обграждащи израза, ще имаме:
text = Your account shows currently a balance of $account  minus
assert text == Your account shows currently a balance of 10.0  minus

Оценяването на изразите може да бъде забавено използвайки оператора „стрелка“ (arrow):

BigDecimal tax = 0.15
text = Your account shows currently a balance of ${->account  account * tax}
tax = 0.10

// Променливата "tax" е променена СЛЕД декларацията на GString-a. Променливите, участващи
// в изрази, биват свързани със самия израз чак, когато той бъде извикан.

assert text == Your account shows currently a balance of 9.000

Трансформация на AST (Abstract Syntax Tree)

Според документацията на Groovy, когато Groovy компилатор компилира Groovy скриптове и класове, в определена точка от изпълнението на процеса, изходният код ще бъде представен в паметта под формата на конкретно синтактично дърво (Concrete Syntax Tree), и след това ще бъде трансформиран до абстрактно синтактично дърво (Abstract Syntax Tree – AST). Целта на AST трансформацията е да позволи на разработчиците да се прикачат към процеса на компилация, за да могат да модифицират AST преди да се превърне в байт код, който ще бъде изпълнен от JVM. AST трансформациите осигуряват на Groovy подобрени метапрограмни възможности по време на компилацията, позволявайки по-голяма гъвкавост на ниво език, без да се губи от производителността при изпълнение.[21]

Примери за AST в Groovy са:

  • Singleton трансформация;
  • Category и Mixin трансформация;
  • Неотменима AST Macro;
  • Newify трансформация;

Както и други.

Traits

Според документацията на Groovy „Traits са структурна конструкция на езика, която позволява: композиция на поведението, имплементация на интерфейси по време на изпълнение, отмяна на поведение, и съвместимост със статичен проверка/компилация на типовете“

Traits могат да бъдат разглеждани като интерфейси, носещи както имплементация, така и състояние по подразбиране. Trait се дефинира чрез използване на ключовата дума trait:

trait FlyingAbility { /* декларация на trait */
    String fly() { I'm flying! } /* декларация на метод вътре в trait-а */
}

След това може да се използва като нормален интерфейс с помощта на ключовата дума implements:

class Bird implements FlyingAbility {} /* Добавя trait-а FlyingAbility към класа Bird */
def b = new Bird() /* инстанциране на нов обект от тип Bird */
assert b.fly() == I'm flying! /* класът Bird автоматично получава функционалността от trait-а FlyingAbility */

Traits позволяват широк спектър от възможности, от просто композиране до тестване. 

Съпоставка с Java[6]

Groovy се опитва да бъде възможно най-естествен за Java разроботчиците. Разработчиците на езика са се опитали да следват принципа на най-малка изненада, когато човек, идващ от Java среда, програмира на Groovy.

По-долу са поместени основните разлики между Groovy и Java:

Включени пакети по подразбиране

Следните пакети и класове са включени по подразбиране и не е необходимо допълнително да пишете import, за да ги използвате:

  • java.io.*
  • java.lang.*
  • java.math.BigDecimal
  • java.math.BigInteger
  • java.net.*
  • java.util.*
  • groovy.lang.*
  • groovy.util.*

Мултиметоди

В Groovy, методите, които ще бъдат извикани, биват избрани по време на изпълнение. Това се нарича multiple dispatch или мултиметоди (multimethods). Това означава, че методът ще бъде избран, според това какъв тип аргументи се подават по време на изпълнение (at runtime). В Java се случва обратното: методите, които ще се изпълнят се избират по време на компилация, според декларираните типове.

Следващият код, написан на Java, може да бъде компилиран и на Java, и на Groovy, но ще се държи по различен начин:

int method(String arg) {
    return 1;
}

int method(Object arg) {
    return 2;
}

Object o = "Object";
int result = method(o);

В Java, резултатът ще е:

assertEquals(2, result);

Докато в Groovy ще е:

assertEquals(1, result);

Това се случва, тъй като Java ще използва статично декларирания тип (o е декларирана от тип Object) и ще извика метода, който приема Object като параметър, докато Groovy ще избере метода по време на изпълнение. Тогава, променлива е от тип String и ще се изпълни версията на метода, която приема String като параметър.

Инициализация на масиви

В Groovy, блок с къдрави скоби ({ ...​ }) е запазен за closure-ите. Това означава, че масивите не могат да бъдат създавани със следния синтаксис:

int[] array = { 1, 2, 3}

Трябва да се използва следния синтаксис:

int[] array = [1,2,3]

Видимост на полетата

В Groovy, оставяйки поле без модификатор за достъп, няма да направи полето private за текущия пакет, както в Java:

class Person {
    String name
}

Вместо това, горния код се използва, за да се направи пропърти, което означава private поле, със съответни свързани към себе си getter и setter. Все пак е възможно да се създаде поле, което е private за текущия пакет, чрез анотация с @PackageScope:

class Person {
    @PackageScope String name
}

ARM блокове

ARM (Automatic Resource Management или автоматично управление на паметта и ресурсите) блоковете от Java 7 не са поддържани в Groovy. Вместо това, Groovy предлага редица методи, които разчитат на closure-ите, които имат същия ефект, но са много по-идиоматични. Например:

Path file = Paths.get("/path/to/file");
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }

} catch (IOException e) {
    e.printStackTrace();
}

Горният код може да се запише така:

new File('/path/to/file').eachLine('UTF-8') {
   println it
}

Или, ако предпочитате версия, по-близка до Java:

new File('/path/to/file').withReader('UTF-8') { reader ->
   reader.eachLine {
       println it
   }
}

Вътрешни класове

Имплементацията на анонимни вътрешни класове и вложени класове следва езиковите спецификации на Java, но те не бива да бъдат следвани на сляпо и трябва да се обърне внимание на различията. Готовата имплементация прилича много на това, което е направено в groovy.lang.Closure, с някой допълнения и някои разлики. Достъпът до private полета и методи например може да е проблем, но от друга страна локалните променливи не е необходимо да са final.

Статични вътрешни класове

Пример за статичен вътрешен клас:

class A {
    static class B {}
}

new A.B()

Използването на статичен вътрешен клас е най-добре поддържано в Groovy. Ако непременно се нуждаете от вътрешен клас, е най-добре той да е статичен.

Анонимни вътрешни класове

import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit

CountDownLatch called = new CountDownLatch(1)

Timer timer = new Timer()
timer.schedule(new TimerTask() {
    void run() {
        called.countDown()
    }
}, 0)

assert called.await(10, TimeUnit.SECONDS)

Инстанциране на не-статични вътрешни класове

В Java, можете да направите следното:

public class Y {
    public class X {}
    public X foo() {
        return new X();
    }
    public static X createX(Y y) {
        return y.new X();
    }
}

Groovy не поддържа синтаксиса y.new X(). Вместо това, трябва да ползвате new X(y), както е показано по-долу:

public class Y {
    public class X {}
    public X foo() {
        return new X()
    }
    public static X createX(Y y) {
        return new X(y)
    }
}

Обърнете внимание! Groovy поддържа извикването на метод с един параметър, без да му се подаде аргумент. Параметърът ще приеме стойност null. Същите правила важат и при извикването на конструктор. Има опасност да напишете new X(), вместо new X(this), например. Тъй като, това, може би е правилно, в общия случай, разработчиците на са намерили добро решение на проблема, за сега.

Ламбда изрази

Java 8 поддържа ламбда изрази и указатели към методи:

Runnable run = () -> System.out.println("Run");
list.forEach(System.out::println);

Ламда изразите в Java 8 могат, малко или много, да се считат за анонимни вътрешни класове. Groovy не поддържа този синтаксис, но може да се използват closure-и вместо това:

Runnable run = { println 'run' }
list.each { println it } // или list.each(this.&println)

GString-ове

Тъй като оградените с двойни кавички литерали биват интерпретирани като стойност от тип GString, Groovy може да върне грешка при компилация или да произведе нежелан код, ако клас с литерал от тип String, който съдържа доларов знак ("$"), е компилиран. Обикновено, Groovy автоматично каства между GString и String, ако API-то декларира типа на параметъра, но бъдете внимателни дали API-то не приема параметъра с тип Object и тогава се опитва да го кастне към истинския му тип.

Низови и символни литерали

Литерали, които са оградени с единични кавички (' ') в Groovy се възприемат за String, а тези с двойни кавички – за String или GString, в зависимост дали има интерполация в литерала.

assert 'c'.getClass()==String
assert "c".getClass()==String
assert "c${1}".getClass() in GString

Groovy ще кастне автоматично String с един символ към char, само когато стойността се присвоява на променлива от тип char. Когато извикваме метод, с аргументи от тип char, трябва или да кастнем изрично, или да се убедим, че стойността е била кастната предварително.

char a='a'
assert Character.digit(a, 16)==10 : 'But Groovy does boxing'
assert Character.digit((char) 'a', 16)==10

try {
  assert Character.digit('a', 16)==10
  assert false: 'Need explicit cast'
} catch(MissingMethodException e) {
}

Groovy поддържа два типа кастване и кастването към char се различава от това към многосимволни низове. Кастването в Groovy е „по-снизходително“ и ще вземе само първия символ от низа, докато в езиците от семейството на C, ще бъде хвърлена грешка.

// за низове с един символ, двете са еднакви
assert ((char) "c").class==Character
assert ("c" as char).class==Character

// докато за многосимволни низове са различни
try {
  ((char) 'cx') == 'c'
  assert false: 'will fail – not castable'
} catch(GroovyCastException e) {
}
assert ('cx' as char) == 'c'
assert 'cx'.asType(char) == 'c'

Примитивни типове и „обвивки“

Поради факта, че Groovy използва тип Object за всичко, той автоматично „обвива“ референтните стойности в примитивни. Пример, ползвайки int:

int i
m(i)

void m(long l) {
  println "in m(long)"                 //Този метод ще бъде извикан в Java, тъй като там разширяването на обхвата има предимство пред unboxing-а.
}

void m(Integer i) {
  println "in m(Integer)"              //Този метод ще бъде извикан в Groovy, тъй като всеки примитивен тип ползва своя wrapper клас.
}

Поведение на оператора ==

В Java ==, сравнява дали стойностите са равни, за примитивни типове, и дали обектите са еднакви, за референтните типове. В Grovy оператор == значи a.compareTo(b)==0, ако обектите са Comparable или a.equals(b) иначе. За да се сравни дали обектите от референтен тип са еднакви, може да се ползва is. Например a.is(b).

Конвертиране

Java автоматично прави разширяващи или стесняващи конвертирания между типовете.

Таблица 1. Конвертиране в Java
Конвертиране в
Конвертиране от boolean byte short char int long float double
boolean - N N N N N N N
byte N - Y C Y Y Y Y
short N C - C Y Y Y Y
char N C C - Y Y Y Y
int N C C C - Y T Y
long N C C C C - T T
float N C C C C C - Y
double N C C C C C C -

'Y' показва, че конвертирането е възможно; 'C' показва, че конвертирането е възможно с изричен каст; 'T` показва, че конвертиране е възможно, но има загуба на данни; 'N' показва, че конвертирането е невъзможно.

Groovy сериозно разширява конвертирането.

Таблица 2. Конвертиране в Groovy
Конвертиране в
Конвертиране от boolean Boolean byte Byte short Short char Character int Integer long Long BigInteger float Float double Double BigDecimal
boolean - B N N N N N N N N N N N N N N N N
Boolean B - N N N N N N N N N N N N N N N N
byte T T - B Y Y Y D Y Y Y Y Y Y Y Y Y Y
Byte T T B - Y Y Y D Y Y Y Y Y Y Y Y Y Y
short T T D D - B Y D Y Y Y Y Y Y Y Y Y Y
Short T T D T B - Y D Y Y Y Y Y Y Y Y Y Y
char T T Y D Y D - D Y D Y D D Y D Y D D
Character T T D D D D D - D D D D D D D D D D
int T T D D D D Y D - B Y Y Y Y Y Y Y Y
Integer T T D D D D Y D B - Y Y Y Y Y Y Y Y
long T T D D D D Y D D D - B Y T T T T Y
Long T T D D D T Y D D T B - Y T T T T Y
BigInteger T T D D D D D D D D D D - D D D D T
float T T D D D D T D D D D D D - B Y Y Y
Float T T D T D T T D D T D T D B - Y Y Y
double T T D D D D T D D D D D D D D - B Y
Double T T D T D T T D D T D T D D T B - Y
BigDecimal T T D D D D D D D D D D D T D T D -

'Y' показва, че конвертирането е възможно; 'D' показва, че конвертирането е възможно, когато е динамично компилиран или чрез изричен каст; 'T` показва, че конвертиране е възможно, но има загуба на данни; 'B' показва операция boxing/unboxing; 'N' показва, че конвертирането е невъзможно.

Ключови думи

Има няколко нови ключови думи в Groovy, в сравнение с Java. Те не могат да се използват за имена на променливи и т.н.

  • as
  • def
  • in
  • trait

Switch case

Case default трябва да е на последно място сред другите case-ове. Докато в Java, default case може да се постави, където и да е, в Groovy той трябва да стои на последно място.

Употреба

  • eXo Platform, Open Source Enterprise Social Collaboration платформата използва Groovy
  • Wired.com използва Groovy и Grails.[22]
  • Въпреки че Groovy може да работи в каквато и да е JVM среда, JBoss Seam фреймуърк предлага Groovy, вместо Java, като език за разработка.[23]
  • Европейското патентно ведомство (ЕПВ) разработи Data Flow Language в Groovy „за да уеднакви сходствата в процеса на комуникация с патентните ведомства на всички държави и да ги направи единствен, широко разпространен процес.“
  • Linkedin използва Groovy и Grails за някои свои подсистеми.[24]
  • XWiki SAS използва Groovy като скриптов език в своите open-source продукти.[25]
  • SoapUI предлага Groovy като език за създаване на тестове за уеб услуги.[26]
    • Sky.com използва Groovy и Grails, за да доставя голямо съдържание онлайн.[27]
    • DataMelt използва Groovy във фреймуърк за работа с числа и статистически анализ на данни
    • vCalc.com използва Groovy за всички математически изрази, подадени от потребителите.[28]
  • Eucalyptus, система за управление на облак, използва Groovy.
  • Среди за разработка

    Много интегрирани среди за разработка и текстови редактори поддържат Groovy:

      Тази страница частично или изцяло представлява превод на страницата Groovy (programming language) в Уикипедия на английски. Оригиналният текст, както и този превод, са защитени от Лиценза „Криейтив Комънс – Признание – Споделяне на споделеното“, а за съдържание, създадено преди юни 2009 година – от Лиценза за свободна документация на ГНУ. Прегледайте историята на редакциите на оригиналната страница, както и на преводната страница, за да видите списъка на съавторите. ​

    ВАЖНО: Този шаблон се отнася единствено до авторските права върху съдържанието на статията. Добавянето му не отменя изискването да се посочват конкретни източници на твърденията, които да бъдат благонадеждни.​

    Източници

    1. Groovy 2.4 And Grails 3.0 To Be Last Major Releases Under Pivotal Sponsorship // 19 Jan 2015.
    2. Groovy Wins the 2007 JAX Innovation Award // Архивиран от оригинала на 2015-10-01. Посетен на 2015-09-30.
    3. VMWare Acquires SpringSource // 10 Aug 2009.
    4. Groovy joins Apache Incubator // 11 Mar 2015.
    5. Groovy Style guide // Groovy-Lang.org. Посетен на 30 септември 2015.
    6. а б The Groovy Programming language – Differences with Java // Groovy-Lang.org.
    7. What's new in Groovy 2.0? // 28 Jun 2012.
    8. König 2007, pp. 37 – 8
    9. König 2007, pp. 38 – 9
    10. König 2007, pp. 41 – 3
    11. Groovy MetaClasses
    12. Metaprogramming Techniques in Groovy and Grails // 11 Jun 2009.
    13. Groovy – Closures // Архивиран от оригинала на 2012-05-22. Посетен на 2015-09-24.
    14. а б „Does groovy call partial application 'currying'“. 10 Aug 2013
    15. Side Notes: Lazy lists in Groovy // 3 Feb 2011.
    16. Groovy's Fold // 20 Jun 2011. Архивиран от оригинала на 2015-02-13. Посетен на 2015-09-24.
    17. Functional Programming with Groovy // 5 Nov 2011.
    18. Function programming in Groovy // Архивиран от оригинала на 2012-10-08. Посетен на 2015-09-24.
    19. JsonBuilder // Архивиран от оригинала на 2012-10-02. Посетен на 2015-09-24.
    20. Groovy Strings – Different ways of creating them // 26 Dec 2009.
    21. Runtime and compile-time metaprogramming
    22. CaseStudy Wired.com // www.springsource.org. Посетен на 2 юни 2015.
    23. Chapter 11. Groovy integration // docs.jboss.org. Посетен на 2 юни 2015.
    24. Grails at LinkedIn // Посетен на 2 юни 2015.
    25. CaseStudy XWiki // www.springsource.org. Посетен на 2 юни 2015.
    26. Scripting and the Script Library | Scripting & Properties // www.soapui.org. Посетен на 2 юни 2015.
    27. Rocher, Graeme. Graeme Rocher's Blog: Sky.com relaunches written in Grails // Graeme Rocher's Blog. 2 октомври 2008. Посетен на 2 юни 2015.
    28. Build an Equation in vCalc using Groovy. 17 април 2015. Посетен на 2 юни 2015.

    Strategi Solo vs Squad di Free Fire: Cara Menang Mudah!