1. var für lokale Variablen (Java 10)
Idee. Der Typ wird aus der rechten Seite abgeleitet, nur für lokale, nicht initialisierte Variablen nicht.
public class VarDemo {
public static void main(String[] args) {
var list = java.util.List.of("a", "b"); // List<String>
for (var s : list) {
System.out.println(s.toUpperCase());
}
var map = new java.util.HashMap<String, Integer>();
map.put("x", 1);
}
}Erläuterungen. var ändert den Typ nicht, sondern macht die Zuweisung kürzer.
Fehler. var x; - nicht ohne Initialisierung. var in Feldern - nicht erlaubt.
Best Practices. Verwende es, wenn der Typ aus der rechten Seite offensichtlich ist (z.B. new HashMap<>(), Factorys, Stream-Operationen).
2. Switch-Ausdrücke (Java 14 permanent; 12–13 Preview)
Idee. switch gibt einen Wert zurück, Pfeile ->, yield.
public class SwitchExprDemo {
enum Day { MON, SAT, SUN }
public static void main(String[] args) {
var d = Day.SAT;
int hours = switch (d) {
case SAT, SUN -> 0;
case MON -> 8;
default -> 6;
};
System.out.println(hours);
}
}Fehler. Mischen von altem : und neuem -> in einem Block.
Best. Bevorzuge den Pfeil-Syntax, kein Fall-Through und kein break.
3. Textblöcke """...""" (Java 15)
Idee. Mehrzeilige Strings ohne Escaping.
public class TextBlocksDemo {
public static void main(String[] args) {
String json = """
{
"name": "Vitaliy",
"skills": ["Java","Spring"]
}
""";
System.out.println(json);
}Fehler. Falsche Einrückung - orientiere dich an der “gesamten Einrückung” der schließenden """.
Best. Für SQL/JSON/XML - Lesbarkeit + formatted(...) für Platzhalter.
4. Records (Java 16)
Idee. Kompakte unveränderliche DTO: equals/hashCode/toString und Accessoren werden generiert.
public record User(String username, int level) {
public User {
if (level < 0) throw new IllegalArgumentException("level >= 0");
}
public String display() { return username + ":" + level; }
}Fehler. Mutation über Reflection/besondere Tricks - bricht die Idee von Records. Best. Speichere “Daten ohne Zustand”, Validierung - im kompakten Konstruktor.
5. Pattern Matching für instanceof (Java 16)
Idee. Pattern Matching liefert sofort eine Variable des richtigen Typs.
static int len(Object o) {
if (o instanceof String s) return s.length();
if (o instanceof java.util.Collection<?> c) return c.size();
return -1;
}Fehler. Variablen Schatten: Verwende nicht den gleichen Namen wie in der inneren Bereich. Best. Entferne Casts: Weniger Rauschen und NPEs.
6. Sealed Classes/Interfaces (Java 17)
Idee. Begrenzter Polymorphismus: Wer kann erben.
public sealed interface Shape permits Circle, Rect { }
public final class Circle implements Shape {
public final double r;
public Circle(double r) { this.r = r; }
}
public non-sealed class Rect implements Shape { // weiter kann man frei erben
public final double w, h;
public Rect(double w, double h) { this.w = w; this.h = h; }
}Fehler. Vergiss permits (wenn nicht alle in einer Datei/Paket sind).
Best. Kombiniere mit switch + Patterns - erschöpfende Zweige.
7. Pattern Matching für switch + Guarded Patterns (Java 21 permanent)
Idee. switch nach Typen und Bedingungen, erschöpfende Prüfungen.
static String render(Object o) {
return switch (o) {
case null -> "null";
case String s when s.isBlank() -> "empty string";
case String s -> "str: " + s;
case Integer i && i > 0 -> "pos int: " + i;
case java.util.List<?> lst -> "list size=" + lst.size();
default -> "other";
};
}Fehler. Unabgedeckte Fälle (füge default/null hinzu).
Best. Für sealed-Hierarchien ist default oft nicht nötig - der Compiler achtet auf die Vollständigkeit.
8. Record Patterns (Java 21 permanent)
Idee. Entpacke record direkt in Variablen/Zweige switch.
record Point(int x, int y) {}
static int manhattan(Object o) {
return switch (o) {
case Point(int x, int y) -> Math.abs(x) + Math.abs(y);
default -> -1;
};
}Fehler. Nichtübereinstimmung der Arnosti/Reihenfolge der Komponenten.
Best. Verwende es zusammen mit sealed für sauberen pattern-basierten Code.
9. Unnamed Variablen & Patterns (_) (Java 22 permanent)
Idee. _ als “ich ignoriere bewusst”.
public class UnderscoreDemo {
public static void main(String[] _ /* ignoriert Argumente */) {
Object o = "java";
if (o instanceof String _) { // matched, aber der Wert ist nicht nötig
System.out.println("It is String");
}
}
}Fehler. _ kann nicht als regulärer Variablenname verwendet werden.
Best. Markiere “nicht verwendete” Parameter/Patterns, um keine Platzhalter zu erstellen.
10. Kompakte Quelldateien & Instance main (Java 25, finaler Branch unnamed/implicit)
Idee. Mini-Programme ohne expliziten Klasse im Quellcode; main ist nicht-statisch.
// Datei: Hello.java (Java 25)
void main() { System.out.println("Hello, Java 25!"); }Der Compiler “verpackt” ihn in eine Klasse beim Build.
Fehler. Verwende gleichzeitig eine reguläre Klasse und den “kompakten” Stil in einer Datei. Best. Ideal für Beispiele, Tools, Snippets.
11. Flexible Konstruktorkörper (Java 25 permanent)
Idee. In Konstruktoren kann Code ausgeführt werden, bevor super(...)/this(...) ausgeführt wird (mit Einschränkungen in Bezug auf Reihenfolge und Initialisierung).
class Base {
Base(String id) { System.out.println("Base " + id); }
}
class Child extends Base {
Child(String raw) {
String id = raw.trim().toUpperCase(); // Logik vor super(...)
super(id);
System.out.println("Child ready");
}
}Fehler. Zugriff auf this/überladene Methoden vor korrekter Initialisierung - vermeide Nebenwirkungen.
Best. Halte frühe Logik sauber/deterministisch (Parsing, Validierung, Normalisierung).
12. Module System (Java 9) – nur Sprachsyntax
Idee. module-info.java beschreibt die Grenzen.
module com.example.core {
exports com.example.api;
requires java.sql;
}Fehler. “Graue” Abhängigkeiten, vergessene exports.
Best. Fixiere explizit die öffentliche Schnittstelle über exports/opens.
13. Module Import Deklarationen (Java 25 permanent)
Idee. Importiere das gesamte Modul in den Sichtbereich des Quellcodes.
import module java.base;
import module java.sql;
public class ModuleImportDemo {
public static void main(String[] args) {
System.out.println(java.time.Instant.now());
try (var conn = java.sql.DriverManager.getConnection("jdbc:h2:mem:db")) {
System.out.println(conn.getMetaData().getURL());
} catch (Exception e) {
e.printStackTrace();
}
}Fehler. Verwechsle mit import package.*; - das ist eine andere Mechanik (Modullevel).
Best. Verwende es in modularen Anwendungen für die Explizitheit von Abhängigkeiten im Quellcode.
14. Primitiven in Patterns/instanceof/switch (Java 25 – noch Preview)**
Idee. Matching auf Primitiven ohne Boxen.
// Kompiliere mit --enable-preview --release 25
static String describeInt(int x) {
return switch (x) {
case int i && i > 0 -> "positive";
case 0 -> "zero";
default -> "negative";
};
}Fehler. Vergiss --enable-preview während der Kompilierung/Ausführung.
Best. Experimentiere vorerst punktuell; beobachte die Finalisierung in 26+.
Häufige Fehler bei der Migration (8 → 25)
- Verwechsle den switch-Ausdruck (benötigt einen Wert) und den alten
switch(Operator). - Verwende
recordals “Gott-Objekt” mit veränderlichen Feldern über Mutator-Tricks - bricht den Vertrag. sealed+switch: vergiss, neue Subklassen hinzuzufügen - der Compiler beginnt, auf fehlende Abdeckung zu protestieren.- Textblöcke mit “Treppen”-Einrückung - richte die schließenden Anführungszeichen aus.
Empfehlungen zum Stil
- Verwende Pattern Matching für Verzweigungen nach Typ/Datenform - weniger Casts und
if-else. - Für DTOs - records; für Hierarchien mit einer geschlossenen Menge - sealed.
- Für Textblöcke - text blocks; für ausdruckbaren Text - switch-Ausdrücke +
formatted(...). - Neue Lern-/CLI-Snippets demonstriere im Stil von Compact Source Files (Java 25).