Modul 15 · Migration Deep Dive · Stufe 2 Java Core

Lambda und Streams

imperative Schleifen und anonyme Klassen wird nachvollziehbar in Stream Pipeline mit Records und Collectors überführt. Die Akte zeigt nicht nur das Ziel, sondern die tatsächlichen Dateien, APIs, Dependencies, Codebelege, Tests, Risiken und Cutover-Schritte.

PipelineMapperReducer
2 → 2Produktionsdateien
26 → 20Java-Zeilen
1 → 1Testdateien
0 / 0Dependencies entfernt / neu
NIEDRIGRisiko · Score 0

Was sich konkret ändert

DimensionLegacyModernMigrationskonsequenz
Programmiermodellimperativ / ohne Framework-Annotationenexplizite Java-AbstraktionenAnnotationen und Containerfunktionen werden nur dort eingesetzt, wo sie eine konkrete technische Verantwortung übernehmen.
Abhängigkeiten1 direkte Dependencies1 direkte Dependencies0 neu, 0 entfernt; Versionen und transitive Auswirkungen im erfolgreichen Online-Build prüfen.
Öffentliche API1 erkannte Methoden2 erkannte MethodenMethoden werden nach fachlicher Rolle gemappt; reine Bootstrap- und Framework-Methoden sind kein fachlicher Vertrag.
Datenmodellclass LegacyOrderAnalytics, record Orderclass OrderAnalytics, record OrderFeldnamen, IDs, Null-Semantik, Gleichheit und Serialisierungsform werden separat regressionstestet.
FehlerverhaltenLegacy-Exceptions und Rückgabewerteexplizitere Fach-/Framework-FehlerabbildungFehler dürfen nicht nur technisch übersetzt werden; Status, Ursache, Retrybarkeit und Client-Vertrag müssen erhalten oder versioniert werden.
TestsBestands- und Golden-Master-TestsUnit-, Slice-, Contract- und IntegrationstestsDer Modern-Pfad wird zuerst gegen denselben fachlichen Vektor geprüft und danach um neue technische Risiken ergänzt.
BetriebLegacy-Start/Lifecyclemodernes Packaging, Health und externe KonfigurationUmstellung über kleine Adapter und Golden-Master-Tests statt Big Bang.
RollbackLegacy-Artefakt bleibt unverändertModern-Artefakt getrennt deploybarKein Rollback über Datenverlust: Schema, Nachrichten und verschlüsselte Daten müssen rückwärtslesbar oder durch Dual-Read abgesichert sein.

Fachlicher Vertrag: unverändert zu erhalten

  • Ergebnis, Reihenfolge, Rundung und Null-Semantik bleiben identisch.
  • Streams erzeugen keine versteckten Seiteneffekte.
  • Parallelisierung wird nur nach Messung aktiviert.

Hauptrisiko und Testfokus

ordering, short-circuit and null semantics

empty input, duplicates, precision and parallel-safety tests

Die Modernisierung gilt erst als abgeschlossen, wenn der fachliche Vertrag automatisiert belegt ist.

Verbindliches Code- und Rollenmapping

Die Zuordnung ist semantisch: Eine Legacy-Klasse kann in mehrere moderne Rollen zerlegt werden.

Legacy-Rolle / DateiModern-Rolle / DateiBedeutung
LegacyOrderAnalytics.javaOrderAnalytics.javaSchleifen werden zu lesbarer Stream-Pipeline.
Order.javaOrder.javaFachliches Eingabeobjekt bleibt stabil.

Legacy-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
LegacyOrderAnalytics.javaclass LegacyOrderAnalyticsList<String> paidCustomersOver(List<Order> orders, double limit)Accumulator22
Order.javarecord Order4

Modern-Quellinventar

DateiTypAnnotationenöffentliche APIPatternZeilen
Order.javarecord Order4
OrderAnalytics.javaclass OrderAnalyticsList<String> paidCustomersOver(List<Order> orders, double limit)
double totalRevenue(List<Order> orders)
Pipeline16

Dependency- und Laufzeitmigration

StatusDependencyVersionScopePrüfung
BEIBEHALTENorg.junit.jupiter:junit-jupiterBOM/Parent → BOM/Parenttest → testGemeinsame Dependency; Version und Scope im effektiven POM prüfen.
Direkte POM-Daten ersetzen keinen erfolgreichen Online-Build mit transitiver SBOM- und CVE-Prüfung.

Vorher-/Nachher-Codebelege

Die folgenden Ausschnitte stammen direkt aus den enthaltenen Projekten. Dadurch ist sichtbar, welche Verantwortung tatsächlich verschoben wurde.

Legacy
LegacyOrderAnalytics.java
Modern
OrderAnalytics.java

Migrationsbedeutung: Schleifen werden zu lesbarer Stream-Pipeline.

Legacy-Code

projects/15-lambdas-streams/legacy/src/main/java/at/aydin/lab/streams/legacy/LegacyOrderAnalytics.java

package at.aydin.lab.streams.legacy;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

// Design Pattern: Accumulator
// Zweck: Sammelt Ergebnisse imperativ in einer veränderlichen Collection.
public final class LegacyOrderAnalytics {
    public List<String> paidCustomersOver(List<Order> orders, double limit) {
        List<String> result = new ArrayList<>();
        for (Order order : orders) {
            if (order.paid()
                    && order.total() > limit
                    && !result.contains(order.customer())) {
                result.add(order.customer());
            }
        }
        Collections.sort(result);
        return result;
    }
}

Modern-Code

projects/15-lambdas-streams/modern/src/main/java/at/aydin/lab/streams/modern/OrderAnalytics.java

package at.aydin.lab.streams.modern;

import java.util.*;

// Design Pattern: Pipeline
// Zweck: Filter-, Mapping- und Reduktionsschritte werden deklarativ zusammengesetzt.
public final class OrderAnalytics {
    public List<String> paidCustomersOver(List<Order> orders, double limit) {
        return orders.stream().filter(Order::paid).filter(o -> o.total() > limit).map(Order::customer).distinct()
                .sorted().toList();
    }

    public double totalRevenue(List<Order> orders) {
        return orders.stream().filter(Order::paid).mapToDouble(Order::total).sum();
    }
}
Technischen Unified Diff öffnen
--- LegacyOrderAnalytics.java
+++ OrderAnalytics.java
@@ -1,22 +1,16 @@
-package at.aydin.lab.streams.legacy;
+package at.aydin.lab.streams.modern;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
 
-// Design Pattern: Accumulator
-// Zweck: Sammelt Ergebnisse imperativ in einer veränderlichen Collection.
-public final class LegacyOrderAnalytics {
+// Design Pattern: Pipeline
+// Zweck: Filter-, Mapping- und Reduktionsschritte werden deklarativ zusammengesetzt.
+public final class OrderAnalytics {
     public List<String> paidCustomersOver(List<Order> orders, double limit) {
-        List<String> result = new ArrayList<>();
-        for (Order order : orders) {
-            if (order.paid()
-                    && order.total() > limit
-                    && !result.contains(order.customer())) {
-                result.add(order.customer());
-            }
-        }
-        Collections.sort(result);
-        return result;
+        return orders.stream().filter(Order::paid).filter(o -> o.total() > limit).map(Order::customer).distinct()
+                .sorted().toList();
+    }
+
+    public double totalRevenue(List<Order> orders) {
+        return orders.stream().filter(Order::paid).mapToDouble(Order::total).sum();
     }
 }
Legacy
Order.java
Modern
Order.java

Migrationsbedeutung: Fachliches Eingabeobjekt bleibt stabil.

Legacy-Code

projects/15-lambdas-streams/legacy/src/main/java/at/aydin/lab/streams/legacy/Order.java

package at.aydin.lab.streams.legacy;

public record Order(long id, String customer, double total, boolean paid) {
}

Modern-Code

projects/15-lambdas-streams/modern/src/main/java/at/aydin/lab/streams/modern/Order.java

package at.aydin.lab.streams.modern;

public record Order(long id, String customer, double total, boolean paid) {
}
Technischen Unified Diff öffnen
--- Order.java
+++ Order.java
@@ -1,4 +1,4 @@
-package at.aydin.lab.streams.legacy;
+package at.aydin.lab.streams.modern;
 
 public record Order(long id, String customer, double total, boolean paid) {
 }

Umsetzungsplan mit Qualitäts-Gates

  1. Arbeitspaket 1
    Imperative Schleifen mit ihren Randfällen als Tests sichern. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  2. Arbeitspaket 2
    Zwischenschritte als benannte Mapper/Predicates extrahieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  3. Arbeitspaket 3
    Stream-Pipeline sequentiell implementieren. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  4. Arbeitspaket 4
    BigDecimal-/Rundungsregeln explizit erhalten. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  5. Arbeitspaket 5
    Leere, doppelte und nullhaltige Eingaben testen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.
  6. Arbeitspaket 6
    Imperativen Pfad erst nach Ergebnisvergleich entfernen. Nachweis: Commit/PR, automatisierter Test und aktualisierte Betriebsdokumentation.

Konkreter Test- und Abnahmekatalog

IDEbenePrüfungerforderlicher Nachweis
15-LAMBDAS-STREAMS-A01Integration/ContractGolden-Master-Ergebnisse sind identisch.Automatisierter Test und CI-Protokoll
15-LAMBDAS-STREAMS-A02Integration/ContractEncounter Order ist dokumentiert und getestet.Automatisierter Test und CI-Protokoll
15-LAMBDAS-STREAMS-A03Integration/ContractKeine Mutation externer Collections.Automatisierter Test und CI-Protokoll
15-LAMBDAS-STREAMS-A04Integration/ContractLeere Eingaben liefern definiertes Ergebnis.Automatisierter Test und CI-Protokoll
15-LAMBDAS-STREAMS-A05Integration/ContractParallelstream wird nicht unbewusst verwendet.Automatisierter Test und CI-Protokoll
15-LAMBDAS-STREAMS-T01UnitFachlogik ohne Container oder externen Dienst testen.Unit-Test
15-LAMBDAS-STREAMS-T02RegressionLegacy- und Modern-Ergebnis für denselben Golden-Master-Vektor vergleichen.Vergleichsreport
15-LAMBDAS-STREAMS-T03NegativeFehlerhafte, leere und grenzwertige Eingaben prüfen.Negativtest
15-LAMBDAS-STREAMS-T04OperationsStart, Health, Shutdown und Konfigurationsfehler prüfen.Deployment-/Startprotokoll
15-LAMBDAS-STREAMS-F01Fokusempty input, duplicates, precision and parallel-safety testsModulspezifischer Testreport

Risikoregister des Moduls

RisikoAuswirkungGegenmaßnahmeGate
ordering, short-circuit and null semanticsNIEDRIGempty input, duplicates, precision and parallel-safety testsvor Cutover

Konfiguration und Ressourcen

Keine zusätzlichen Ressourcen.

Rollback und Koexistenz

Beide Analytics-Implementierungen können hinter derselben Schnittstelle per Feature Flag verglichen werden.

Abbruchkriterien

  • Fachlicher Golden-Master weicht ab.
  • Daten-, Nachrichten- oder API-Kompatibilität ist ungeklärt.
  • Fehlerquote, Latenz oder Ressourcenverbrauch überschreiten das vereinbarte Limit.
  • Monitoring oder Rückfallpfad ist nicht funktionsfähig.

Definition of Done

Direkte Arbeitslinks

⌂ Cockpit