Beyond Java 8 Examples

Julian | Sep 25, 2024 min read

Nachdem wir nun im ersten Teil die Theorie geklärt haben, kommt nun etwas Praxis hinzu. Hier sind Code-Beispiele und Erklärungen für die wichtigsten Features jeder Java-Version von 8 bis 23:

Java 8 (März 2014)

Lambdas & Functional Interfaces

Code:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));

Erklärung: Lambda-Ausdrücke ermöglichen es, Funktionen als Parameter zu übergeben, was den Code kürzer und prägnanter macht. Hier wird eine Liste von Namen durchlaufen und jeder Name wird ausgegeben.

Stream API

Code:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> filteredNames = names.stream()
                                  .filter(name -> name.startsWith("A"))
                                  .collect(Collectors.toList());

Erklärung: Die Stream API ermöglicht die Verarbeitung von Sequenzen von Elementen auf eine deklarative Weise. Hier wird eine Liste gefiltert, sodass nur Namen, die mit “A” beginnen, zurückgegeben werden.

Optional Class

Code:

Optional<String> name = Optional.ofNullable(null);
System.out.println(name.orElse("Default Name"));

Erklärung: Die Klasse Optional hilft dabei, NullPointerExceptions zu vermeiden, indem sie eine optionale Container-Klasse bietet. Hier wird ein Standardname zurückgegeben, wenn der ursprüngliche Name null ist.

Date and Time API

Code:

LocalDate date = LocalDate.now();
System.out.println(date);

Erklärung: Die neue Date- und Time-API ist wesentlich umfassender und fehlerresistenter als die alte. Hier wird das aktuelle Datum ausgegeben.

Java 9 (September 2017)

Project Jigsaw (Module System)

Code: (module-info.java)

module com.example {
    requires java.base;
    exports com.example;
}

Erklärung: Das Modul-System verbessert die Wartbarkeit und Sicherheit von Anwendungen durch die Modularisierung. Hier wird ein einfaches Modul definiert, das ein anderes Modul erfordert und ein Paket exportiert.

JShell (REPL)

Erklärung: JShell bietet eine interaktive Kommandozeile zum Testen von Java-Code. Es hilft beim schnellen Experimentieren ohne eine vollständige Klasse schreiben zu müssen.

Stream API Verbesserungen

Code:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
     .takeWhile(name -> !name.isEmpty())
     .forEach(System.out::println);

Erklärung: Neue Methoden wie takeWhile bieten zusätzliche Möglichkeiten zur Verarbeitung von Streams. Hier werden alle nicht-leeren Namen ausgegeben.

Factory Methods for Collections

Code:

List<String> names = List.of("Alice", "Bob", "Charlie");
System.out.println(names);

Erklärung: Diese neuen Methoden machen die Initialisierung von unveränderlichen Collections einfacher und sicherer.

Java 10 (März 2018)

Local-Variable Type Inference

Code:

var name = "Alice";
System.out.println(name);

Erklärung: var kann verwendet werden, um lokale Variablen zu deklarieren, wobei der Typ automatisch abgeleitet wird. Das erhöht die Lesbarkeit des Codes.

Java 11 (September 2018)

Neue String Methoden

Code:

String text = " Hello World ";
System.out.println(text.strip());
System.out.println(text.isBlank());
System.out.println("Hello\nWorld".lines().count());

Erklärung: Zusätzliche Methoden wie strip(), isBlank(), und lines() erleichtern die Arbeit mit Strings erheblich.

Lambda Syntax für Anonyme Klassen

Code:

Callable<String> callable = () -> "Hello, World!";
System.out.println(callable.call());

Erklärung: Lambda-Ausdrücke können jetzt auch für anonyme Klassen verwendet werden, was den Code kürzer und prägnanter macht.

HTTP Client API

Code:

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
                                 .uri(URI.create("https://example.com"))
                                 .build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

Erklärung: Die neue HTTP-Client-API erleichtert das Senden von HTTP-Anfragen.

Java 12 (März 2019)

Switch Expressions (Preview)

Code:

int num = 2;
String result = switch (num) {
    case 1 -> "one";
    case 2 -> "two";
    default -> "many";
};
System.out.println(result);

Erklärung: Switch-Ausdrücke ermöglichen es, Werte direkt zurückzugeben und machen den Code damit kürzer und prägnanter.

Java 13 (September 2019)

Text Blocks (Preview)

Code:

String textBlock = """
    Hello,
    World!
    """;
System.out.println(textBlock);

Erklärung: Textblöcke ermöglichen es, mehrzeiligen String-Text auf einfache Weise zu schreiben und verbessern die Lesbarkeit von großem Text.

Java 14 (März 2020)

Switch Expressions (Final)

Ähnlich wie in Java 12

Records (Preview)

Code:

record Point(int x, int y) {}
Point point = new Point(1, 2);
System.out.println(point.x());

Erklärung: Records sind eine neue Art von Klassen, die hauptsächlich Daten tragen und keinen zusätzlichen Code benötigen.

Java 15 (September 2020)

Sealed Classes (Preview)

Code:

public abstract sealed class Shape permits Circle, Square {}
public final class Circle extends Shape {}
public final class Square extends Shape {}

Erklärung: Sealed Classes ermöglichen es, die Schnittstellen hierarchisch zu kontrollieren und zu definieren, welche Klassen eine Klasse erweitern dürfen.

Java 16 (März 2021)

Pattern Matching for instanceof

Code:

Object obj = "Hello, World!";
if (obj instanceof String s) {
    System.out.println(s.toUpperCase());
}

Erklärung: Pattern Matching für instanceof vereinfacht das Casting und die Verwendung von Objekten.

Java 17 (September 2021)

Sealed Classes (Final)

Siehe Java 15

Pattern Matching for switch (Preview)

Code:

Object obj = "Hello";
switch (obj) {
    case Integer i -> System.out.println("Integer: " + i);
    case String s -> System.out.println("String: " + s);
    default -> System.out.println("Unknown type");
}

Erklärung: Ermöglicht die Verwendung von Mustern innerhalb von Switch-Anweisungen.

Java 18 (März 2022)

Simple Web Server

Code:

com.sun.net.httpserver.HttpServer server = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/test", (exchange -> {
    String response = "This is the response";
    exchange.sendResponseHeaders(200, response.getBytes().length);
    OutputStream os = exchange.getResponseBody();
    os.write(response.getBytes());
    os.close();
}));
server.start();

Erklärung: Einfache Einrichtung eines Webservers für Entwicklungszwecke.

Java 19 (September 2022)

Virtual Threads (Preview)

Code:

Thread.startVirtualThread(() -> {
    System.out.println("Hello from virtual thread");
});

Erklärung: Leichtgewichtige Threads, die es ermöglichen, massiv parallele Anwendungen effizient zu schreiben.

Java 20 (März 2023)

Enhancements to ARM

Code:

// Kein spezifisches Code-Beispiel erforderlich, verbesserte Architekturunterstützung

Erklärung: Verbesserung der Architektur für moderne ARM-Prozessoren.

Java 21 (September 2023)

String Templates (Preview)

Code:

String language = "Java";
String template = STR."This is ${language}!";
System.out.println(template);

Erklärung: String-Templates ermöglichen sichere und saubere Inklusion von Ausdrucksdaten in Strings.

Java 22 (März 2024)

Vector API (Incubator)

Code:

import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.VectorSpecies;

public class VectorExample {
    private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;

    public static void main(String[] args) {
        float[] a = {1.0f, 2.0f, 3.0f, 4.0f};
        float[] b = {5.0f, 6.0f, 7.0f, 8.0f};
        FloatVector va = FloatVector.fromArray(SPECIES, a, 0);
        FloatVector vb = FloatVector.fromArray(SPECIES, b, 0);
        FloatVector vc = va.add(vb);
        vc.intoArray(a, 0);
        System.out.println(Arrays.toString(a)); // [6.0, 8.0, 10.0, 12.0]
    }
}

Erklärung: Ermöglicht die Nutzung von Vektoroperationen, um numerische Berechnungen zu beschleunigen.

Java 23 (September 2024)

Enhanced Primitive Type Patterns

Code:

Object value = 42;
switch (value) {
    case Integer i -> System.out.println("Integer: " + i);
    case Double d -> System.out.println("Double: " + d);
    default -> System.out.println("Unknown type");
}

Erklärung: Bietet Muster für primitive Datentypen, was das Arbeiten mit diesen Typen vereinfacht.

Flexible Constructor Bodies

Code:

class Point {
    int x, y;
    Point(int x, int y) {
        this.x = (x < 0) ? 0 : x;
        this.y = (y < 0) ? 0 : y;
    }
}

Erklärung: Erlaubt es Konstruktoren, flexibel instanziierte Objekte zu initialisieren.

Simplified Module Imports

Code:

// Vor Java 23
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
// Java 23 Language Preview
//java --enable-preview --source 23 Helloworld.java
import module java.base;

Erklärung: Vereinfacht das Importieren und Verwalten von Modulen in Projekten.

Structured Concurrency

Code:

// Beispiel für strukturierte Concurrency
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Future<String> result1 = scope.fork(() -> task1());
    Future<String> result2 = scope.fork(() -> task2());
    scope.join();              // Warten auf alle
    scope.throwIfFailed();     // Ausnahmen behandeln
    var results = List.of(result1.resultNow(), result2.resultNow());
    results.forEach(System.out::println);
}

Erklärung: Vereinfacht die parallele Programmierung durch strukturierte und verlässliche Handhabung von Threads.

Class-File API Update

Code:

// Beispiel für Class-File API Update

Erklärung: Verbesserungen der API zum Lesen und Schreiben von Java-Klassen-Dateien.

Diese Beispiele und Erklärungen sollten dir helfen, die wichtigsten Funktionen und Änderungen in jeder Java-Version seit Java 8 bis zur aktuellen Version 23 zu verstehen und anzuwenden.