Einführung in die Groovy Language

Einführung in Groovy Language

1. Überblick

Groovy is a dynamic, scripting language for the JVM. Es kompiliert Bytecode und fügt sich nahtlos in Java-Code und -Bibliotheken ein.

In diesem Artikel werden einige der wesentlichen Funktionen vonGroovy vorgestellt, einschließlich der grundlegenden Syntax, Kontrollstrukturen und Sammlungen.

Dann werden wir uns einige der Hauptmerkmale ansehen, die es zu einer attraktiven Sprache machen, einschließlich Nullsicherheit, impliziter Wahrheit, Operatoren und Zeichenketten.

2. Umgebung

Wenn wir Groovy in Maven-Projekten verwenden möchten, müssen wir denpom.xml: Folgendes hinzufügen


    
        // ...
        
            org.codehaus.gmavenplus
            gmavenplus-plugin
            1.5
       
   


    // ...
    
        org.codehaus.groovy
        groovy-all
        2.4.10
    

Das neueste Maven-Plugin enthälthere und die neueste Version vongroovy-allhere.

3. Grundfunktionen

In Groovy gibt es viele nützliche Funktionen. Schauen wir uns nun die Grundbausteine ​​der Sprache an und wie sie sich von Java unterscheidet.

Schauen wir uns nun die Grundbausteine ​​der Sprache an und wie sie sich von Java unterscheidet.

3.1. Dynamische Eingabe

Eines der wichtigsten Merkmale von Groovy ist die Unterstützung der dynamischen Eingabe.

Typdefinitionen sind optional und die tatsächlichen Typen werden zur Laufzeit ermittelt. Schauen wir uns diese beiden Klassen an:

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

Diese beiden Klassen definieren dieselbegetName-Methode, sie ist jedoch in einem Vertrag nicht explizit definiert.

Stellen Sie sich nun vor, wir haben eine Liste von Objekten mit Enten und Katzen, die die MethodegetNamehaben. Mit Groovy können wir Folgendes tun:

Duck duck = new Duck()
Cat cat = new Cat()

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

Der Code wird kompiliert und die Ausgabe des obigen Codes wäre:

Duck
Cat

3.2. Implizite Wahrheitsumwandlung

Wie in JavaScript wertet Groovy bei Bedarf jedes Objekt in einen Booleschen Wert aus, z. wenn Sie es in einerif-Anweisung verwenden oder wenn Sie den Wert negieren:

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

Bei dieser Konvertierung sind einige einfache Regeln zu beachten:

  • Nicht leereCollections,-Arrays, Maps werden zutrue ausgewertet

  • Matcher mit mindestens einer Übereinstimmung ergibttrue

  • Iterators undEnumerations mit weiteren Elementen werden zutrue gezwungen

  • Nicht leereStrings,GStrings undCharSequences werden zutrue gezwungen

  • Zahlen ungleich Null werden mittrue bewertet

  • Nicht-Null-Objektreferenzen werden zutrue gezwungen

Wenn wir die implizite Wahrheitskonvertierung anpassen möchten, können wir unsereasBoolean()-Methode definieren.

3.3. Importe

Einige Pakete werden standardmäßig importiert und müssen nicht explizit importiert werden:

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-Transformationen

Mit AST (Abstract Syntax Tree) -Transformationen können wir uns in den Groovy-Kompilierungsprozess einbinden und ihn an unsere Bedürfnisse anpassen. Dies erfolgt zum Zeitpunkt der Kompilierung, sodass beim Ausführen der Anwendung keine Leistungseinbußen auftreten. Wir können unsere AST-Transformationen erstellen, aber wir können auch die eingebauten verwenden.

Wir können unsere Transformationen schaffen oder von den eingebauten profitieren.

Werfen wir einen Blick auf einige wissenswerte Anmerkungen.

4.1. AnmerkungTypeChecked

Diese Annotation wird verwendet, um den Compiler zu einer strengen Typprüfung für mit Annotationen versehene Codeteile zu zwingen. Der Mechanismus zur Typprüfung ist erweiterbar, sodass wir auf Wunsch sogar eine strengere Typprüfung als in Java anbieten können.

Schauen wir uns das folgende Beispiel an:

class Universe {
    @TypeChecked
    int answer() { "forty two" }
}

Wenn wir versuchen, diesen Code zu kompilieren, wird der folgende Fehler festgestellt:

[Static type checking] - Cannot return value of type java.lang.String on method returning type int

Die Annotation@TypeChecked kann auf Klassen und Methoden angewendet werden.

4.2. AnmerkungCompileStatic

Mit dieser Annotation kann der Compiler Kompilierungszeitprüfungen wie mit Java-Code ausführen. Danach führt der Compiler eine statische Kompilierung durch und umgeht so das Groovy-Metaobjektprotokoll.

Wenn eine Klasse mit Anmerkungen versehen ist, werden alle Methoden, Eigenschaften, Dateien, inneren Klassen usw. der kommentierten Klasse wird typgeprüft. Wenn eine Methode mit Anmerkungen versehen ist, wird die statische Kompilierung nur auf die Elemente (Abschlüsse und anonyme innere Klassen) angewendet, die von dieser Methode eingeschlossen sind.

5. Eigenschaften

In Groovy können wir POGOs (Plain Old Groovy Objects) erstellen, die genauso funktionieren wie POJOs in Java, obwohl sie kompakter sind, weilgetters and setters are automatically generated for public properties während der Kompilierung. Es ist wichtig zu beachten, dass sie nur generiert werden, wenn sie nicht bereits definiert sind.

Dies gibt uns die Flexibilität, Attribute als offene Felder zu definieren und gleichzeitig das Verhalten beim Festlegen oder Abrufen der Werte außer Kraft zu setzen.

Betrachten Sie dieses Objekt:

class Person {
    String name
    String lastName
}

Da der Standardbereich für Klassen, Felder und Methodenpublic – ist, handelt es sich um eine öffentliche Klasse, und die beiden Felder sind öffentlich.

Der Compiler konvertiert diese in private Felder und fügt die MethodengetName(),setName(),getLastName() undsetLasfName() hinzu. Wenn wir diesetter undgetter für ein bestimmtes Feld definieren, erstellt der Compiler keine öffentliche Methode.

5.1. Verknüpfungsnotationen

Groovy bietet eine Abkürzungsnotation zum Abrufen und Festlegen von Eigenschaften. Anstelle der Java-Methode, Getter und Setter aufzurufen, können wir eine feldähnliche Zugriffsnotation verwenden:

resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME

resourcePrototype.setName("something")
resourcePrototype.name = "something"

6. Betreiber

Schauen wir uns nun neue Operatoren an, die zusätzlich zu den aus einfachem Java bekannten hinzugefügt wurden.

6.1. Null-Safe Dereference

Am beliebtesten ist der nullsichere Dereferenzierungsoperator“?”, mit dem wirNullPointerException vermeiden können, wenn wir eine Methode aufrufen oder auf eine Eigenschaft einesnull-Objekts zugreifen. Dies ist besonders nützlich bei verketteten Anrufen, bei denen der Wert vonnullan einem bestimmten Punkt in der Kette auftreten kann.

Zum Beispiel können wir sicher anrufen:

String name = person?.organization?.parent?.name

Wenn im obigen Beispiel aperson,person.organization oderorganization.parentnull sind, wirdnull zurückgegeben.

6.2. Elvis-Betreiber

Mit dem Elvis-Operator“?: ”können wir ternäre Ausdrücke verdichten. Diese beiden sind gleichwertig:

String name = person.name ?: defaultName

and

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

Beide weisen der Namensvariablen den Wertperson.name zu, wenn erGroovy true ist (in diesem Fall nichtnull und hat eine Länge vonnon-zero).

6.3. Raumschiffbetreiber

Der Raumschiffoperator“<⇒” ist ein relationaler Operator, der sich wie dercompareTo() von Java verhält, der zwei Objekte vergleicht und je nach den Werten beider Argumente -1, 0 oder +1 zurückgibt.

Wenn das linke Argument größer als das rechte ist, gibt der Operator 1 zurück. Wenn das linke Argument kleiner als das rechte ist, gibt der Operator −1 zurück. Wenn die Argumente gleich sind, wird 0 zurückgegeben.

Der größte Vorteil der Verwendung der Vergleichsoperatoren ist die reibungslose Behandlung vonnulls, sodassx <⇒ y niemalsNullPointerException werfen:

println 5 <=> null

Das obige Beispiel gibt als Ergebnis 1 aus.

7. Streicher

Es gibt mehrere Möglichkeiten, Zeichenfolgenliterale auszudrücken. Der in Java verwendete Ansatz (Strings in doppelten Anführungszeichen) wird unterstützt, es ist jedoch auch zulässig, einfache Anführungszeichen zu verwenden, wenn dies bevorzugt wird.

Mehrzeilige Zeichenfolgen, die in anderen Sprachen manchmal als Heredocs bezeichnet werden, werden ebenfalls mit dreifachen Anführungszeichen (entweder einfach oder doppelt) unterstützt.

Mehrzeilige Zeichenfolgen, die in anderen Sprachen manchmal als Heredocs bezeichnet werden, werden ebenfalls mit dreifachen Anführungszeichen (entweder einfach oder doppelt) unterstützt.

Mit doppelten Anführungszeichen definierte Zeichenfolgen unterstützen die Interpolation mit der Syntax von$\{}:

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

Tatsächlich kann jeder Ausdruck innerhalb von$\{} platziert werden:

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

Ein String mit doppelten Anführungszeichen wird als GString bezeichnet, wenn er einen Ausdruck$\{} enthält. Andernfalls handelt es sich um ein einfachesString-Objekt.

Der folgende Code wird ausgeführt, ohne den Test zu bestehen:

def a = "hello"
assert a.class.name == 'java.lang.String'

def b = 'hello'
assert b.class.name == 'java.lang.String'

def c = "${b}"
assert c.class.name == 'org.codehaus.groovy.runtime.GStringImpl'

8. Sammlungen und Karten

Schauen wir uns an, wie einige grundlegende Datenstrukturen behandelt werden.

8.1. Lists

Hier ist ein Code zum Hinzufügen einiger Elemente zu einer neuen Instanz vonArrayList in Java:

List list = new ArrayList<>();
list.add("Hello");
list.add("World");

Und hier ist dieselbe Operation in Groovy:

List list = ['Hello', 'World']

Listen sind standardmäßig vom Typjava.util.ArrayList und können auch explizit durch Aufrufen des entsprechenden Konstruktors deklariert werden.

Es gibt keine separate Syntax fürSet, aber wir können dafür den Typcoercion verwenden. Verwenden Sie entweder:

Set greeting = ['Hello', 'World']

or:

def greeting = ['Hello', 'World'] as Set

8.2. Map

Die Syntax für aMap ist ähnlich, wenn auch etwas ausführlicher, da wir Schlüssel und Werte angeben müssen, die durch Doppelpunkte getrennt sind:

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

Nach dieser Initialisierung erhalten wir ein neuesLinkedHashMap mit den Einträgen:Key1 → Value1, Key2 → Value 2, Key3 → Another Value.

Wir können auf verschiedene Arten auf Einträge in der Karte zugreifen:

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

9. Kontrollstrukturen

9.1. Bedingungen:if-else

Groovy unterstützt erwartungsgemäß die bedingteif/else-Syntax:

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

9.2. Bedingungen:switch-case

Die Anweisungswitch ist abwärtskompatibel mit Java-Code, sodass wir Fälle durchgehen können, in denen derselbe Code für mehrere Übereinstimmungen verwendet wird.

Der wichtigste Unterschied besteht darin, dass einswitch einen Abgleich mit mehreren verschiedenen Werttypen durchführen kann:

def x = 1.23
def result = ""

switch ( x ) {
    case "foo":
        result = "found foo"
        break

    case "bar":
        result += "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 }: // or { x < 0 }
        result = "negative"
        break

    default:
        result = "default"
}

println(result)

Im obigen Beispiel werdennumber. gedruckt

9.3. Schleifen:while

Groovy unterstützt die üblichenwhile-Schleifen wie Java:

def x = 0
def y = 5

while ( y-- > 0 ) {
    x++
}

9.4. Schleifen:for

Groovy begrüßt diese Einfachheit und empfiehlt nachdrücklichfor-Schleifen, die dieser Struktur folgen:

for (variable in iterable) { body }

Diefor-Schleife iteriert überiterable. Häufig verwendete Iterables sind Bereiche, Sammlungen, Karten, Arrays, Iteratoren und Aufzählungen. Tatsächlich kann jedes Objekt iterabel sein.

Klammern um den Körper sind optional, wenn sie nur aus einer Anweisung bestehen. Nachfolgend finden Sie Beispiele für die Iteration überrange,list,array,map undstrings:

def x = 0
for ( i in 0..9 ) {
    x += i
}

x = 0
for ( i in [0, 1, 2, 3, 4] ) {
    x += i
}

def array = (0..4).toArray()
x = 0
for ( i in array ) {
    x += i
}

def map = ['abc':1, 'def':2, 'xyz':3]
x = 0
for ( e in map ) {
    x += e.value
}

x = 0
for ( v in map.values() ) {
    x += v
}

def text = "abc"
def list = []
for (c in text) {
    list.add(c)
}

Die Objekt iteration macht die Schaluppe Groovyfor-zu einer ausgeklügelten Kontrollstruktur. Dies ist ein gültiges Gegenstück zur Verwendung von Methoden, die über ein Objekt mit Abschlüssen iterieren, z. B. die Verwendung der MethodeCollection’s each.

Der Hauptunterschied besteht darin, dass der Körper einerfor-Schleife kein Abschluss ist. Dies bedeutet, dass dieser Körper ein Block ist:

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

in der Erwägung, dass dieser Körper ein Verschluss ist:

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

Obwohl sie ähnlich aussehen, unterscheiden sie sich in der Konstruktion erheblich.

Ein Verschluss ist ein eigenständiges Objekt und weist unterschiedliche Merkmale auf. Es kann an einer anderen Stelle erstellt und an dieeach-Methode übergeben werden. Der Körper derfor--Sloop wird jedoch direkt alsbytecode an seinem Erscheinungspunkt erzeugt. Es gelten keine besonderen Regeln für den Geltungsbereich.

10. Ausnahmebehandlung

Der große Unterschied besteht darin, dass die Behandlung geprüfter Ausnahmen nicht erzwungen wird.

Um allgemeine Ausnahmen zu behandeln, können wir den potenziell ausnahmeverursachenden Code in einentry/catch-Block einfügen:

try {
    someActionThatWillThrowAnException()
} catch (e)
    // log the error message, and/or handle in some way
}

Wenn Sie den Typ der Ausnahme, die wir abfangen, nicht deklarieren, wird jede Ausnahme hier abgefangen.

11. Verschlüsse

Einfach ausgedrückt ist ein Closure ein anonymer Block ausführbaren Codes, der an Variablen übergeben werden kann und Zugriff auf Daten in dem Kontext hat, in dem er definiert wurde.

Sie ähneln auch anonymen inneren Klassen, obwohl sie keine Schnittstelle implementieren oder eine Basisklasse erweitern. Sie ähneln Lambdas in Java.

Interessanterweise kann Groovy die JDK-Erweiterungen, die zur Unterstützung von Lambdas eingeführt wurden, insbesondere die Streaming-API, voll ausnutzen. Wir können immer Verschlüsse verwenden, bei denen Lambda-Ausdrücke erwartet werden.

Betrachten wir das folgende Beispiel:

def helloWorld = {
    println "Hello World"
}

Die VariablehelloWorld enthält jetzt einen Verweis auf den Abschluss, und wir können ihn ausführen, indem wir die Methodecall aufrufen:

helloWorld.call()

Mit Groovy können wir eine natürlichere Methodenaufrufsyntax verwenden - es ruft diecall-Methode für uns auf:

helloWorld()

11.1. Parameter

Abschlüsse können wie Methoden Parameter haben. Es gibt drei Varianten.

Im letzteren Beispiel gibt es nur einen Parameter mit dem Standardnamenit, da nichts deculpersistence_startared vorhanden ist. Der modifizierte Verschluss, der das druckt, was gesendet wird, wäre:

def printTheParam = { println it }

Wir könnten es so nennen:

printTheParam('hello')
printTheParam 'hello'

Wir können auch Parameter in Closures erwarten und diese beim Aufruf übergeben:

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

Die Typdefinition von Parametern ist identisch mit Variablen. Wenn wir einen Typ definieren, können wir nur diesen Typ verwenden, aber auch alles übergeben, was wir wollen:

def say = { what ->
    println what
}
say "Hello World"

11.2. Optionale Rückgabe

Die letzte Anweisung eines Abschlusses kann implizit zurückgegeben werden, ohne dass eine return-Anweisung geschrieben werden muss. Dies kann verwendet werden, um den Kesselschildcode auf ein Minimum zu reduzieren. So kann ein Abschluss, der das Quadrat einer Zahl berechnet, wie folgt gekürzt werden:

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

Dieser Abschluss verwendet den impliziten Parameterit und die optionale return-Anweisung.

12. Fazit

Dieser Artikel bot eine kurze Einführung in die Groovy-Sprache und ihre wichtigsten Funktionen. Wir haben zunächst einfache Konzepte wie die grundlegende Syntax, bedingte Anweisungen und Operatoren eingeführt. Wir haben auch einige erweiterte Funktionen wie Bediener und Verschlüsse vorgestellt.

Wenn Sie weitere Informationen zur Sprache und ihrer Semantik erhalten möchten, können Sie direkt zuofficial site wechseln.