Dynamische Sprache für die JVM mit Skript-Komfort
Ausführen: Datei hallo.groovy speichern und mit groovy hallo.groovy ausführen (Apache Groovy 4 von groovy-lang.org, benötigt Java).
def für dynamische Variablen, Typen sind optional; Semikolons und Klammern oft überflüssig${...} (GString)7 / 2 ergibt 3.5; intdiv liefert die Ganzzahldivisiongroovy hallo.groovy # Skript ausführen
groovy -e 'println 1 + 2' # Einzeiler
groovysh # interaktive Konsole
groovyc Hallo.groovy # zu .class übersetzen
sdk install groovy # Installation mit SDKMAN!return ist optionalnull, 0, leere Strings/Collections sind falsch?: (Elvis) und ?. (sicherer Zugriff) vermeiden null-Fehler{ x -> ... } sind Werte: curry, >>, it und Übergabe als letztes Argumentdef n = 15
if (n % 15 == 0) println "FizzBuzz"
else if (n % 3 == 0) println "Fizz"
else println n
def status = n > 10 ? "groß" : "klein"
println status
println(null ? "wahr" : "falsch")
println("" ? "wahr" : "falsch")
println([] ? "wahr" : "falsch")
println([0] ? "wahr" : "falsch")
println("x" ? "wahr" : "falsch")
def name = null
println name ?: "Standardname" // Elvis-Operator
println name?.length() // sicherer Zugriff
println "Text"?.toUpperCase()
switch (n) {
case 1..9: println "einstellig"; break
case [10, 15, 20]: println "in der Liste"; break
case ~/\d+/: println "Regex"; break
default: println "sonst"
}
switch ("hallo") {
case String: println "ein String"; break
}[...], Maps [key: value], Ranges 1..5 und Sets bieten viele Komfortmethodencollect, findAll, inject, groupBy, countBy, sum, sort { } ersetzen Schleifen*. (Spread) ruft eine Methode für jedes Element auf; *liste verteilt ArgumentewithDefault macht Zählermaps einfachdef l = [5, 3, 9, 1, 7]
println l
println "${l.size()} ${l[0]} ${l[-1]} ${l.first()} ${l.last()}"
println l[1..3]
println l.sort(false)
println l.reverse()
println l.collect { it * 2 }
println l.findAll { it > 4 }
println l.find { it > 4 }
println "${l.sum()} ${l.min()} ${l.max()} ${l.count { it > 3 }}"
println l.inject(0) { acc, x -> acc + x }
println "${l.any { it > 8 }} ${l.every { it > 0 }}"
println l.take(2)
println l.drop(3)
println l.join("-")
println (l + [8, 9])
println (l - [3, 9])
println l.indexOf(9)
println l.contains(7)
l << 11
l.add(0, 100)
l.remove(0)
println l
println l.groupBy { it % 2 == 0 ? "gerade" : "ungerade" }
println l.collate(2)
println([[1, 2], [3]].flatten())
println([1, 2, 2, 3, 3, 3].unique())
println ([1, 2, 3].withIndex().collect { v, i -> v * i })
println l.sort().toUnique()
def kopf = l.head()
println kopf
println([3, 1, 2].sort { a, b -> b <=> a })
println(["bb", "a", "ccc"].sort { it.length() })
println ([1, 2, 3, 4].split { it % 2 == 0 })interface, abstract class und trait strukturieren Code@ToString, @EqualsAndHashCode, @Immutable, @Memoized sparen Boilerplateclass Person {
String name
int alter
private int geheim = 42
String toString() { "$name ($alter)" }
boolean istVolljaehrig() { alter >= 18 }
static Person kind(String name) { new Person(name: name, alter: 5) }
}
def p = new Person(name: "Mia", alter: 17)
println p
p.alter = 18 // ruft setAlter(18) auf
println p.alter
println p.istVolljaehrig()
println Person.kind("Ben")
println p.getName()
println p.properties.keySet().sort()
println p.metaClass.respondsTo(p, "istVolljaehrig").size() > 0
p.name += " Muster"
println p.name=~, find, findAll, Indexierung s[0..4], format, Templatesfile.text, <<, eachLine, withWriter, eachFileMatchJsonSlurper/JsonOutput und XmlSlurper/MarkupBuilder verarbeiten JSON und XML/.../ vermeiden Escape-Orgien bei Regex und Pfadendef s = "Hallo Groovy-Welt"
println s.size()
println s.toUpperCase()
println s.substring(6, 12)
println s[0..4]
println s[-4..-1]
println s.replace("Welt", "Erde")
println s.replaceAll(/[aeiou]/, "*")
println s.split(/[ -]/).toList()
println s.contains("Groovy")
println s.startsWith("Hallo")
println s.indexOf("G")
println s.reverse()
println s.tokenize(" -")
println s.count("l")
println " trim ".trim() + "|"
println "abc".center(9, "*")
println "42".toInteger() + 1
println "3.5".toDouble() * 2
println "x".isNumber()
println "12".isNumber()
println "a,b,,c".split(",", -1).size()
println s =~ /G\w+/ ? "gefunden" : "nichts"
def m = (s =~ /(\w+)-(\w+)/)
println m[0]
println m[0][2]
println "2024-03-15".find(/(\d+)-(\d+)-(\d+)/) { all, j, mo, t -> "$t.$mo.$j" }
println "Preise: 12, 7 und 120".findAll(/\d+/)*.toInteger().sum()
println String.format("%05d|%-6s|%8.3f|%x", 42, "li", Math.PI, 255)
println String.format("%,d", 1234567)
println "ab".padLeft(5, "_")
println "CamelCaseText".split(/(?=[A-Z])/).toList()
println "wort".capitalize()
println "a\tb".expand()delegate und Closures erlauben DSLs wie Gradle oder JenkinsmethodMissing, propertyMissing und metaClass erweitern Klassen zur Laufzeituse) und Expando sind leichtgewichtige Alternativen@CompileStatic bringt Typprüfung und Tempoclass HtmlBuilder {
StringBuilder sb = new StringBuilder()
int tiefe = 0
def methodMissing(String name, args) {
def attribute = args.find { it instanceof Map } ?: [:]
def inhalt = args.find { it instanceof Closure }
def text = args.find { it instanceof String }
def attr = attribute.collect { k, v -> " $k=\"$v\"" }.join()
sb << " " * tiefe << "<$name$attr>"
if (inhalt) {
sb << "\n"
tiefe++
inhalt.delegate = this
inhalt()
tiefe--
sb << " " * tiefe
} else if (text) sb << text
sb << "</$name>\n"
}
}
def b = new HtmlBuilder()
b.html {
body(class: "start") {
h1("Hallo")
p("Absatz")
}
}
print b.sbjava.time, java.util.concurrent, ...)Thread.start { }, ExecutorService, AtomicInteger"befehl".execute() startet Prozesse; .text liefert die Ausgabe@Grab lädt Bibliotheken ohne Build-Dateiimport java.time.*
import java.util.concurrent.*
def datum = LocalDate.of(2024, 3, 15)
println datum.plusDays(20)
println datum.dayOfWeek
println Duration.ofMinutes(135).toHours()
def liste = new ArrayList<String>()
liste.add("b"); liste.add("a")
Collections.sort(liste)
println liste
println Math.floorMod(-7, 3)
println java.util.UUID.nameUUIDFromBytes("x".bytes).toString().size()
println new Random(42).nextInt(100) >= 0
println String.valueOf([1, 2, 3] as int[])
println System.getProperty("java.version") != null
println Runtime.runtime.availableProcessors() > 0
println 'abc'.bytes
println new String([72, 105] as byte[])def zeile = { String a, String b -> println "${a.padRight(18)} $b" }
zeile("1 + 1", "${1 + 1}")
zeile("'a' * 3", "${'a' * 3}")
zeile("[1,2,3].sum()", "${[1, 2, 3].sum()}")
zeile("(1..4).sum()", "${(1..4).sum()}")
zeile("null?.size()", "${null?.size()}")
zeile("0 ?: 'leer'", "${0 ?: 'leer'}")
zeile("[3,1,2].sort()", "${[3, 1, 2].sort()}")
zeile("'abc'[1]", "${'abc'[1]}")
zeile("1.0 == 1", "${1.0 == 1}")
zeile("'a'.equals('a')", "${'a'.equals('a')}")
zeile("'a'.is('a')", "${'a'.is('a')}")
zeile("[1,2] == [1,2]", "${[1, 2] == [1, 2]}")
zeile("5 in 1..10", "${5 in 1..10}")
zeile("[a:1].a", "${[a: 1].a}")
zeile("Integer.MAX_VALUE", "${Integer.MAX_VALUE}")