- 1 Section
- 10 Lessons
- unbegrenzt
- Debugging & Fehleranalyse10
- 1.1Fehlertypen: Syntaxfehler, Laufzeitfehler, Logikfehler
- 1.2Systematische Fehlersuche: Duck-Debugging, Divide & Conquer
- 1.3Debugger-Grundkonzepte: Breakpoints, Watches, Call Stack
- 1.4Debugging in Java mit IntelliJ / Eclipse
- 1.5Debugging in Python mit VS Code und pdb
- 1.6Debugging in JavaScript: Browser DevTools
- 1.7Logging: Fehler protokollieren und auswerten
- 1.8Fehler in Datenbankabfragen finden
- 1.9Fehler in Netzwerkverbindungen und APIs debuggen
- 1.10Praxisaufgaben: Fehlerhafte Programme korrigieren
Debugging in Java mit IntelliJ / Eclipse
Mit den Debugger-Grundkonzepten aus L3 bist du gerüstet für jeden Debugger – jetzt schauen wir konkret auf Java. Die wichtigsten IDEs sind IntelliJ IDEA (heute Industrie-Standard) und Eclipse (älter, immer noch verbreitet). Beide haben ausgezeichnete Debugger – die meiste Zeit zeigen wir IntelliJ, weil es heute die Mehrheit nutzt. Eclipse funktioniert sehr ähnlich, Tastaturkürzel weichen aber teils ab.
Java hat einen großen Vorteil: das ganze Debugging passiert auf JVM-Ebene (Java Virtual Machine). Die JVM unterstützt das JDWP (Java Debug Wire Protocol) – ein standardisiertes Protokoll. Daher funktionieren IntelliJ, Eclipse, NetBeans und sogar VS Code (mit Plugin) alle gleich. Sogar Remote-Debugging über Netzwerk klappt damit.
1) Debug-Modus starten
Der erste Schritt: Code im Debug-Modus laufen lassen statt im normalen „Run"-Modus. In IntelliJ gibt es einen grünen Käfer-Button in der Toolbar oben rechts neben dem normalen Run-Pfeil. Oder per Tastatur: Shift+F9. In Eclipse: F11.
Was ist anders? Der Debug-Modus hängt die IDE an die JVM des Programms via JDWP. Damit kann sie das Programm steuern – anhalten, weiterlaufen, Variablen lesen. Im normalen Run-Modus läuft das Programm „blind" durch, du siehst nur die Console-Ausgaben.
Wichtig: Setze vor dem Start mindestens einen Breakpoint, sonst läuft der Debug-Lauf einfach komplett durch und beendet sich, ohne dass du was tun konntest. Ein Klick links neben einer Zeilennummer setzt einen Breakpoint (roter Punkt erscheint). Erst dann Debug starten.
2) Das Debug-Tool-Window
Sobald das Programm an einem Breakpoint anhält, öffnet IntelliJ automatisch das Debug-Tool-Window am unteren Bildschirmrand. Es hat mehrere Tabs:
- Threads & Variables: zeigt alle laufenden Threads und die lokalen Variablen pro Frame
- Console: stdout/stderr des Programms
- Watches: explizit hinzugefügte Beobachtungs-Ausdrücke
- Frames: der Call Stack
- Memory View: Speicherauslastung pro Klasse (für Memory-Leak-Diagnose)
Im Editor selbst erscheinen jetzt Inline-Werte – kleine graue Annotationen direkt neben Variablen, die ihren aktuellen Wert zeigen. Sehr praktisches Feature: du siehst auf einen Blick was los ist, ohne das Variables-Panel anschauen zu müssen.
3) IntelliJ-Debugger live
Schauen wir uns einen realistischen Debug-Lauf an. Wir haben eine fehlerhafte Funktion: ein Online-Shop berechnet Rabatte, aber die Mathematik ist kaputt. Klick durch die Steps und beobachte das Variable-Panel, den Call Stack und die Inline-Werte:
price * percent / 200.0 mit price=100 und percent=10 ergibt 5, aber 10% von 100 sind 10. Division durch 200 statt 100 ist der Fehler.4) Wichtige Tastenkürzel
Mit der Maus debuggen ist langsam – die Profis nutzen Shortcuts. IntelliJ und Eclipse haben sehr ähnliche Bindings, hier die wichtigsten:
5) Inline-Werte und Datatips
Ein Feature das du sofort lieben wirst: Inline Values. Während du im Debug-Modus pausiert bist, zeigt IntelliJ direkt im Code die aktuellen Werte als kleine graue Annotation rechts neben jeder Variable. Diese Inline-Werte sind brutal effizient: du brauchst nicht ständig zum Variables-Panel zu schauen, sondern siehst alles direkt im Code-Kontext.
Wenn du mit der Maus über eine Variable hoverst, öffnet sich ein Data-Tooltip mit der Struktur des Objekts – inklusive Klick auf Objektfelder zum Aufklappen. Das ist besonders praktisch bei komplexen Objekten wie List/Map/HashMap. Bei einer ArrayList
6) Conditional und Logpoint-Breakpoints
Wie in L3 erwähnt: normale Breakpoints stoppen immer. In Schleifen wäre das nervig. Die Lösung: Rechtsklick auf den roten Punkt → Edit Breakpoint öffnet ein Dialog wo du Bedingungen und Aktionen einstellen kannst.
Praxis-Beispiele für IntelliJ-Conditions (gültige Java-Boolean-Ausdrücke):
i == 100– stoppt nur in der 100. Iterationuser == null– stoppt nur wenn user null istlist.size() > 1000– nur bei großen Listenuser.getName().startsWith("admin")– nur bei bestimmten Datenprice < 0 || price > 10000– nur bei unplausiblen Werten
Logpoints sind eine Spezialform: statt anzuhalten, loggen sie einen Wert in die Console. Du machst einen normalen Breakpoint, rechtsklickst drauf, wählst „Suspend off" und „Log evaluated expression": "User: " + user.getName(). Bei jedem Erreichen wird das gedruckt, das Programm läuft aber durch. Sehr nützliches Ersatz-Tool für temporäre System.out.println()-Statements: du baust nichts in den Code ein, aber kriegst trotzdem Output.
7) Exception-Breakpoints
Spezialform: auto-stoppen bei Exceptions. Wenn dein Programm crasht, willst du oft an der Stelle des Crashes sein – ohne vorher zu wissen wo das ist. In IntelliJ: Strg+Shift+F8 öffnet die Breakpoints-Verwaltung → „Java Exception Breakpoints" → + → NullPointerException hinzufügen. Ab jetzt stoppt der Debugger bei jeder NPE – egal wo im Code.
Sehr nützlich auch für deine eigenen Exception-Klassen: InvalidInputException oder ähnliche Domain-Exceptions. Bei sporadischen Crashes findest du so sofort den Ort. Aber Achtung: bei „caught" Exceptions, die mit try/catch behandelt werden, ist das auch aktiv – kann nerven. Optionen: nur „uncaught" stoppen, oder spezifische Exception-Typen.
8) Evaluate Expression
Eine extreme Power-User-Funktion: Alt+F8 öffnet einen Editor wo du beliebigen Java-Code im aktuellen Debug-Kontext ausführen kannst. Beispiele:
- „Wie viele Items sind in der Liste?" →
items.size() - „Was wäre wenn ich diesen Wert ändere?" →
discount = 10.0setzen - „Was gibt diese Methode für andere Inputs zurück?" →
applyDiscount(50.0, 20.0) - „Sind alle Items teurer als 10?" →
items.stream().allMatch(i -> i.getPrice() > 10)
Das ist Live-Java im laufenden Programm. Eine geniale Funktion um Hypothesen schnell zu testen. Im Vergleich zu „Code ändern + neu kompilieren + neu starten" sparst du Minuten pro Test. Du kannst sogar komplexe Stream-Ausdrücke aus K40b hier evaluieren.
9) Stacktrace lesen
Wenn ohne Debugger ein Crash kommt, sehen Anfänger meist nur „rote Schrift im Terminal" und scrollen weg. Profis lesen den Stacktrace systematisch von oben nach unten:
So liest du das richtig:
- Erste Zeile (Top): der Exception-Typ + die hilfreiche „Helpful NPE"-Message ab Java 14: „Cannot invoke
String.length()because the return value ofUser.getName()is null". Java-magisch: genau die Variable die null war! - Zweite Zeile: wo der Crash passiert ist –
OrderProcessor.java:42. In IntelliJ klickst du drauf und springst direkt hin. - Weitere Zeilen: die Aufruf-Hierarchie.
processUserwurde vonprocessOrdersZeile 25 aufgerufen, das wiederum vonMain.runZeile 18, gestartet inmain.
Mit dieser Info weißt du in unter einer Minute wo der Bug ist. Helpful NullPointerException ist eine moderne Java-Funktion (seit Java 14, by default aktiv ab Java 15+) – ältere Java-Versionen sagen nur „NullPointerException" ohne den hilfreichen Hinweis welche Variable null war. Wenn deine Firma noch Java 8 nutzt: rüste das nach.
10) Stream-Debugging
Eine Java-Spezialität: Stream-API. Code wie list.stream().filter(...).map(...).collect(...) ist schwer zu debuggen, weil alles in einer Zeile passiert. IntelliJ hat hier ein Geheimwaffe: Trace Current Stream Chain.
Setze einen Breakpoint auf die Zeile mit der Stream-Operation. Im Debug-Modus: rechtsklicken im Variables-Panel → „Trace Current Stream Chain". Es öffnet sich eine Visualisierung die jeden Schritt zeigt: was kam vor filter rein, was nach filter raus, was nach map, was am Ende. Sehr lehrreich um zu verstehen warum eine Stream-Pipeline nicht das tut was du dachtest.
11) Remote-Debugging
Eine weitere Java-Stärke: du kannst die JVM im Hintergrund auf einem Server debuggen – ohne IDE auf dem Server zu installieren. Starte deine Java-App mit:
Die JVM hört jetzt auf Port 5005 für Debugger-Verbindungen. In IntelliJ erstellst du eine „Remote JVM Debug"-Konfiguration mit der Server-IP und Port 5005. Beim Starten verbindet sich IntelliJ über das Netzwerk an die laufende JVM, und du kannst Breakpoints setzen, als wäre es lokal.
Sehr nützlich für: Bugs die nur in einer bestimmten Server-Umgebung auftreten, Staging-Tests mit echten Daten, oder wenn du keinen Reproduktions-Setup lokal hast. Aber Vorsicht in Production: Debug-Port nie öffentlich exponieren – das wäre ein massives Sicherheitsrisiko. Nur in geschützten Netzen nutzen.
12) Hot Code Replacement
Während du im Debug-Modus pausiert bist, kannst du Code ändern und „neu laden" ohne das Programm zu beenden. In IntelliJ heißt das HotSwap: nach einer Code-Änderung drückst du Strg+F9 (Build Project) – wenn die Änderung kompatibel ist, lädt die JVM die neue Klassen-Version sofort, während die App weiterläuft.
Was geht:
- Method-Bodies ändern
- Inhalte von Schleifen anpassen
- String-Literale ändern
Was NICHT geht:
- Neue Methoden oder Felder hinzufügen (sehr begrenzt)
- Klassen-Hierarchie ändern
- Statische Initialisierer
Für die nicht-unterstützen Änderungen gibt es Plugins wie JRebel oder DCEVM, die fast jede Änderung hot-replacen können. Großer Produktivitäts-Boost wenn man oft kleine Änderungen testet.
13) Eclipse: die Unterschiede
Wer mit Eclipse arbeitet, hat fast die gleichen Features mit anderen Kürzeln. Die wichtigsten Unterschiede:
| Aktion | IntelliJ | Eclipse |
|---|---|---|
| Debug starten | Shift+F9 | F11 |
| Breakpoint toggle | Strg+F8 | Strg+Shift+B |
| Step Over | F8 | F6 |
| Step Into | F7 | F5 |
| Step Out | Shift+F8 | F7 |
| Resume | F9 | F8 |
| Inspect Expression | Strg+Alt+F8 | Strg+Shift+I |
| Display View | Variables-Panel | Display-View (Editor für Expressions) |
Eclipse hat zusätzlich die nützliche Display View: ein leerer Editor wo du Java-Statements eingibst und mit Strg+Shift+D ausführst. Praktisch für mehr-zeilige Experimente während des Debuggings. IntelliJ hat dazu sein Evaluate-Expression-Dialog.
14) Häufige Stolperfallen
Drei klassische Probleme beim Java-Debugging:
- „Source not found": du steppst in eine Library-Methode rein und siehst keinen Code, nur eine .class-Datei. Lösung: Maven/Gradle-Source-Jars aktivieren (in IntelliJ: Settings → Build → Maven → „Sources" angeklickt).
- Optimized-Out-Variablen: bei produktions-optimiertem Code (z.B. ProGuard, JIT) sind manche lokale Variablen „weg-optimiert" und im Debugger nicht sichtbar. Workaround: Debug-Build ohne Optimierungen.
- Breakpoint wird ignoriert: meist weil der Code in einer anderen JVM-Instanz läuft als die du debuggst. Z.B. zwei JVMs für Tomcat-Web vs. Worker-Background-Threads. Prüfe in der Run-Konfiguration wo du wirklich attacht bist.
Zusammenfassung
Java-Debugging über IntelliJ IDEA oder Eclipse; beide nutzen JVM's JDWP-Protokoll. Debug starten: Käfer-Button oder Shift+F9 (IntelliJ) bzw. F11 (Eclipse). Breakpoint: Klick links neben Zeile (roter Punkt). Inline-Werte zeigen Variablen-Werte direkt im Code. Variables-Panel mit allen lokalen + Watches. Frames-Panel = Call Stack. Step-Shortcuts: F8 Step Over, F7 Step Into, Shift+F8 Step Out, F9 Resume. Conditional Breakpoints: Rechtsklick + Java-Boolean. Logpoint: Suspend off + Log Expression = print ohne Code-Änderung. Exception-Breakpoints: stoppen automatisch bei NullPointer/etc. Evaluate Expression: Alt+F8 für Live-Java im Debug-Kontext. Helpful NPE ab Java 14: sagt welche Variable null war. Stream-Debugging: „Trace Current Stream Chain" für Stream-Pipelines. Remote-Debug: JDWP über Port 5005 für Server-JVMs. HotSwap: Code-Änderung ohne Neustart. Eclipse hat andere Shortcuts (F6 Step Over, F5 Into, F7 Out) aber gleiche Konzepte. Nächste Lektion: Python-Debugging.
