Entwicklung & Code
Die wichtigsten Neuerungen von Java 25: Schneller Startup mit Stable Values
Die Veröffentlichung für das OpenJDK 25 ist für den 16. September 2025 vorgesehen. Diesmal sind 18 JEPs (JDK Enhancement Proposals) eingeplant. Das ist zwar etwas weniger als noch bei Java 24, aber dafür werden dieses Mal einige Features nach vorangehenden Previews finalisiert. Außerdem bieten die meisten Distributoren für Java 25 wieder einen verlängerten Support (LTS) an. Viele Java-Projekte wechseln in den nächsten Monaten vom letzten LTS Release 21 zu 25.
Wir werfen hier einen ersten Blick auf die aus Developer-Sicht interessantesten Punkte. Weitere Details lassen sich über die jeweiligen JEPs nachvollziehen. In einem zweiten Post betrachten wir dann die weiteren Änderungen, die mehr unter der Haube versteckt oder nicht so relevant für die Java-Entwicklerinnen und -Entwickler sind. Die meisten in diesem Beitrag beschriebenen JEPs sind übrigens Wiedervorlagen, die bereits in früheren Java-Versionen als Inkubator oder Preview veröffentlicht wurden. Ganz neu sind die Stable Values, die eine größere Flexibilität bei der Initialisierung von final-Feldern bieten.
JEP 502: Stable Values
Stable Values sind Objekte, die genau einmal zum Einsatz kommen und danach unveränderlich sind. Die JVM (Java Virtual Machine) behandelt ihren Inhalt wie eine echte Konstante und kann dieselben Optimierungen (zum Beispiel Constant Folding) anwenden, wie bei final‑Feldern – nur, dass die Initialisierung beliebig spät erfolgen darf. Damit bekommt Java eine „Deferred Immutability“, die Start‑ und Aufwärmzeiten verkürzt, ohne Sicherheitsrisiken mit Thread einzugehen. Die Ziele sind:
- Schnelleres Start‑Up: Keine monolithische Initialisierung aller Komponenten mehr.
- Entkopplung von Erzeugung & Initialisierung eines unveränderlichen Werts – ohne Performance‑Kosten.
- Garantierte At‑Most‑Once‑Initialisierung auch in hoch parallelen Szenarien.
- Konstanten‑Optimierungen für Anwendungscode zugänglich machen, nicht nur für JDK‑internen Code.
Stable Values sind eine reine Library‑API. Es wird kein neues Schlüsselwort geben. Außerdem gibt es keine Änderung an der Semantik von final, bestehender Code bleibt unberührt. Bisher müssen final‑Felder eager (sofort) initialisiert werden – die Initialisierung eines Loggers oder eine Datenbank‑Connection bremst so den Programmstart aus. Workarounds wie Lazy Holder, Double‑Checked Locking oder ConcurrentHashMap.computeIfAbsent
sind entweder eingeschränkt, fehleranfällig oder verhindern JIT‑Optimierungen (Just in Time). Stable Values schließen die Lücke zwischen strenger Immutability und flexibler Lazy‑Initialisierung.
Der Lambda-Ausdruck in orElseSet
wird garantiert genau einmal ausgeführt, selbst wenn mehrere Virtual Threads gleichzeitig logger()
aufrufen. Danach kann der JIT (Just in Time Compiler der Hotspot VM) alle Zugriffe optimieren, wie durch Constant Folding.
class OrderController {
private final StableValue logger = StableValue.of();
private Logger logger() {
return logger.orElseSet(() -> Logger.create(OrderController.class));
}
}
Stable Values sind besonders für parallele Programmierung interessant. Im Umfeld von Virtual Threads arbeitet das Entwicklerteam schon seit Längerem an weiteren Bausteinen. Während Structured Concurrency bereits zum sechsten Mal als Preview dabei ist, gelten die Scoped Values nach vier Previews jetzt als final.
JEP 506 – Scoped Values (Final in JDK 25)
Scoped Values sind eine Alternative zu ThreadLocal-Variablen, die Threads unterschiedliche Zugriffe auf einen globalen Zustand ermöglichen. ThreadLocal lässt sich beliebig ändern, hat eine unbegrenzte Lebensdauer (Leak-Gefahr, vor allem in Pools) und ist teurer durch Vererbung an Kind-Threads. Scoped Values begrenzen die Lebensdauer klar, sind read-only und lassen sich über viele Threads hinweg platz- und zeitsparend nutzen. Gegenüber den Previews wird die API finalisiert. Einzige Änderung: ScopedValue.orElse
akzeptiert kein null
mehr. Ein Web-Framework bindet beispielsweise einmal pro Request den FrameworkContext (zum Beispiel Spring ApplicationContext oder ein AuthenticationContext). Die Handler und interne Framework-Aufrufe (etwa DB-Zugriff) können auf diesen FrameworkContext zugreifen, ohne dass er immer als zusätzlicher Parameter durchgereicht werden muss. Und auch in Kind-(Virtual) Threads ist er automatisch verfügbar.
JEP 505 – Structured Concurrency (Preview)
Mit dem StructuredTaskScope erhält eine API Einzug, die zusammengehörige Nebenläufigkeit als eine Einheit behandelt: Subtasks werden im Block geforkt und über ein join() wieder zusammengeführt. Fehler sorgen gegebenenfalls für einen direkten Abbruch anderer Subtasks. Beim Debugging lässt sich in den Thread-Dumps die Task-Hierarchie leicht nachvollziehen. Damit erlaubt Structured Concurrency die Implementierung auf eine besonders les- und wartbare Art und Weise. Alternativ konnten Entwicklerinnen und Entwickler für diesen Zweck bisher die Parallel Streams, den ExecutorService oder reaktive Programmierung einsetzen. Alles sehr mächtige Ansätze, die aber gerade einfache Umsetzungen unnötig kompliziert und fehleranfällig machen.
Neu gegenüber der letzten Preview: Scopes lassen sich über statische Fabrikmethoden öffnen (open()
für den Standardfall, d. h. entweder sind alle erfolgreich oder bei einem Fehler bricht alles ab). Alternative Abschluss-Policies und Rückgabewerte werden über Joiner-basierte open(...)
-Varianten gesteuert. Ziele sind unter anderem das Vermeiden von Thread-Leaks und Cancellation-Delays sowie bessere Observability. Nicht beabsichtigt ist der Ersatz von ExecutorService/Future, neue Channel-Primitiven oder eine neue Cancel-Mechanik. Gerade bei I/O-Fan-out mit Virtual Threads wird die Koordination einfacher, robuster und nachvollziehbarer.
// --enable-preview beim Kompilieren und Starten
record Response(String user, int order) {}
Response handle() throws InterruptedException {
try (var scope = StructuredTaskScope.
Trotz seiner 30 Jahre zieht Java auch weiter viele Programmierneulinge an. Die JEPs 511 (Module Import Declarations) und 512 (Compact Source Files and Instance Main Methods) helfen aber nicht nur Anfängern, sie machen auch erfahrenen Developern das Leben einfacher. Beide JEPs erreichen nun nach mehreren vorangegangenen Previews den finalen Status.
JEP 511 – Module Import Declarations (Final in JDK 25)
Dieses JEP ergänzt die Sprache um import module
, sodass alle exportierten Pakete eines Moduls mit einer Deklaration verfügbar sind. Das reduziert Import-Boilerplate, erleichtert die Wiederverwendung modularer Bibliotheken (ohne dass der eigene Code modular sein muss) und funktioniert reibungslos neben den bekannten import-Deklarationen. Für Einsteiger oder auch für Anwender des Prototypings in JShell sinkt die Hürde, weil sie nicht mehr wissen müssen, in welchem Paket sich einzelne Typen befinden. In Szenarien mit transitiven Modulabhängigkeiten (zum Beispiel java.sql, java.xml) vereinfacht sich die Nutzung zusammengehöriger APIs spürbar.
import module java.base;
List xs = List.of("a", "b");
Path p = Path.of("data.txt");
// List/Map/Stream/Path sind ohne einzelne Paket-Imports nutzbar
JEP 512 – Compact Source Files & Instance-main (Final in JDK 25)
Wir können jetzt in einer einzelnen Java-Datei viel schlanker kleine Programme abspeichern und ausführen. Ziel ist eine sanfte Einstiegskurve: Grundkonzepte zuerst, Programmieren-im-Kleinen ohne überflüssige Zeremonie. Bei wachsender Komplexität lässt sich der Code nahtlos zu Klassen/Packages/Modulen ausbauen. Gegenüber den Previews wird das Feature finalisiert und umbenannt (aus simple wird compact). Die neue IO-Klasse liegt nun in java.lang und wird damit implizit importiert, ihre statischen Methoden aber nicht. Außerdem basiert IO jetzt auf System.out
/System.in
statt java.io.Console
.
// > java Main.java
void main() {
IO.println("Hello, World!");
}
JEP 513 – Flexible Constructor Bodies (Final in JDK 25)
Konstruktoren dürfen nun Anweisungen vor dem Aufruf von super(...)
oder this(...)
enthalten. Diese Prolog-Phase dient beispielsweise zur Validierung von Argumenten, zum Initialisieren eigener Felder, ohne das entstehende Objekt anderweitig zu referenzieren, oder zum Transformieren von Inputwerten. Danach folgt der gewohnte Epilog. Das macht viele Konstruktoren natürlicher (z. B. fail-fast
) und erhöht die Sicherheit, weil Unterklassen-Felder vor einem möglichen Zugriff durch Superklassen-Konstruktoren oder dort aufgerufene Methoden bereits gesetzt sind. Ziel ist es, überflüssige Beschränkungen zu entfernen und zusätzliche Garantien für einen vollständig initialisierten Objektzustand zu geben. Das umgeht die praktischen Probleme der bisherigen Regel „super() muss zuerst kommen“, durch die es zu unnötiger Arbeit, zu tückischen Initialisierungsfehlern bei mehreren Threads und zu Integritätsverletzungen kommen konnte.
JEP 507 – Primitive Typen in Patterns, instanceof und switch (3. Preview)
Dieser JEP macht Pattern Matching einheitlich für alle Typen, inklusive Primitive. Er erlaubt primitive Typmuster in allen Pattern-Kontexten (top-level und verschachtelt), erweitert instanceof auf Primitive (inklusive sichere, verlustfreie Umwandlungen) und lässt switch über alle primitiven Typen laufen (auch boolean, long, float, double). Ziel ist weniger Reibung und mehr Ausdrucksstärke: unsichere Casts und Boxing entfallen, da ein Pattern nur matcht, wenn die Konversion verlustfrei ist. Außerdem lassen sich Typmuster, instanceof
und „safe casting“ semantics sauber aufeinander ausrichten.
// switch mit primitive type pattern
switch (x.getStatus()) {
case 0 -> "okay";
case 1 -> "warning";
case 2 -> "error";
case int i -> "unknown: " + i; // zeigt unbekannten int-Status
}
// instanceof mit sicherer Konversion (matcht nur verlustfrei)
if (i instanceof byte b) { /* b nutzen */ }
// Record-Pattern mit sicherem Narrowing
if (json instanceof JsonObject(var map)
&& map.get("age") instanceof JsonNumber(int age)) {
// nur wenn double → int verlustfrei passt
}
JEP 508 – Vector API (erneut Inkubator)
Die Vector-API erlaubt, Vektorberechnungen in Java auszudrücken, die der HotSpot-Compiler zu nativen SIMD-Instruktionen (x64: SSE/AVX, AArch64: NEON/SVE) kompiliert – mit stabilerer Performance als rein skalare Implementierungen. In JDK 25 ist diese API erneut im Inkubatorstatus, da man noch auf die Implementierung von Value Classes als Grundlage für die Vector API wartet. Neu sind:
- VectorShuffle ↔ MemorySegment-Zugriff
- Anbindung nativer Mathe-Bibliotheken über die FFM-API statt HotSpot-C++-Code (wartungsärmer)
- Auto-Vektorisierung von Float16-Operationen (Add/Sub/Mul/Div/Sqrt/FMA) auf unterstützten x64-CPUs.
Ziel ist eine klare, plattform-agnostische API mit verlässlicher Abbildung auf Vektorbefehle und „graceful degradation“.
Das waren 8 der insgesamt 18 neuen JEPs. Die anderen, die weniger für Entwicklerinnen und Entwickler relevant, aber trotzdem spannende Themen sind, schauen wir uns in einem zweiten Post an. Zusätzlich sind die vielen kleineren Neuerungen, für die es keine JEPs gibt, in den Release-Notes zum Nachlesen. Änderungen am JDK (Java Klassenbibliothek) wie die Stable Values oder Structured Concurrency kann man sich zudem über den Java Almanac anzeigen lassen.
(mdo)
Entwicklung & Code
Modernes C++: Trauer um unseren Blogautor Rainer Grimm
Leider ist unser Autor Rainer Grimm im Oktober verstorben. Wir trauern um einen großartigen Autor, Experten und Menschen. Rainer hat seit fast zehn Jahren regelmäßig in diesem Blog über aktuelle C++-Themen, kommende Standards, komplexe Probleme und mehr geschrieben.
(Bild: Rainer Grimm)
Im Oktober 2023 hatte Rainer die Diagnose erhalten, dass er an Amyotropher Lateralsklerose (ALS) leidet, einer schweren und unheilbaren neurologischen Erkrankung, die zu Muskellähmung führt. In seinem englischen Blog „My ALS Journey“ schrieb Rainer offen über seine Krankheit. Noch Anfang September lautete die Überschrift „I feel good“.
Bis zum Schluss war sein Ziel, über die Krankheit zu informieren und die Forschung indirekt zu unterstützen, um Ansatzpunkte für Therapien zu finden. Außerdem sammelte er immer wieder Geld für die ALS-Forschung, unter anderem durch spezielle Aktionen beim Verkauf seiner Bücher und durch einen Spendenlauf.
Experte für C++
Als Experte schrieb er über C++ und andere IT-Themen. Neben seinem regelmäßigen Blog verfasste er zahlreiche Artikel und sieben Bücher. Ein achtes Buch hatte er in Arbeit. Zusätzlich arbeitete er als Trainer und trat auf zahlreichen Konferenzen auf.
Seinen Blog schrieb er bis zum Schluss regelmäßig und hat in den vergangenen Monaten die wichtigsten Neuerungen von C++26 vorgestellt. „Modernes C++“ erschien lange Zeit wöchentlich. Nach dem Fortschreiten seiner Krankheit wechselte er auf einen Zweiwochentakt. Er konnte dabei bereits nicht mehr tippen, sondern diktierte die Texte, und seine Ehefrau Beatrix Jaud-Grimm half bei der Korrektur. Bis zum Ende hielt er Onlinevorträge und war als Trainer aktiv.
Geboren wurde Rainer am 26. Juni 1966. Nach seiner Ausbildung zum Krankenpfleger und Rettungssanitäter holte er das Abitur nach und studierte Mathematik. Er arbeitete anschließend als Softwarearchitekt bei der Tübinger Firma Science + Computing. 2016 hatte er zusammen mit seiner Ehefrau ein Schulungsunternehmen für C++ gegründet.
Leidenschaft für den Laufsport
Rainer war nicht nur IT-Experte, sondern auch leidenschaftlicher Läufer und Trainer beim TV Rottenburg. Er hat an vielen Meisterschaften teilgenommen und als junger Mann zweimal den Ironman absolviert. Noch im September hatte er einen Spendenlauf für die ALS-Forschung organisiert.
Anfang Oktober 2025 erkrankte Rainer an einer schweren Lungenentzündung. Er entschied sich bewusst gegen lebenserhaltenden Maßnahmen, die eine Dauerbeatmung bedeutet hätten und ihm die Möglichkeit zu sprechen genommen hätten.
Rainer starb am 6. Oktober im Kreis seiner Familie. Er hinterlässt seine Ehefrau Beatrix, die ihn während seiner Krankheit aufopfernd gepflegt hat, und zwei Kinder.
(rme)
Entwicklung & Code
Die Produktwerker: Anforderungen wirksam kommunizieren als Product Owner
Anforderungen zu formulieren, gehört zum Alltag jeder Produktrolle. Doch obwohl viele Product Owner viel Zeit und Sorgfalt in ihre User Stories und Akzeptanzkriterien stecken, kommt am Ende oft etwas anderes heraus als gedacht. Warum ist das so – und was lässt sich daran ändern?
Klare Kommunikation für wirksame Produktentwicklung
In der aktuellen Folge des Podcasts „Die Produktwerker“ sprechen Tim Klein und Oliver Winter darüber, worauf es bei der Kommunikation von Anforderungen wirklich ankommt. Dabei geht es weniger um Tools oder Templates – sondern um die Frage, wie Sprache, Haltung und Kontext darüber entscheiden, ob Teams und Stakeholder das Gleiche verstehen, wenn sie über ein Feature oder ein Problem sprechen.
Die beiden Gastgeber greifen damit ein alltägliches, aber oft unterschätztes Thema auf – und geben zahlreiche Impulse für mehr Klarheit, bessere Zusammenarbeit und letztlich wirksamere Produktentwicklung. Eine Folge, deren Inhalte Product Ownern in ihrer täglichen Arbeit sofort weiterhelfen werden.
(Bild: deagreez/123rf.com)
So geht Produktmanagement: Auf der Online-Konferenz Product Owner Day von dpunkt.verlag und iX am 13. November 2025 kannst du deinen Methodenkoffer erweitern und dich von den Good Practices anderer Unternehmen inspirieren lassen.
Die aktuelle Ausgabe des Podcasts steht auch im Blog der Produktwerker bereit: „Anforderungen wirksam kommunizieren als Product Owner„.
(mai)
Entwicklung & Code
Visual Studio Code 1.105 erweitert KI-Chat um vollqualifizierte Tool-Namen
Mit der September-2025-Version von Visual Studio Code führt Microsoft eine Reihe von Neuerungen ein, darunter erweiterte Chat-Funktionen und vollqualifizierte Tool-Namen sowie einen MCP-Marktplatz. Entwicklerinnen und Entwickler erhalten zudem neue Möglichkeiten zur KI-gestützten Konfliktlösung und verbesserte Authentifizierungsoptionen.
Chat-System erhält umfangreiche Neuerungen
Das Chat-System von Visual Studio Code 1.105 führt vollqualifizierte Tool-Namen ein, um Konflikte zwischen integrierten Tools und solchen von MCP-Servern oder Extensions zu vermeiden. Die Namen der Tools verweisen nun unmittelbar auf den MCP-Server, die Erweiterung oder die Werkzeugsammlung, zu der sie gehören. Statt codebase
verwenden Entwickler nun search/codebase
, statt list_issues
nutzen sie github/github-mcp-server/list_issues
. Laut Microsoft hilft dies auch beim Auffinden fehlender Extensions oder MCP-Server.
Eine Code Action unterstützt bei der Migration zu den qualifizierten Tool-Namen.
(Bild: Microsoft)
Für benutzerdefinierte Modelle hat Microsoft die Edit-Tools verbessert und einen Lernmechanismus zur Auswahl optimaler Tool-Sets eingeführt. Bei OpenAI-kompatiblen Modellen lässt sich die Liste der Edit-Tools über die Einstellung github.copilot.chat.customOAIModels
konfigurieren. Die Unterstützung für verschachtelte AGENTS.md-Dateien in Unterordnern des Arbeitsbereichs ist als experimentelle Funktion verfügbar. Dies ermöglicht spezifischere Kontexte und Anweisungen für verschiedene Codebereiche, etwa unterschiedliche Vorgaben für Frontend- und Backend-Code. Die Funktion lässt sich über die Einstellung chat.useNestedAgentsMdFiles
aktivieren.
Benachrichtigungen des Betriebssystems informieren nun über eingehende Chat-Antworten, wenn das VS Code-Fenster nicht im Fokus steht. Die Benachrichtigung enthält eine Vorschau der Antwort und bringt bei Auswahl den Chat-Input in den Fokus. Das Verhalten steuert die Einstellung chat.notifyWindowOnResponseReceived
. In Visual Studio Code 1.105 stehen zudem neue LLMs zur Verfügung: GPT-5-Codex von OpenAI, optimiert für agentisches Coding, und Claude Sonnet 4.5 von Anthropic für Coding und Real-World-Agenten. Die Auswahl erfolgt über den Modell-Picker im Chat.
MCP-Marktplatz als Vorschau-Feature
Die neue Version des kostenlosen Code-Editors stellt erstmals einen MCP-Marktplatz in der Extensions-Ansicht bereit, der das Durchsuchen und Installieren von MCP-Servern direkt im Editor ermöglicht. Der Marktplatz nutzt die GitHub MCP Registry als Datenquelle. Entwickler können MCP-Server über den @mcp-Filter, die Dropdown-Auswahl „MCP Servers“ oder die direkte Namenssuche finden. Die Funktion ist standardmäßig deaktiviert und lässt sich über chat.mcp.gallery.enabled
aktivieren. Laut Microsoft befindet sich das Feature noch in der Vorschau-Phase – etwaige Unzulänglichkeiten beim Verwenden seien daher nicht auszuschließen.
Beim Senden von Chat-Nachrichten starten MCP-Server nun automatisch. VS Code vermeidet in diesem Fall störende Dialoge und zeigt stattdessen Indikatoren im Chat an, wenn ein Server Aufmerksamkeit benötigt. Die Einstellung chat.mcp.autostart
steuert das Verhalten.
Verbessert hat das VS-Code-Entwicklungsteam zudem die Darstellung von MCP-Ressourcen aus Tools: Der Editor fügt standardmäßig eine Vorschau des Ressourceninhalts hinzu und gibt Anweisungen zum Abrufen vollständiger Inhalte, was die Modell-Performance bei der Tool-Nutzung steigern soll. Darüber hinaus wurden einige MCP-Spezifikations-Updates implementiert: SEP-973 ermöglicht benutzerdefinierten Icons für Server, Ressourcen und Tools. SEP-1034 erlaubt Standard-Werte bei der Elicitation-Nutzung.
Weitere Verbesserungen für Entwickler
Visual Studio Code 1.105 führt KI-gestützte Lösung von Merge-Konflikten ein. Bei Dateien mit Git-Merge-Konflikt-Markierungen erscheint eine neue Aktion in der unteren rechten Editor-Ecke, die den Chat öffnet und einen agentischen Ablauf mit Merge-Base und Änderungen beider Branches als Kontext startet.
Das runTests-Tool im Chat unterstützt nun Test-Code-Coverage-Berichte an den Agenten, was die Generierung und Verifikation von Tests ermöglicht, die den gesamten Code abdecken. Für lang laufende Tasks zeigt VS Code OS-Benachrichtigungen bei Abschluss an, wenn das Fenster nicht im Fokus steht. Die Einstellung task.notifyWindowOnTaskCompletion
steuert dieses Verhalten.
Alle weiteren Informationen zu Visual Studio Code 1.105 lassen sich dem Ankündigungsbeitrag entnehmen.
Lesen Sie auch
Python in Visual Studio Code: Verbesserungen für Python Environments
Nicht nur den Sourcecode-Editor selbst, sondern auch die Python-Erweiterungen hat Microsoft mit einem Update versehen. Im Oktober-Release (während bei Visual Studio Code der Vormonat namensgebend ist, richtet sich die Python-Erweiterung nach dem aktuellen) widmet sich das Entwicklungsteam insbesondere den Verbesserungen der Erweiterung Python Environments. Das Update verspricht unter anderem verbesserte Leistung und Zuverlässigkeit bei der Arbeit mit Conda-Umgebungen – Code lässt sich nun direkt ohne conda run
starten. Auch gelegentlich auftretende Abstürze beim Ausführen von Python-Dateien, die input() verwenden, wurden korrigiert. Die Erweiterung aktualisiert nun auch automatisch die Umgebungsmanager beim Erweitern von Baumknoten, sodass die Umgebungsliste ohne weitere Maßnahmen auf dem neuesten Stand bleibt.
Weitere Informationen zu den Updates für Python in VS Code liefert ein Beitrag auf Microsofts Entwicklerblog.
(map)
-
UX/UI & Webdesignvor 2 Monaten
Der ultimative Guide für eine unvergessliche Customer Experience
-
UX/UI & Webdesignvor 1 Monat
Adobe Firefly Boards › PAGE online
-
Social Mediavor 2 Monaten
Relatable, relevant, viral? Wer heute auf Social Media zum Vorbild wird – und warum das für Marken (k)eine gute Nachricht ist
-
Entwicklung & Codevor 2 Monaten
Posit stellt Positron vor: Neue IDE für Data Science mit Python und R
-
Entwicklung & Codevor 1 Monat
EventSourcingDB 1.1 bietet flexiblere Konsistenzsteuerung und signierte Events
-
UX/UI & Webdesignvor 4 Wochen
Fake It Untlil You Make It? Trifft diese Kampagne den Nerv der Zeit? › PAGE online
-
Apps & Mobile Entwicklungvor 3 Monaten
Firefox-Update 141.0: KI-gestützte Tab‑Gruppen und Einheitenumrechner kommen
-
Online Marketing & SEOvor 3 Monaten
So baut Googles NotebookLM aus deinen Notizen KI‑Diashows