main
Ileyan Al Jaaf 2024-06-08 01:30:12 +02:00
parent 13afd81615
commit affa624e20
17 changed files with 607 additions and 325 deletions

View File

@ -5,12 +5,21 @@ Aus zeitlichen Gründen empfehlen wir die Verwendung eines [Online Compilers][2]
## Themenüberblick:
1. Ana: Einführung
2. Yase: Datentypen, Schleifen
3. Yuliya: Methoden, Klassen
4. Luka: Bedingungen, Datenstrukturen
5. Yannick: IO, Exception
6. Ileyan: Schlüsselwörter, Tests
| # | Thema |
| --- | ----- |
| 1. |[Schlüsselwörter](./skript/keywords.md)|
| 2. |[Datentypen](./skript/datentypen.md)|
| 3. |[Operatoren](./skript/operatoren.md)|
| 4. |[Schleifen](./skript/schleifen.md) |
| 5. |[Bedingungen](./skript/bedingungen.md)|
| 6. | [Klassen](./skript/klassen.md) |
| 7. | [Methoden](./skript/methoden.md)|
| 8. | [Exception Handling](./skript/exceptions.md) |
| 9. | [I/O]()|
| 10. | [Datenstrukturen](./skript/datenstrukturen.md)|
| 11. | [Testen]()|
## Live Übungen:

View File

@ -1,47 +0,0 @@
## Schlüsselwörter
- Folgende Schlüsselwörter gibt es in Groovy:
<img src="img/keywords.png" width="350">
Diese Wörter (und auch die Bezeichner für die Datentypen) dürfen im allgemeinen, wie in vielen anderen Sprachen nicht als Variablennamen benutzt werden. Jedoch gibt es in Groovy einen Weg dies zu umgehen:
```Groovy
def "this"(){print "Diese Methode hat den Namen \'this\' }
//-> "Diese Methode hat den Namen 'this'"
```
Hierbei muss man den Methodennamen in Anführungszeichen setzen. Ein Methodenaufruf würde dann wie folgt aussehen:
```Groovy
this.this(); //(Es wird angenommen das Objekt ruft selbst die Methode auf)
```
Es wird jedoch stark davon abgeraten dieses Groovy - Feature zu benutzen, da es in den meisten Fällen keine Vorteile bietet und nur für Verwirrung sorgt.
### Kontextuelle Schlüsselwörter:
- as
- in
- permitsrecord
- sealed
- trait
- var
- yields
Da diese Schlüsselwörter in weder in Java, noch in früheren Groovy Versionen existierten, kann man sie für Variablen- / Methodennamen benutzen, ohne sich des oben gezeigten Tricks bedienen zu müssen. Es wird empfohlen beim Aufrufen dieser Methoden / beim Zugriff auf diese Variablen ein "this." davorzusetzen, damit es nicht Verwirrungen kommt. Am besten lässt man es jedoch direkt sein und überlegt sich andere Namen.
## Tests
- Groovy bietet nicht nur Support für JUnit 5 (und älter), sondern liefert auch einen eigenen Satz an Testmethoden, um die testgetriebene Programmierung zu vereinfachen.
Ein Beispiel hierfür wäre Spock. Mit Spock kann man sowohl Java, als auch Groovy Code testen. Getestet wird mit sogenannten Spezifikationen. Die Testklasse muss also von **spock.lang.Specification** erben.
<img src="img/spock.png" width="500">
#### Erklärung:
1. Der Name der Testmethode muss ein String sein, der beschreibt, was beim Testen erwartet wird.
2. Das Schlüsselwort **setup** dient dazu, lokale Variablen zu initialisieren, die für den Test gebraucht werden (vgl. @BeforeEach Annotation, JUnit)
3. Das **when** Schlüsselwort beschreibt den Codeabschnitt, der zu einem bestimmten Verhalten führen soll
4. **then** beschreibt das erwartete Verhalten.

BIN
img/assertion2.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
img/assertion3.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
img/exceptions.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -32,7 +32,7 @@ die Variable haben soll.
Wenn man z.B. eine grosse Zahl hat, wird der Typ automatisch an die grössere Zahl angepasst
Beispiel
```
```Groovy
def a = 100
boolean isInteger = a Instance of Integer
println(isInteger) //-> true
@ -46,7 +46,7 @@ Man kann einen String auf verschiedene Arten definieren.
Sie reichen von einfachen einzeiligen Strings ...
Beispiel
```
```Groovy
def einfach = 'einfache Anführungszeichen'
def doppelt = "doppelte Anführungszeichen"
def slashy = /ein "Slashy String" ohne 'Escape'/
@ -61,7 +61,7 @@ println(dollar) // weitere Möglichkeit und Einfügen von '/'
...bis hin zu komplexen mehrzeiligen Textblöcken
Beispiel
```
```Groovy
def dreifach = '''
Ich bin
ein String der über
@ -88,7 +88,7 @@ Java = statisch typisiert d.h. der Typ der Variablen
wird zur Kompilierungszeit festgelegt und kann sich nicht ändern
Beispiel
```
```Groovy
String s = "Hallo Welt";
System.out.println(s); // Hallo Welt
@ -100,8 +100,8 @@ Groovy = dynamisch typisiert d.h. der Typ der Variablen
wird zur Laufzeit bestimmt. Daher ist es auch möglich
einer Variablen die zuvor einen String-Wert hatte, einen Integer-Wert zuzuweisen
Beispiel
```
Beispiel:
```Groovy
def s = "Hallo Welt"
println s.getClass() // -> class java.lang.String
@ -116,8 +116,8 @@ Dabei wird ein Platzhalter im String durch seinen tatsächlichen Wert ersetzt, w
der String ausgewertet wird.
Platzhalter werden durch `${ausdruck}` gekennzeichnet
Beispiel
```
Beispiel:
```Groovy
def person = [name: 'Thomas Smits', lehrt: 'PR3']
def hochschule = "Hochschule Mannheim"
def ausdruck = "Hallo, mein Name ist ${person.name}. Ich unterrichte ${person.lehrt}. An der ${hochschule}."
@ -130,7 +130,7 @@ Man nennt dies einen `GString`
Jeder String kann mit `+` konkateniert werden
Beispiel
```
```Groovy
def eins = "Ein String"
def zwei = ' wird konkateniert'
@ -142,7 +142,7 @@ Man kann auf Zeichen eines Strings mit positiven und negativen Indizes zugreifen
Zählungen beginnen bei null und negative Indizes beginnen den String am Ende
Beispiel
```
```Groovy
def greeter = "Hallo Welt"
println(greeter[1]) // -> 'a'

View File

@ -0,0 +1,50 @@
# Exception-Handling:
Grundsätzlich ähnelt sich die Ausnahmebehandlung in Groovy der in Java sehr, weshalb dies ein eher kurzes Kapitel wird. Dennoch wollen wir hier auf einige Grundlagen und Besonderheiten eingehen.
#### Vererbungshierarchie:
<img src="./../img/exceptions.png" width="350">
Es gilt die selbe Vererbungshierarchie, wie in Java. Alle Exception Klassen sind von der Klasse `Exception`, und somit auch indirekt von `Throwable` abgeleitet. Will man eigene Exceptions schreiben, müssen diese also von `Exception` erben.
#### Ausnahmen fangen:
Zum Fangen von Ausnahmen werden auch in Groovy try-catch-finally Blöcke benutzt.
- `try:` Dieser Block enthält den gefährlichen Code, der potentiell Ausnahmen werfen könnte.
- `catch:` Hier findet die eigentliche Fehlerbehandlung statt. Die Exceptions sollen hier nicht einfach ausgegeben bzw. ignoriert werden, sondern sinnvoll behandelt werden
- `finally:` Dieser Block ist gedacht für Aufräumarbeiten und wird immer ausgeführt, egal ob das Programm abrubt beendet wird durch Eintritt in den **catch**-Block, oder normal beendet wird.
Es können auch mehrere catch-Blocke nach einem try-Block folgen. Der Compiler wählt hier den ersten passenden Block aus. Deshalb gilt: **Man soll beim Schreiben der catch-Blöcke immer vom Spezifischen zum Allgemeinen gehen.**
````Groovy
try {
// Code der die Exception werfen kann
} catch (IOException e) {
// Fehlerbehandlung
} catch (Exception e) {
// Fehlerbehandlung
}
````
#### Dynamische Ausnahmebehandlung:
Anders als in Java muss in Groovy der Typ der Exception nicht angegeben werden. Da Groovy eine dynamisch typisierte Sprache ist, kann hier auch einfach nur der Variablenname angegeben werden. Der Compiler wählt dann die passende Exception zur Laufzeit aus.
````Groovy
try {
def result = 1 / 0
} catch (e) {
e.printStackTrace()
// Ausgabe: Caught an exception: Divison by zero
}
````
#### GString-Interpolation bei Exceptions:
Groovy erlaubt es die Exception Message dierekt durch die GString Interpolation auszugeben. Dadurch kann man Individuellere Konsolenausgaben bei Fehlerbehandlungen erreichen.
````Groovy
try {
def file = new File("gibtesnicht.txt")
file.text
} catch (e) {
println "Datei wurde nicht gefunden: ${e.message}"
}
// Ausgabe: Datei wurde nicht gefunden: gibtesnicht.txt (No such file or directory)
````

76
skript/keywords.md 100644
View File

@ -0,0 +1,76 @@
## Schlüsselwörter
- Folgende Schlüsselwörter gibt es in Groovy:
<img src="./../img/keywords.png" width="350">
Diese Wörter (und auch die Bezeichner für die Datentypen) dürfen im allgemeinen, wie in vielen anderen Sprachen nicht als Variablennamen benutzt werden. Jedoch gibt es in Groovy einen Weg dies zu umgehen:
```Groovy
def "this"(){print "Diese Methode hat den Namen \'this\' }
//-> "Diese Methode hat den Namen 'this'"
```
Hierbei muss man den Methodennamen in Anführungszeichen setzen. Ein Methodenaufruf würde dann wie folgt aussehen:
```Groovy
this.this(); //(Es wird angenommen das Objekt ruft selbst die Methode auf)
```
Es wird jedoch stark davon abgeraten dieses Groovy - Feature zu benutzen, da es in den meisten Fällen keine Vorteile bietet und nur für Verwirrung sorgt.
### Kontextuelle Schlüsselwörter:
- as
- in
- def
- permitsrecord
- sealed
- trait
- var
- yields
Da diese Schlüsselwörter in weder in Java, noch in früheren Groovy Versionen existierten, kann man sie für Variablen- / Methodennamen benutzen, ohne sich des oben gezeigten Tricks bedienen zu müssen. Es wird empfohlen beim Aufrufen dieser Methoden / beim Zugriff auf diese Variablen ein "this." davorzusetzen, damit es nicht Verwirrungen kommt. Am besten lässt man es jedoch direkt sein und überlegt sich andere Namen.
### Das Schlüsselwort "def":
Eines der wichtigsten Groovy-Features ist die dynamische Typisierung. Ihr bester Freund wird hier das Schlüsselwort "def" sein. Es wird benutzt, um eine Variable oder eine Methode zu definieren, ohne hierbei den Typ explizit angeben zu müssen. Würden wir in Java z.B. folgendes versuchen:
````Java
public class MyClass {
public static void main(String args[]) {
int a = 5;
a = "Hallo";
System.out.println(a);
}
}
````
Dann würden wir folgende Ausgabe erhalten:
````
MyClass.java:4: error: incompatible types: String cannot be converted to int
a = "Hallo";
^
1 error
````
In Groovy gibt es für genau solche Fälle jedoch das Schlüsselwort "def". Folgendes ist also in Groovy möglich:
````Groovy
def a = 10
a = "Hallo"
println a // Ausgabe: Hallo
````
Dieses Feature kann vor allem bei Methoden nützlich sein, bei denen man sich noch nicht auf einen Rückgabewert festgelegt hat. So ist es also möglich, dass eine Methode in einem Fall eine Zahl zurückgibt, in einem anderen Fall jedoch einen String. Folgendes Beispiel verdeutlicht das ganze nochmal:
````Groovy
def divide(x, y){
if (y == 0) {
return "Keine Division durch 0 erlaubt!"
}
x/y
}
println divide(6,3) //Ausgabe: class java.math.BigDecimal
println divide(1,0) //Ausgabe: class java.lang.String
````
Wie sie vielleicht bemerkt haben, wurde bei diesem Beispiel absichtlich auf die Angabe von Typen bei den Methodenparametern verzichtet. Groovy erlaubt es einem nämlich auch hier auf die explizite Angabe von Typen zu verzichten.

142
skript/klassen.md 100644
View File

@ -0,0 +1,142 @@
# Klassen
### Definition einer Klasse
Klassen in Groovy werden ähnlich wie in Java definiert, jedoch mit einigen
syntaktischen Erleichterungen: mit dem class-Schlüsselwort, ohne Semikolon
Beispiel
```Groovy
class Person {
String name
int age
}
```
### Konstruktoren
Groovy fügt automatisch einen Standardkonstruktor (="Default-Konstruktor") hinzu, wenn
keine Konstruktoren explizit definiert sind. Dieser Standardkonstruktor initialisiert alle
Eigenschaften der Klasse mit ihren Standardwerten.
Man kann auch benutzerdefinierte Konstruktoren definieren oder die beiden Konstruktorarten
auch gleichzeitig nutzen. Man spricht dabei von Konstruktorüberladung (auch wie in Java,
C++, C#...)
```Groovy
class Person {
String name
int age
//Default-Konstruktor
def person = new Person()
//benutzerdefinierter Konstruktor
Person(String name, int age) {
this.name = name
this.age = age
}
}
```
```Groovy
class Person {
String name
int age
Person() {
// Standardkonstruktor
}
Person(String name, int age) {
this.name = name
this.age = age
}
}
def person1 = new Person()
println(person1.name) // Ausgabe: null
println(person1.age) // Ausgabe: 0
def person2 = new Person("Alice", 30)
println(person2.name) // Ausgabe: Alice
println(person2.age) // Ausgabe: 30
```
### Standardkonstruktor mit Map
Groovy bietet eine spezielle Initialisierungsform mit einer Map an. Dieser Konstruktor
ermöglicht Objekte einfach und übersichtlich zu initialisieren, indem die Eigenschaften
des Objekts direkt in Form von Schlüssel-Wert-Paaren in der Map angegeben werden.
Groovy kümmert sich dann um die Zuordnung der Werte zu den entsprechenden Feldern der Klasse.
Der Map-Konstruktor muss nicht explizit definiert werden (hier nur als Beispiel), da es ein eingebautes Standard-Feature von Groovy ist.
```Groovy
class Person {
String name
int age
// Map-Konstruktor
Person(Map properties) {
properties.each { key, value -> this."$key" = value }
}
}
Person person = new Person(name: 'John', age: 30)
println(person.name) // Ausgabe: John
println(person.age) // Ausgabe: 30
```
### Eigenschaften
Eigenschaften können direkt als Felder definiert werden. Groovy
generiert automatisch Getter- und Setter-Methoden (wie in Ruby)
Beispiel
```Groovy
Person person = new Person()
person.name = "John"
person.age = 30
println person.name
//John
```
Getter und Setter können aber auch manuell überschrieben werden
Beispiel
```Groovy
class Fruits {
private String fruitName
private String fruitColor
def setFruitName(String name) {
fruitName = name
}
def getFruitName() {
return "The fruitname is $fruitName"
}
def setFruitColor(String color) {
fruitColor = color
}
def getFruitColor(){
return "The color is $fruitColor"
}
static void(args) {
//Instanz erstellen
Fruits apple = new Fruits()
apple.setFruitName("apple")
apple.setFruitColor("red")
}
}
```

View File

@ -1,156 +1,15 @@
# Klassen
### Definition einer Klasse
Klassen in Groovy werden ähnlich wie in Java definiert, jedoch mit einigen
syntaktischen Erleichterungen: mit dem class-Schlüsselwort, ohne Semikolon
Beispiel
```
class Person {
String name
int age
}
```
### Konstruktoren
Groovy fügt automatisch einen Standardkonstruktor (="Default-Konstruktor") hinzu, wenn
keine Konstruktoren explizit definiert sind. Dieser Standardkonstruktor initialisiert alle
Eigenschaften der Klasse mit ihren Standardwerten.
Man kann auch benutzerdefinierte Konstruktoren definieren oder die beiden Konstruktorarten
auch gleichzeitig nutzen. Man spricht dabei von Konstruktorüberladung (auch wie in Java,
C++, C#...)
```
class Person {
String name
int age
//Default-Konstruktor
def person = new Person()
//benutzerdefinierter Konstruktor
Person(String name, int age) {
this.name = name
this.age = age
}
}
```
```
class Person {
String name
int age
Person() {
// Standardkonstruktor
}
Person(String name, int age) {
this.name = name
this.age = age
}
}
def person1 = new Person()
println(person1.name) // Ausgabe: null
println(person1.age) // Ausgabe: 0
def person2 = new Person("Alice", 30)
println(person2.name) // Ausgabe: Alice
println(person2.age) // Ausgabe: 30
```
### Standardkonstruktor mit Map
Groovy bietet eine spezielle Initialisierungsform mit einer Map an. Dieser Konstruktor
ermöglicht Objekte einfach und übersichtlich zu initialisieren, indem die Eigenschaften
des Objekts direkt in Form von Schlüssel-Wert-Paaren in der Map angegeben werden.
Groovy kümmert sich dann um die Zuordnung der Werte zu den entsprechenden Feldern der Klasse.
Der Map-Konstruktor muss nicht explizit definiert werden (hier nur als Beispiel), da es ein eingebautes Standard-Feature von Groovy ist.
```
class Person {
String name
int age
// Map-Konstruktor
Person(Map properties) {
properties.each { key, value -> this."$key" = value }
}
}
Person person = new Person(name: 'John', age: 30)
println(person.name) // Ausgabe: John
println(person.age) // Ausgabe: 30
```
### Eigenschaften
Eigenschaften können direkt als Felder definiert werden. Groovy
generiert automatisch Getter- und Setter-Methoden (wie in Ruby)
Beispiel
```
Person person = new Person()
person.name = "John"
person.age = 30
println person.name
//John
```
Getter und Setter können aber auch manuell überschrieben werden
Beispiel
```
class Fruits {
private String fruitName
private String fruitColor
def setFruitName(String name) {
fruitName = name
}
def getFruitName() {
return "The fruitname is $fruitName"
}
def setFruitColor(String color) {
fruitColor = color
}
def getFruitColor(){
return "The color is $fruitColor"
}
static void(args) {
//Instanz erstellen
Fruits apple = new Fruits()
apple.setFruitName("apple")
apple.setFruitColor("red")
}
}
```
# Methoden
### Definition einer Methode
Methoden werden ähnlich wie in Java definiert, können aber optional einen Rückgabetyp
haben
```
class Calculator {
int add(int a, int b) {
return a + b
}
```Groovy
class Calculator {
int add(int a, int b) {
return a + b
}
}
```
@ -159,9 +18,9 @@ werden.
Beispiel 1
```
def printHello() {
println "Hello..."
```Groovy
def printHello() {
println "Hello..."
}
printHello()
@ -179,7 +38,7 @@ sum(5,2)
Methoden können Instanzmethoden sein und auf Instanzvariablen zugreifen, indem man $-Zeichen und optional eckige Klammern nutzt.
```
```Groovy
class Person {
String name
int age
@ -197,7 +56,7 @@ person.introduce()
### Statische Methoden
```
```Groovy
class MathUtils {
// Definition einer statischen Methode
static int add(int a, int b) {
@ -223,7 +82,7 @@ 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
@ -239,7 +98,7 @@ Expando ist eine spezielle Klasse in Groovy, die ermöglicht, Objekten zur Laufz
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()
@ -259,7 +118,7 @@ Methodenparameter können Standdardwerte haben (wie in Ruby). Diese werden einge
gesetzt werden.
Beispiel 1
```
```Groovy
class Greeter {
void greet(String name = "World") {
println "Hello, $name!"
@ -270,7 +129,7 @@ class Greeter {
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)
}
@ -289,7 +148,7 @@ Closures enthalten Parameter, den Pfeil -> und den auszuführenden Code. Paramet
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!" }
@ -302,7 +161,7 @@ zugreifen und diese beibehalten können. Somit wird es Closures ermöglicht, Zus
zwischen verschiedenen Aufrufen beizubehalten.
```
```Groovy
def createCounter() {
def count = 0 //lokale var
return { ->
@ -323,7 +182,7 @@ println(counter()) // Ausgabe: 2
3. Übergabe als Parameter
```
```Groovy
def performOperation(int x, Closure operation) {
return operation(x)
}
@ -337,7 +196,7 @@ println(result) // Ausgabe: 10
Eine Closure kann sowohl als eine reguläre Methode als auch mit call aufrufen werden
```
```Groovy
// Closure-Definition
def greet = { name ->
return "Hello, ${name}!"
@ -354,7 +213,7 @@ 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 }
@ -383,7 +242,7 @@ selbst (normalerweise mit this) zurückgegeben wird.
Methoden denselben oder ähnlichen Kontext haben. (wie in JS, )
Beispiel
```
```Groovy
class FluentPerson {
String name
int age
@ -415,7 +274,7 @@ Man kann Funktionalität zu Klassen hinzufügen, ohne Vererbung zu verwenden, in
Mixins verwendet.
Beispiel
```
```Groovy
class ExtraMethods {
String shout(String str) {
return str.toUpperCase()

View File

@ -0,0 +1,146 @@
# Operatoren
## Grundlegende Operatoren
Grundsätzlich bietet Groovy dieselben Operatoren an, die es auch in Java gibt. Groovy erweiteret die Menge an Operatoren, die Java einem zur Verfügung stellt jedoch nochmal um einige mehr, auf hier eingegangen wird. Zu den grundlegenden Operatoren gehören:
- Arithmetische Operatoren (-, +, *, **,…)
- Relationale Operatoren (==, !=, <, >,…)
- Logische Operatoren (&&, ||, !)
- Bitweise Operatoren (&, |, ^, ~)
- Bitweise Verschiebung (<<, >>,>>>)
- Konditionale Operatoren (!, ? :, ?: )
Wie bereits erwähnt, gibt es die meisten dieser Operatoren schon in Java. Deshalb setzen wir diese an dieser Stelle als bereits bekannt voraus. Auf die bisher unbekannten Operatoren wollen wir jedoch etwas genauer eingehen.
---
### 1. Exponentialoperator (**)
Dies ist ein relativ simpler Operator. Er wird verwendet, um eine gegebene Zahl auf eine bestimmte Potenz zu erhöhen:
````Groovy
def a = 2
def b = 3
println a**b // Ausgabe: 8 (Weil 2^3 = 8)
````
### 2. SicherheitsnavigationsOperator (?.):
Der Sicherheitsnavigationsoperator wird verwendet, um null-sichere Zugriff auf Objekteigenschaften, Methoden oder Array-Elemente zu ermöglichen. Ein bestimmter Ausdruck wird also nur ausgeführt, wenn das Objekt, auf das gerade zugegriffen wird nicht null ist. Somit wird eine NullPointerException vermieden. Ist das Objekt nämlich null, wird einfach null zurückgegeben und keine Exception geworfen.
- Verwendung: **< Objekt >?.< Eigenschaft >**
````Groovy
class Person {
String name
}
Person person = null
def name = person?.name
println name // Ausgabe: null
````
### 3. Methodenreferenzoperator (.&):
Der Methodenreferenzoperator wird verwendet, um eine Methode als Closure zu referenzieren. Auf Closures wird später im Skript nochmal eingegangen. Dieser Operator ermöglicht es dem Programmierer Methoden als Objekte zu behandeln, die später wieder aufgerufen werden können. Dieses Feature ist mit Lambdas in Java vergleichbar.
Verwendung: **< Methode > { < Objekt >.&< Methode >()}**
````Groovy
class Person {
def name
}
def getName(){
name
}
def personen = [new Person(name: "Tom"), new Person(name: "Max"), new Person(name: "Tim")]
def names = personen.collect {it.&getName()} //Ausgabe: [Tom, Max, Tim]
````
### 4. Spread-Operator(*.):
Der Spread Operator wird verwendet, um eine Methode auf alle Elemente einer Colletion anzuwenden.
- Verwendung:
**< Collection >*.< Methode >**
````Groovy
class Person {
def name
}
def getName(){
name
}
def personen = [new Person(name: "Tom"), new Person(name: "Max"), new Person(name: "Tim")]
def names = personen*.getName()
println names //Ausgabe: [Tom, Max, Tim]
````
### 5. Spread-Map-Operator(*: )
Ermöglicht es die Inhalte einer Map in eine andere zu kopieren. Gibt es in der Map, in die hineinkopiert werden soll einen bestimmten Key schon, dann wird der Wert an der Stelle einfach ersetzt.
Verwendung: **def map2 = [< Element1 >, < Element2 >,… \*:< map1 >]**
````Groovy
def map1: = [a: 1, b:3]
def map2= [c: 4, b: 2, *:map1]
println map2 //Ausgabe: [c:4, b:3, a:1]
````
### 6. Raumschiff-Operator (<=>):
Der Raumschiffoperator ist ähnlich zur compare() Methode in Java und wird verwendet, um zwei Werte miteinander zu vergleichen.
Verwendung: **< Wert1 > <=> < Wert2 >**
- Gilt Wert1 < Wert2: Rückgabewert: -1
- Gilt Wert1 > Wert2: Rückgabewert: 1
- Gilt Wert1 == Wert2: Rückgabewert: 0
````Groovy
println 3 <=> 5 // Ausgabe: -1
println 5 <=> 5 // Ausgabe: 0
println 7 <=> 5 // Ausgabe: 1
````
### 7. Range-Operator(..)
Der Range Operator wird in Groovy verwendet, um eine Sequenz von Werten (Ganzzahlen/Chars) innerhalb eines bestimmten Bereiches zu erstellen. Hierbei gilt: Beide Werte sind inklusiv. Will man jedoch den rechten Wert ausschließen, muss man den Range-Exclusive-Operator (..<) verwenden. Es ist auch möglich innerhalb einer Range Sprünge in einem bestimmten Intervall zu machen. Dies erreicht man mit der **(< range >).step(n)**-Methode.
- Verwendung **< Wert1 >..< Wert2 >**
````Groovy
def range = 1..5
println range.collect() // Ausgabe: [1, 2, 3, 4, 5]
def range2 = 1..<5
println range2.collect() // Ausgabe: [1, 2, 3, 4]
def range3 = (1..10).step 2
println range3.collect() // Ausgabe: [1, 3, 5, 7, 9]
````
### 8. Regex-Operatoren (=\~) / (==\~):
Die Regex-Operatoren werden verwendet, um zu prüfen, ob ein String mit einem Regulären Ausdruck (*kurz regex*) übereinstimmt.
- **(\=~)**: Prüft, ob ein Teil des Strings mit dem regulären Ausdruck übereinstimmt.
- **(==\~)**: Prüft, ob der gesamte String mit dem regulären Ausdruck übereinstimmt.
- **(\~/String/)**: Wird zum definieren ddes regulären Ausdrucks verwendet
- Verwendung: **< String > ~= < Muster >**
````Groovy
def text = "Groovy ist toll!"
def pattern = ~/Groovy/
if (text =~ pattern) {
println "Der Text entält das Muster."
}
else {
println "Der Text enthält das Muster nicht."
}
// Ausgabe: Der Text enthält das Muster.
````
Würde man jedoch den **(==\~)**-Operator benutzen, würde die Ausgabe wie folgt aussehen:
````Groovy
def text = "Groovy ist toll!"
def pattern = ~/Groovy/
if (text ==~ pattern) {
println "Der Text entält das Muster."
}
else {
println "Der Text enthält das Muster nicht."
}
// Ausgabe: Der Text enthält das Muster nicht.
````

View File

@ -0,0 +1,87 @@
# Schleifen
## While-Schleife
Syntax Kopfgesteuerte `while-Schleife`
```Groovy
def y = 0
while (y < 5){
print(y + " ") // Ausgabe: 1 2 3 4
y++
}
```
## for-Schleife
Syntax der `for-Schleife` wie in Java
```Groovy
for (int i = 0; i < 5; i++){
print(i + " ") // Ausgabe: 1 2 3 4
}
```
## times()-Schleife:
In Groovy besitzen Zahlen die Methode `n.times()`. Sie bekommt ein Closure als Parameter und führt die übergebene Methode **n-mal** aus. Man kann den Variablen innerhalb der Closure Namen geben, kann es jedoch auch sein lassen. Gibt man den Variablen keinen Namen, wird der Name *it* benutzt.
````Groovy
5.times {def e -> print e + " "} // Ausgabe: 0 1 2 3 4
5.times {println it + " "} // Ausgabe: 0 1 2 3 4
````
## each()-Schleife:
Man kann über Elemente von Collections iterieren, indem man die collection `.each()` Methode benutzt. Sie bekommt ein Closure als Parameter und wendet den Ausdruck auf alle Elemente der Liste an.
````Groovy
def map = [name: "Thomas", nachname: "Smits"]
map.each {key, value -> println "$key: $value"} // Ausgabe: name: Thomas nachname: Smits
````
## for-in Schleife
```Groovy
for (variable in iterable) {body}
```
Die `for-in Schleife` folgt dieser einfachen Struktur. Sie durchläuft das Objekt `iterable`. Häufig verwendete Iterables sind Ranges, Collections, Maps, Arrays, Iterators und Enumerationen. Jedes Objekt kann ein Groovy ein Iterable sein. Klammern um den Body sind optinal, wenn er nur aus einer Anweisung besteht.
Im Folgenden Beispiele für Iterationen:
### Über Ranges:
```Groovy
for (i in 0..5){
print(i + " ") // Ausgabe: 1 2 3 4 5
}
for (i in 'a'..<'d'){
print(i + " ") // Ausgabe: letzter Buchstabe exklusiv
}
```
### Über eine Liste:
```Groovy
def list = [1, 2, 3, 4, 5]
for (element in list){
print element + " " // Ausgabe: 1 2 3 4 5
}
```
### über eine Array:
```Groovy
def arr = ['a', 'b', 'c']
for (ch in arr){
print (ch + " ") // Ausgabe: a b c
}
```
### Über eine Map:
```Groovy
def map = [name: "Alice", age: 18]
for (entry in map){
print(${entry.key}: ${entry.value}) // Ausgabe: name: Alice age: 18
}
```
### Über eine Zeichenfolge:
```Groovy
def text = "Groovy"
for (ch in text){
print(ch + " ") // Ausgabe: G r o o v y
}
```

60
skript/tests.md 100644
View File

@ -0,0 +1,60 @@
## Tests
##### Power Assertions
Genau wie in Java, gibt es in Groovy auch das Schlüsselwort `assert`. Im Gegensatz zu Java sind Assertions in Groovy jedoch standardmäßig aktiviert. Sie erleichtern die Fehlersuche und das Debugging und zeigen eine Übersicht des Ausdrucks mitsamt der **aktuellen** Variablenwerten. Der Entwickler sieht also genau, welcher Teil des Ausdrucks das Problem verursacht hat.
````Groovy
def a = 1
def b = 2
def c = 3
// Ausdruck liefert 9 statt 10
assert a + b * c == 10
````
<img src="./../img/power-assertions.png" width="350">
Es kann während der Auswertung von Power-Assertions zu inkonsistenten Fehlermeldungen kommen. Das liegt daran, dass bei den Power-Assertions nur die Referenzen auf die Variablen gespeichert. Werden diese Werte also verändert, werden nur die aktuellen Werte angezeigt, da über die Referenz auf die Variable zugegriffen wird.
````Groovy
def getLastAndRemove(list) {
return list.remove(list.size() - 1)
}
def list = [1, 2, 3]
assert getLastAndRemove(list) == 4
````
<img src="./../img/assertion2.png" width="350">
````Groovy
assert [[1,2,3,3,3,3,4]].first().unique() == [1,2,3]
````
<img src="./../img/assertion3.png" width="350">
---
#### Spock:
- Groovy bietet nicht nur Support für JUnit 5 (und älter), sondern liefert auch einen eigenen Satz an Testmethoden, um die testgetriebene Programmierung zu vereinfachen.
Ein Beispiel hierfür wäre Spock. Mit Spock kann man sowohl Java, als auch Groovy Code testen. Getestet wird mit sogenannten Spezifikationen. Die Testklasse muss also von `spock.lang.Specification` erben.
````Groovy
class StackSpec extends Specification {
def "Ein Element zum Stack hinzufuegen führt zur erhoehung von size"() {
setup: "Eine neue Stack-Instanz wurde erstellt"
def stack = new Stack()
when:
stack.push 42
then:
stack.size() == 1
}
}
````
##### Erklärung:
- Der Name der Testmethode muss ein String sein, der beschreibt, was beim Testen erwartet wird.
- Das Schlüsselwort `setup` dient dazu, lokale Variablen zu initialisieren, die für den Test gebraucht werden (vgl. **@BeforeEach** Annotation, JUnit)
3. Das `when` Schlüsselwort beschreibt den Codeabschnitt, der zu einem bestimmten Verhalten führen soll
4. `then` beschreibt das erwartete Verhalten.

View File

@ -1,100 +0,0 @@
# Schleifen
## while-Schleife
Syntax Kopfgesteuerte `while-Schleife`
```
class Beispiel {
static void main(String[] args){
def y = 0
while (y < 5){
print(y + " ") // -> 1 2 3 4
y++
}
}
}
```
## for-Schleife
Syntax der `for-Schleife` wie in Java
```
class Beispiel {
static void main(String[] args){
for (int i = 0; i < 5; i++){
print(i + " ") // -> 1 2 3 4
}
}
}
```
## for-in Schleife
```
for (variable in iterable) {body}
```
Die `for-in Schleife` folgt dieser einfachen Struktur. Sie durchläuft das Objekt `iterable`. Häufig verwendete Iterables sind Ranges, Collections, Maps, Arrays, Iterators und Enumerationen. Jedes Objekt kann ein Groovy ein Iterable sein. Klammern um den Body sind optinal, wenn er nur aus einer Anweisung besteht.
Im Folgenden Beispiele für Iterationen:
### über Ranges:
```
class Beispiel {
static void main(String[] args){
for (i in 0..5){
print(i + " ") // -> 1 2 3 4 5
}
for (i in 'a'..<'d'){
print(i + " ") // -> a b c letzter Buchstabe exklusiv
}
}
}
```
### über eine Liste:
```
class Beispiel {
static void main(String[] args){
def list = [1, 2, 3, 4, 5]
for (element in list){
print element + " " // -> 1 2 3 4 5
}
}
}
```
### über eine Array:
```
class Beispiel {
static void main(String[] args){
def arr = ['a', 'b', 'c']
for (ch in arr){
print (ch + " ") // -> a b c
}
}
}
```
### über eine Map:
```
class Beispiel {
static void main(String[] args){
def map = [name: "Alice", age: 18]
for (entry in map){
print(${entry.key}: ${entry.value}) // -> name: Alice age: 18
}
}
}
```
### über eine Zeichenfolge:
```
class Beispiel {
static void main(String[] args){
def text = "Groovy"
for (ch in text){
print(ch + " ") // -> G r o o v y
}
}
}
```