Schnipsel: kurze Scala-Rezepte
Manche Aufgaben kommen immer wieder: eine Datei einlesen, Zeit messen, ein Datum formatieren. Hier stehen kurze, erprobte Lösungen in Scala 3 zum Nachschlagen – jeweils mit Hinweis auf die Lektion, die den Hintergrund erklärt.
Textdatei lesen
import scala.io.Source
import scala.util.Using
val zeilen: List[String] =
Using.resource(Source.fromFile("daten.txt", "UTF-8"))(_.getLines().toList)Using.resource schließt die Datei auch im Fehlerfall; die Variante Using(…) liefert ein Try (siehe Exception Handling).
Textdatei schreiben
import java.nio.file.{Files, Path}
import java.nio.charset.StandardCharsets.UTF_8
Files.writeString(Path.of("ausgabe.txt"), "Stufe für Stufe\n", UTF_8)Die Java-Standardbibliothek genügt hier völlig. Wer viel mit Dateien arbeitet, greift zur Bibliothek os-lib: os.write(os.pwd / "ausgabe.txt", "Text").
Einfache CSV auswerten
case class Zeile(ort: String, temperatur: Double)
val daten = zeilen.drop(1) // Kopfzeile überspringen
.map(_.split(";").map(_.trim))
.collect { case Array(ort, t) => Zeile(ort, t.replace(",", ".").toDouble) }
daten.groupMapReduce(_.ort)(_.temperatur)(math.max)Für echte CSV-Dateien mit Anführungszeichen und Zeilenumbrüchen in Feldern lohnt eine Bibliothek. Mehr zu groupMapReduce unter Map.
Zeit messen
def gemessen[A](name: String)(block: => A): A =
val start = System.nanoTime
val ergebnis = block
println(f"$name: ${(System.nanoTime - start) / 1e6}%.1f ms")
ergebnis
val summe = gemessen("Summe") { (1 to 10_000_000).map(_.toLong).sum }Der By-Name-Parameter block: => A sorgt dafür, dass der Block erst innerhalb der Messung ausgeführt wird (siehe Funktionen).
Zufallszahlen
import scala.util.Random
Random.nextInt(6) + 1 // Würfel: 1 bis 6
Random.between(10, 20) // 10 bis 19
Random.shuffle(List("a", "b", "c")) // zufällige Reihenfolge
val r = new Random(42) // mit festem Startwert, reproduzierbarDatum und Uhrzeit
import java.time.{LocalDate, LocalDateTime}
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
val heute = LocalDate.now
val format = DateTimeFormatter.ofPattern("dd.MM.yyyy")
heute.format(format) // z. B. "24.09.2026"
LocalDate.parse("01.05.2027", format) // Text → Datum
ChronoUnit.DAYS.between(heute, LocalDate.of(2026, 12, 24)) // Tage bis HeiligabendUmgebungsvariablen und Argumente
val port = sys.env.get("PORT").flatMap(_.toIntOption).getOrElse(8080)
val debug = sys.props.get("debug").contains("true")Kommandozeilenargumente nimmt am einfachsten die @main-Methode entgegen, siehe Hello world.
Wiederholen, bis es klappt
import scala.util.{Try, Success, Failure}
def nochmal[A](versuche: Int)(aktion: => A): Try[A] =
Try(aktion) match
case Failure(_) if versuche > 1 => nochmal(versuche - 1)(aktion)
case ergebnis => ergebnis
nochmal(3) { ladeVomServer() }Liste in Blöcke teilen
(1 to 10).grouped(4).toList
// List(Vector(1, 2, 3, 4), Vector(5, 6, 7, 8), Vector(9, 10))
List("a", "b", "c", "d").sliding(2).toList
// List(List(a, b), List(b, c), List(c, d))Häufigstes Element
val woerter = List("scala", "java", "scala", "kotlin", "scala")
woerter.groupMapReduce(identity)(_ => 1)(_ + _).maxBy(_._2)
// (scala, 3)Text in Wörter zerlegen
"Stufe um Stufe, Schritt für Schritt!".toLowerCase
.split("[^\\p{L}]+").filter(_.nonEmpty).toList
// List(stufe, um, stufe, schritt, für, schritt)\p{L} steht für jeden Buchstaben, auch Umlaute. Mehr zu Zeichenketten unter Strings.
Enum aus Text
enum Stufe:
case Einstieg, Sprachkern, Objekte
def stufe(s: String): Option[Stufe] =
Stufe.values.find(_.toString.equalsIgnoreCase(s))
stufe("einstieg") // Some(Einstieg)Stufe.valueOf(s) gibt es auch, wirft aber bei unbekanntem Text eine Ausnahme – die Variante mit Option ist robuster (siehe Option).