Inleiding tot Groovy Language

1. Overzicht

Groovy is een dynamische scripttaal voor de JVM. Het compileert naar bytecode en combineert naadloos met Java-code en bibliotheken.

In dit artikel gaan we enkele van de essentiële functies van Groovy bekijken, waaronder basissyntaxis, besturingsstructuren en verzamelingen.

Vervolgens zullen we enkele van de belangrijkste kenmerken bekijken die het een aantrekkelijke taal maken, inclusief nulveiligheid, impliciete waarheid, operators en strings.

2. Omgeving

Als we Groovy in Maven-projecten willen gebruiken, moeten we het volgende toevoegen aan het pom.xml:

  // ... org.codehaus.gmavenplus gmavenplus-plugin 1.5 // ... org.codehaus.groovy groovy-all 2.4.10 

De meest recente Maven-plug-in is hier te vinden en de nieuwste versie van het groovy-all hier.

3. Basisfuncties

Er zijn veel handige functies in Groovy. Laten we nu eens kijken naar de basisbouwstenen van de taal en hoe deze verschilt van Java.

Laten we nu eens kijken naar de basisbouwstenen van de taal en hoe deze verschilt van Java.

3.1. Dynamisch typen

Een van de belangrijkste kenmerken van Groovy is de ondersteuning voor dynamisch typen.

Typedefinities zijn optioneel en werkelijke typen worden tijdens runtime bepaald. Laten we deze twee klassen eens bekijken:

klasse Duck {String getName () {'Duck'}} klasse Cat {String getName () {'Cat'}} 

Die twee klassen definiëren hetzelfde getName methode, maar het is niet expliciet vastgelegd in een contract.

Stel je nu voor dat we een lijst hebben met objecten met eenden en katten die de getName methode. Met Groovy kunnen we het volgende doen:

Duck duck = nieuw Duck () Cat cat = new Cat () def list = [duck, cat] list.each {obj -> println obj.getName ()}

De code wordt gecompileerd en de uitvoer van de bovenstaande code zou zijn:

Duck Cat

3.2. Impliciete waarheidsconversie

Net als in JavaScript evalueert Groovy elk object naar een boolean indien nodig, bijv. bij gebruik in een als verklaring of bij het ontkennen van de waarde:

if ("hallo") {...} if (15) {...} if (someObject) {...}

Er zijn een paar eenvoudige regels die u bij deze conversie moet onthouden:

  • Niet leeg Collecties, arrays, kaarten evalueren naar waar
  • Matcher met ten minste één match resulteert in waar
  • Iteratoren en Opsommingen met verdere elementen worden gedwongen waar
  • Niet leeg Snaren, GStrings en CharSequences, worden gedwongen waar
  • Getallen die niet nul zijn, worden geëvalueerd naar waar
  • Objectreferenties die niet nul zijn, worden gedwongen waar

Als we de impliciete waarheidsconversie willen aanpassen, kunnen we onze asBoolean () methode.

3.3. Invoer

Sommige pakketten worden standaard geïmporteerd en we hoeven ze niet expliciet te importeren:

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

4. AST-transformaties

AST (Abstracte syntaxisboom) -transformaties stellen ons in staat deel te nemen aan het Groovy-compilatieproces en het aan te passen aan onze behoeften. Dit wordt gedaan tijdens het compileren, dus er is geen prestatieverlies bij het uitvoeren van een applicatie. We kunnen onze AST-transformaties maken, maar we kunnen ook de ingebouwde gebruiken.

We kunnen onze transformaties creëren, of we kunnen profiteren van de ingebouwde transformaties.

Laten we eens kijken naar enkele annotaties die de moeite waard zijn om te weten.

4.1. Annotatie Type gecontroleerd

Deze annotatie wordt gebruikt om de compiler te dwingen om strikte typecontrole uit te voeren voor geannoteerde stukjes code. Het typecontrolemechanisme is uitbreidbaar, zodat we desgewenst zelfs nog strengere typecontrole kunnen bieden dan in Java beschikbaar is.

Laten we het onderstaande voorbeeld eens bekijken:

klasse Universe {@TypeChecked int answer () {"tweeënveertig"}}

Als we deze code proberen te compileren, zien we de volgende foutmelding:

[Statische typecontrole] - Kan de waarde van het type java.lang.String niet retourneren op de methode die het type int retourneert

De @TypeChecked annotatie kan worden toegepast op klassen en methoden.

4.2. Annotatie CompileStatic

Deze annotatie stelt de compiler in staat om compilatietijdcontroles uit te voeren zoals het wordt gedaan met Java-code. Daarna voert de compiler een statische compilatie uit, waardoor het Groovy-metaobject-protocol wordt omzeild.

Wanneer een klasse is geannoteerd, worden alle methoden, eigenschappen, bestanden, innerlijke klassen, enz. Van de geannoteerde klasse type-gecontroleerd. Wanneer een methode wordt geannoteerd, wordt statische compilatie alleen toegepast op die items (sluitingen en anonieme innerlijke klassen) die door die methode worden omsloten.

5. Eigenschappen

In Groovy kunnen we POGO's (Plain Old Groovy Objects) maken die op dezelfde manier werken als POJO's in Java, hoewel ze compacter zijn omdat getters en setters worden automatisch gegenereerd voor openbare eigendommen tijdens de compilatie. Het is belangrijk om te onthouden dat ze alleen worden gegenereerd als ze nog niet zijn gedefinieerd.

Dit geeft ons de flexibiliteit om attributen te definiëren als open velden, terwijl we de mogelijkheid behouden om het gedrag te overschrijven bij het instellen of ophalen van de waarden.

Beschouw dit object:

class Person {String name String lastName}

Omdat het standaardbereik voor klassen, velden en methoden openbaar - dit is een openbare klasse en de twee velden zijn openbaar.

De compiler converteert deze naar privévelden en voegt getName (), setName (), getLastName () en setLasfName () methoden. Als we het setter en getter voor een bepaald veld zal de compiler geen openbare methode maken.

5.1. Snelkoppelingsnotaties

Groovy biedt een snelkoppelingsnotatie voor het ophalen en instellen van eigenschappen. In plaats van de Java-manier om getters en setters aan te roepen, kunnen we een veldachtige toegangsnotatie gebruiken:

resourceGroup.getResourcePrototype (). getName () == SERVER_TYPE_NAME resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME resourcePrototype.setName ("iets") resourcePrototype.name = "iets"

6. Operatoren

Laten we nu eens kijken naar nieuwe operators die zijn toegevoegd bovenop degene die bekend zijn van gewoon Java.

6.1. Null-Safe Dereference

De meest populaire is de nulveilige dereferentie-operator “?” waardoor we een NullPointerException bij het aanroepen van een methode of het openen van een eigenschap van een nul voorwerp. Het is vooral handig bij aaneengeschakelde oproepen waarbij een nul waarde kan op een bepaald punt in de keten voorkomen.

We kunnen bijvoorbeeld veilig bellen:

Stringnaam = persoon? .Organisatie? .Ouder? .Naam

In het bovenstaande voorbeeld als a persoon, persoon.organisatie, of organisatie. ouder zijn nul, dan nul wordt geretourneerd.

6.2. Elvis-operator

De Elvis-operator “?:”Laat ons ternaire uitdrukkingen samenvatten. Deze twee zijn gelijkwaardig:

String name = person.name?: DefaultName

en

String naam = person.name? person.name: defaultName

Ze kennen allebei de waarde toe van person.name naar de naamvariabele als dat zo is Groovy waar (in dit geval niet nul en heeft een niet nul lengte).

6.3. Ruimteschip Operator

De ruimteschipoperator “” is een relationele operator die werkt als die van Java vergelijk met() die twee objecten vergelijkt en -1, 0 of +1 retourneert, afhankelijk van de waarden van beide argumenten.

Als het linkerargument groter is dan het rechter, geeft de operator 1 terug. Als het linkerargument kleiner is dan het rechtse, retourneert de operator −1. Als de argumenten gelijk zijn, wordt 0 geretourneerd.

Het grootste voordeel van het gebruik van de vergelijkingsoperatoren is de vlotte afhandeling van nulls zoals dat x y zal nooit een NullPointerException:

println 5 null

Het bovenstaande voorbeeld zal 1 als resultaat afdrukken.

7. Snaren

Er zijn meerdere manieren om letterlijke tekenreeksen uit te drukken. De benadering die in Java wordt gebruikt (tekenreeksen met dubbele aanhalingstekens) wordt ondersteund, maar het is ook toegestaan ​​om enkele aanhalingstekens te gebruiken wanneer dit de voorkeur heeft.

Meerregelige tekenreeksen, in andere talen soms heredocs genoemd, worden ook ondersteund, met behulp van drievoudige aanhalingstekens (enkel of dubbel).

Meerregelige tekenreeksen, in andere talen soms heredocs genoemd, worden ook ondersteund, met behulp van drievoudige aanhalingstekens (enkel of dubbel).

Strings gedefinieerd met dubbele aanhalingstekens ondersteunen interpolatie met de ${} syntaxis:

def name = "Bill Gates" def greeting = "Hallo, $ {name}"

In feite kan elke uitdrukking in de ${}:

def name = "Bill Gates" def greeting = "Hallo, $ {name.toUpperCase ()}"

Een tekenreeks met dubbele aanhalingstekens wordt een GString genoemd als deze een uitdrukking bevat ${}anders is het een vlakte Draad voorwerp.

De onderstaande code wordt uitgevoerd zonder de test te mislukken:

def a = "hallo" assert a.class.name == 'java.lang.String' def b = 'hallo' assert b.class.name == 'java.lang.String' def c = "$ {b} "assert c.class.name == 'org.codehaus.groovy.runtime.GStringImpl'

8. Collecties en kaarten

Laten we eens kijken hoe sommige basisgegevensstructuren worden behandeld.

8.1. Lijsten

Hier is wat code om een ​​paar elementen toe te voegen aan een nieuwe instantie van ArrayList in Java:

Lijstlijst = nieuwe ArrayList (); list.add ("Hallo"); list.add ("Wereld");

En hier is dezelfde bewerking in Groovy:

List list = ['Hallo', 'Wereld']

Lijsten zijn standaard van type java.util.ArrayList en kan ook expliciet worden gedeclareerd door de overeenkomstige constructor aan te roepen.

Er is geen aparte syntaxis voor een Set, maar we kunnen type gebruiken dwang daarom. Gebruik ofwel:

Begroeting instellen = ['Hallo', 'Wereld']

of:

def begroeting = ['Hallo', 'Wereld'] als ingesteld

8.2. Kaart

De syntaxis voor een Kaart is vergelijkbaar, zij het een beetje meer uitgebreid, omdat we sleutels en waarden moeten kunnen specificeren die worden gescheiden door dubbele punten:

def key = 'Key3' def aMap = ['Key1': 'Value 1', Key2: 'Value 2', (key): 'Another value']

Na deze initialisatie krijgen we een nieuw LinkedHashMap met de vermeldingen: Key1 -> Value1, Key2 -> Value 2, Key3 -> Another Value.

We hebben op veel manieren toegang tot vermeldingen op de kaart:

println aMap ['Key1'] println aMap [key] println aMap.Key1

9. Controlestructuren

9.1. Voorwaardelijke voorwaarden: als-anders

Groovy ondersteunt het voorwaardelijke als / anders syntaxis zoals verwacht:

if (...) {// ...} else if (...) {// ...} else {// ...} 

9.2. Voorwaardelijke voorwaarden: schakelkast

De schakelaar -instructie is achterwaarts compatibel met Java-code, zodat we gevallen kunnen doorlopen die dezelfde code voor meerdere overeenkomsten delen.

Het belangrijkste verschil is dat a schakelaar kan matching uitvoeren met meerdere verschillende waardetypes:

def x = 1.23 def result = "" switch (x) {case "foo": result = "found foo" break case "bar": resultaat + = "bar" break case [4, 5, 6, 'inList'] : result = "list" break case 12..30: result = "range" break case Number: result = "number" break case ~ / fo * /: result = "foo regex" break case {it <0}: / / of {x <0} result = "negative" break default: result = "default"} println (resultaat)

Het bovenstaande voorbeeld wordt afgedrukt aantal.

9.3. Lussen: terwijl

Groovy ondersteunt het gebruikelijke terwijl loops zoals Java doet:

def x = 0 def y = 5 terwijl (y--> 0) {x ++}

9.4. Lussen: voor

Groovy omarmt deze eenvoud en moedigt sterk aan voor loops volgens deze structuur:

voor (variabele in iterable) {body}

De voor lus herhaalt zich itereerbaar. Veelgebruikte iterables zijn reeksen, verzamelingen, kaarten, arrays, iterators en opsommingen. In feite kan elk object een itereerbaar zijn.

Bretels om het lichaam zijn optioneel als het uit slechts één verklaring bestaat. Hieronder staan ​​voorbeelden van iteratie over een bereik, lijst, array, kaart, en snaren:

def x = 0 voor (i in 0..9) {x + = i} x = 0 voor (i in [0, 1, 2, 3, 4]) {x + = i} def array = (0. .4) .toArray () x = 0 voor (i in array) {x + = i} def map = ['abc': 1, 'def': 2, 'xyz': 3] x = 0 voor (e in kaart) {x + = e.value} x = 0 voor (v in map.values ​​()) {x + = v} def text = "abc" def lijst = [] voor (c in tekst) {lijst. voeg (c)} toe

Object iteratie maakt de Groovy voor-loop een geavanceerde controlestructuur door. Het is een geldige tegenhanger van het gebruik van methoden die een object met sluitingen herhalen, zoals het gebruik van Collectie is elk methode.

Het belangrijkste verschil is dat de body van een voor lus is geen sluiting, dit betekent dat dit lichaam een ​​blok is:

voor (x in 0..9) {println x}

terwijl dit lichaam een ​​sluiting is:

(0..9). Elk {println it}

Ook al zien ze er hetzelfde uit, ze zijn heel verschillend qua constructie.

Een sluiting is een object op zich en heeft verschillende eigenschappen. Het kan op een andere plaats worden gebouwd en worden doorgegeven aan de elk methode. Het lichaam van de voor-lus wordt direct gegenereerd als bytecode op het moment van verschijnen. Er zijn geen speciale scopingregels van toepassing.

10. Afhandeling van uitzonderingen

Het grote verschil is dat de gecontroleerde afhandeling van uitzonderingen niet wordt afgedwongen.

Om algemene uitzonderingen af ​​te handelen, kunnen we de code die mogelijk uitzonderingen veroorzaakt in een proberen te vangen blok:

probeer {someActionThatWillThrowAnException ()} catch (e) // log het foutbericht en / of behandel het op een of andere manier}

Door het type uitzondering dat we opvangen niet aan te geven, wordt elke uitzondering hier opgevangen.

11. Sluitingen

Simpel gezegd, een sluiting is een anoniem blok met uitvoerbare code die kan worden doorgegeven aan variabelen en toegang heeft tot gegevens in de context waarin deze is gedefinieerd.

Ze lijken ook op anonieme innerlijke klassen, hoewel ze geen interface implementeren of een basisklasse uitbreiden. Ze lijken op lambda's op Java.

Interessant is dat Groovy volledig kan profiteren van de JDK-toevoegingen die zijn geïntroduceerd om lambda's te ondersteunen, met name de streaming-API. We kunnen altijd sluitingen gebruiken waar lambda-uitingen worden verwacht.

Laten we het onderstaande voorbeeld eens bekijken:

def helloWorld = {println "Hello World"}

De variabele Hallo Wereld bevat nu een verwijzing naar de sluiting, en we kunnen deze uitvoeren door haar aan te roepen bellen methode:

helloWorld.call ()

Met Groovy kunnen we een meer natuurlijke methode-aanroepsyntaxis gebruiken - het roept de bellen methode voor ons:

Hallo Wereld()

11.1. Parameters

Net als methoden kunnen sluitingen parameters hebben. Er zijn drie varianten.

In het laatste voorbeeld, omdat er niets declpersistence_startared is, is er maar één parameter met de standaardnaam het. De gewijzigde sluiting die afdrukt wat het wordt verzonden, zou zijn:

def printTheParam = {println it}

We zouden het zo kunnen noemen:

printTheParam ('hallo') printTheParam 'hallo'

We kunnen ook parameters verwachten in sluitingen en deze doorgeven bij het aanroepen van:

def power = {int x, int y -> return Math.pow (x, y)} println power (2, 3)

De typedefinitie van parameters is hetzelfde als variabelen. Als we een type definiëren, kunnen we alleen dit type gebruiken, maar het kan ook en alles doorgeven wat we willen:

def say = {what -> println what} say "Hallo wereld"

11.2. Optioneel retourneren

De laatste verklaring van een afsluiting kan impliciet worden geretourneerd zonder de noodzaak om een ​​retourverklaring te schrijven. Dit kan worden gebruikt om de boilerplate-code tot een minimum te beperken. Dus een sluiting die het kwadraat van een getal berekent, kan als volgt worden ingekort:

def vierkant = {it * it} println vierkant (4)

Deze sluiting maakt gebruik van de impliciete parameter het en de optionele return-instructie.

12. Conclusie

Dit artikel gaf een korte inleiding tot de taal van Groovy en de belangrijkste kenmerken ervan. We zijn begonnen met het introduceren van eenvoudige concepten zoals basissyntaxis, voorwaardelijke instructies en operatoren. We hebben ook enkele meer geavanceerde functies gedemonstreerd, zoals operators en sluitingen.

Als je meer informatie wilt over de taal en zijn semantiek, ga dan rechtstreeks naar de officiële site.