# Methoden ### Definition einer Methode Methoden werden ähnlich wie in Java definiert, können aber optional einen Rückgabetyp haben ```Groovy class Calculator { int add(int a, int b) { return a + b } } ``` In Groovy können Methoden direkt ohne Klasse und main-Methode definiert und aufgerufen werden. Beispiel 1 ```Groovy def printHello() { println "Hello..." } printHello() def sum(int a, int b) { println "Sum is "+(a+b) } sum(5,2) //Hello... // 7 ``` ### Instanzmethoden Methoden können Instanzmethoden sein und auf Instanzvariablen zugreifen, indem man $-Zeichen und optional eckige Klammern nutzt. ```Groovy class Person { String name int age // Instanzmethode, um die Person vorzustellen def introduce() { println("Hello, my name is $name and I am ${age} years old.") } } Person person = new Person(name: 'Alice', age: 30) person.introduce() // Hello, my name is Alice and I am 30 years old. ``` ### Statische Methoden ```Groovy class MathUtils { // Definition einer statischen Methode static int add(int a, int b) { return a + b } static void main(String[] args) { // Aufruf der statischen Methode ohne Instanz der Klasse int result = MathUtils.add(5, 10) println("Sum is $result") // Ausgabe: Sum is 15 } } ``` ### Dynamische Methoden Groovy erlaubt es, Methoden zur Laufzeit hinzuzufügen. In diesem Beispiel wird die Methode sayHello zur Klasse DynamicExample hinzugefügt, nachdem die Klasse bereits definiert wurde Beispiel Groovy ermöglicht es, Methoden zur Laufzeit hinzuzufügen, was eine hohe Flexibilität bei der Gestaltung von Klassen und deren Verhalten bietet. Diese Fähigkeit ist Teil der dynamischen Natur von Groovy und wird durch die metaClass-Eigenschaft ermöglicht ```Groovy class DynamicExample {} // Hinzufügen einer Methode(=closure) zur Laufzeit DynamicExample.metaClass.sayHello = { -> println "Hello, World!" } def example = new DynamicExample() example.sayHello() ``` ### Expando Expando ist eine spezielle Klasse in Groovy, die ermöglicht, Objekten zur Laufzeit dynamisch Methoden und Eigenschaften hinzuzufügen. Dadurch ist die vorherige Deklaration der Felder in der Klasse nicht nötig Beispiel ```Groovy // Erstellen eines Expando-Objekts def expando = new Expando() // Hinzufügen einer Eigenschaft 'name' und Zuweisung des Wertes "Groovy" expando.name = "Groovy" // Hinzufügen einer Methode 'sayHello', die eine Nachricht ausgibt, die die Eigenschaft 'name' verwendet expando.sayHello = { -> println "Hello from $name" } // Aufrufen der Methode 'sayHello', was die Nachricht "Hello from Groovy" ausgibt expando.sayHello() // Ausgabe: Hello from Groovy ``` ### Default-Parameter Methodenparameter können Standdardwerte haben (wie in Ruby). Diese werden eingesetzt, falls beim Aufruf keine Parameter gesetzt werden. Beispiel 1 ```Groovy class Greeter { void greet(String name = "World") { println "Hello, $name!" } } ``` Ruft man die Methode ohne Parameter auf, werden die Default-Paramter eingesetzt Beispiel 2 ```Groovy def sum(int a=10, int b=3) { println "Sum is "+(a+b) } sum() // Sum is 13 ``` ### Closures Closures können auf Variablen aus ihrem umgebenden Gültigkeitsbereich zugreifen und diese „einfangen“. Dadurch können sie auf Werte zugreifen, die zum Zeitpunkt ihrer Erstellung existierten. Closures enthalten Parameter, den Pfeil -> und den auszuführenden Code. Parameter sind optional und werden, sofern angegeben, durch Kommas getrennt. 1. Parameter ```Groovy //closure takes one parameter - name - and prints it when invoked def greet = { String name -> println "Hello, $name!" } greet.call("John") ``` 2. Referenzierung von Variablen und Rückgabewerte Dieses Beispiel zeigt, wie Closures auf Variablen im auf Variablen im umgebenden Kontext zugreifen und diese beibehalten können. Somit wird es Closures ermöglicht, Zustände zwischen verschiedenen Aufrufen beizubehalten. ```Groovy def createCounter() { def count = 0 //lokale var return { -> count += 1 return count } } //Ergebnis bzw. closure wird counter zugewiesen def counter = createCounter() //counter hat zugriff auf count *innerhalb des Kontexts* //in dem sie erstellt wurde println(counter()) // Ausgabe: 1 println(counter()) // Ausgabe: 2 ``` 3. Übergabe als Parameter ```Groovy def performOperation(int x, Closure operation) { return operation(x) } def closure = { y -> y * 2 } def result = performOperation(5, closure) println(result) // Ausgabe: 10 ``` ### Wie ruft man eine Closure auf Eine Closure kann sowohl als eine reguläre Methode als auch mit call aufrufen werden ```Groovy // Closure-Definition def greet = { name -> return "Hello, ${name}!" } // Aufruf der Closure als reguläre Methode println(greet("Alice")) // Ausgabe: Hello, Alice! // Aufruf der Closure mit call println(greet.call("Bob")) // Ausgabe: Hello, Bob! ``` Methoden können auch auf Maps und Listen angewendet werden, besonders nützlich mit Closures. ```Groovy def myMap = [ 'subject': 'groovy', 'topic': 'closures'] println myMap.each { it } def myList = [1, 2, 3, 4, 5] println myList.find { item -> item == 3 } // 3 println myList.findAll { item -> item > 3 } // [4, 5] println myList.any { item -> item > 5 } // false println myList.every { item -> item > 3 } // false println myList.collect { item -> item * 2 } // [2, 4, 6, 8, 10] ``` Im Gegensatz zu einer regulären Groovy-Methode: - Wir können eine Closure als Argument an eine Methode übergeben - Wir können eine Closure einer Variablen zuweisen und später ausführen, entweder als Methode oder mit call. - Groovy bestimmt den Rückgabewert der Closures zur Laufzeit. - Wir können Closures innerhalb einer Closure deklarieren und aufrufen. - Closures geben immer einen Wert zurück ### Methodenverkettung Methodenverkettung ermöglicht,dass Methodenaufrufe direkt nacheinander aufeinanderfolgen können, indem das Objekt selbst (normalerweise mit this) zurückgegeben wird. Dies ermöglicht eine flüssige und verständliche Art, Methoden aufzurufen und zu kombinieren, insbesondere wenn diese Methoden denselben oder ähnlichen Kontext haben. (wie in JS, ) Beispiel ```Groovy class FluentPerson { String name int age FluentPerson setName(String name) { this.name = name return this } FluentPerson setAge(int age) { this.age = age return this } } // Erstellen einer neuen FluentPerson-Instanz und Methodenverkettung def person = new FluentPerson() .setName("Alice") .setAge(30) println "Name: ${person.name}, Age: ${person.age}" // Ausgabe: Name: Alice, Age: 30 ``` ### Mixin(Misching) Man kann Funktionalität zu Klassen hinzufügen, ohne Vererbung zu verwenden, indem man Mixins verwendet. Beispiel ```Groovy class ExtraMethods { String shout(String str) { return str.toUpperCase() } } @Mixin(ExtraMethods) class MyClass {} def myObject = new MyClass() println myObject.shout("hello") ```