Besseres 'printf'-Debugging

Andere Sprachen: English Español Français 日本語 한국어 Português 中文

Eine der häufigsten Debugging-Techniken, das ‘printf’-Debugging, ist besonders beliebt, weil die meisten Menschen es intuitiv lernen, wenn sie ihre ersten Programme schreiben.

‘printf’-Debugging ist sehr zugänglich, da man keine speziellen Werkzeuge dafür benötigt. Wenn man sich mit seinen ersten Bugs auseinandersetzt, noch bevor man weiß, was ein Debugger ist, kommt es einem natürlich in den Sinn, das Programm Variablen Schritt für Schritt ausgeben zu lassen, damit man die Ausführung in der Konsole verfolgen kann.

Obwohl es eine der grundlegendsten Debugging-Techniken ist, nutzen auch erfahrene Entwickler sie häufig. Sie kann bei der Untersuchung jeder Art von Problemen helfen, wie suboptimale Routinen, inkonsistenter Zustand, Multithreading-Probleme und mehr.

Wie bereits erwähnt, erfordert diese Technik keine speziellen Werkzeuge wie eine IDE. Wenn man jedoch eine verwendet, kann sie die Effizienz beim Protokollieren des Programmzustands noch weiter steigern.

Info icon

Dieser Artikel zeigt Funktionen von IntelliJ IDEA. Ähnliche Funktionen können in anderen IDEs vorhanden sein oder auch nicht. Wenn du ein anderes Werkzeug verwendest, solltest du dessen Dokumentation konsultieren, um zu sehen, ob diese Funktionen dort ebenfalls vorhanden sind.

Live Templates

IntelliJ IDEA bietet Live Templates für die gängigsten Debug-Logging-Muster. Um ein Live Template für Debug-Logging zu verwenden, gib die entsprechende Abkürzung ein und drücke Tab. IntelliJ IDEA generiert die Print-Anweisung und fügt sie an der Cursorposition ein.

Schauen wir uns ein paar Beispiele an.

Methodenparameter protokollieren


public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

    // type 'soutp' here, then press Tab

    return null;
}
public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

    System.out.println("in = " + in + ", mask = " + mask + ", newColor = " + newColor);

    return null;
}

Werte protokollieren


public static double coolMethod(double parameter) {
    double a = Math.random();
    double b = Math.random();

    // type 'soutv' here, press Tab, then select the value

    return a * b * parameter;
}
public static double coolMethod(double parameter) {
    double a = Math.random();
    double b = Math.random();

    System.out.println("b = " + b);

    return a * b * parameter;
}

Methodenaufrufe protokollieren


public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

    // type 'soutm' here, then press Tab

    return null;
}
public static BufferedImage recolor(BufferedImage in, BufferedImage mask, int newColor) {

    System.out.println("ImageUtils.recolor");

    return null;
}

Logging-Breakpoints

Einer der Nachteile beim Debugging mit Print-Anweisungen ist, dass sie den Aufwand der manuellen Verwaltung mit sich bringen. Man kann sie nicht schnell ein- und ausschalten, und man möchte sie definitiv nicht versehentlich committen und in der Produktion ausführen.

Aus diesem Grund würde ich empfehlen, Logging-Breakpoints zu verwenden, wenn du etwas zu Debugging-Zwecken protokollieren musst, da sie viel einfacher zu verwalten sind.

Der Protokollierungs-Breakpoint wird als gelber Kreis im Editor-Gutter angezeigt. Der Protokollierungs-Breakpoint wird als gelber Kreis im Editor-Gutter angezeigt.

Um einen Logging-Breakpoint zu setzen, halte Shift gedrückt und klicke dann in den Randbereich. Im Gegensatz zu einem regulären Breakpoint hält er die Programmausführung nicht an, sondern gibt stattdessen in die Konsole aus.

Standardmäßig ist es eine Meldung, die besagt, dass das Programm diese Zeile erreicht hat. Du kannst auch die Optionen neben dem Kontrollkästchen Evaluate and log in den Breakpoint-Einstellungen verwenden, wenn du lieber den aktuellen Stack-Trace oder das Ergebnis eines benutzerdefinierten Ausdrucks protokollieren möchtest.

Breakpoint-Einstellungen-Dialog mit einem benutzerdefinierten Ausdruck im Feld 'Auswerten und protokollieren' und der 'Anhalten'-Checkbox deaktiviert. Breakpoint-Einstellungen-Dialog mit einem benutzerdefinierten Ausdruck im Feld 'Auswerten und protokollieren' und der 'Anhalten'-Checkbox deaktiviert.
Info icon

Sei vorsichtig mit Logging-Ausdrücken. Das Auswerten von Ausdrücken, die Seiteneffekte verursachen, kann eine Quelle neuer Bugs oder unerwarteten Verhaltens sein. Außerdem können sie bei der Verwendung in häufig ausgeführtem Code dein Programm erheblich verlangsamen.

Wenn Logging-Breakpoints zahlreich werden, kannst du sie im Dialog Breakpoints (Run | View Breakpoints) verfolgen und verwalten:

Der Dialog "Breakpoints" zeigt alle Breakpoints innerhalb des Projekts nach Typ gruppiert an. Der Dialog "Breakpoints" zeigt alle Breakpoints innerhalb des Projekts nach Typ gruppiert an.

Du kannst sogar benutzerdefinierte Gruppen für sie erstellen:

Ein Rechtsklick auf einen Haltepunkt im Dialogfeld 'Haltepunkte' zeigt ein Kontextmenü mit der Option 'In Gruppe verschieben'. Ein Rechtsklick auf einen Haltepunkt im Dialogfeld 'Haltepunkte' zeigt ein Kontextmenü mit der Option 'In Gruppe verschieben'.

Dies hilft dir, deine Breakpoints zentral zu verwalten. Zum Beispiel kannst du eine Gruppe erstellen, die sich auf einen bestimmten Bug bezieht, und sie für später speichern. Wenn das Problem verschwindet, schalte sie einfach aus. Sollte das Problem wieder auftreten, musst du nicht alles von Grund auf neu erstellen. Du schaltest die Gruppe einfach wieder ein.

Häufige Ereignisse protokollieren

Bei Ereignissen, die während der Programmausführung häufig auftreten, kann das Protokollieren jedes einzelnen Ereignisses überflüssig sein. Dies überflutet nicht nur die Konsole mit Nachrichten, sondern viel Interaktion mit I/O kann auch die Debugging-Sitzung erheblich verlangsamen.

Konsole mit vielen ähnlichen Nachrichten, wie 'Maus bewegt zu 380, 183' Konsole mit vielen ähnlichen Nachrichten, wie 'Maus bewegt zu 380, 183'

Für solche Ereignisse kann es nützlich sein, die Funktion Pass count zu verwenden. Du kannst darauf im Dialog Breakpoints zugreifen.

Breakpoint-Einstellungen-Dialog mit dem Feld 'Überzählung' auf 100 gesetzt Breakpoint-Einstellungen-Dialog mit dem Feld 'Überzählung' auf 100 gesetzt

Nachdem du Pass count auf einen bestimmten Wert gesetzt hast, wird der entsprechende Breakpoint nur bei jedem n-ten Treffer ausgelöst, wodurch sichergestellt wird, dass das Logging nicht zum Ärgernis wird.

Zusammenfassung

Unabhängig davon, ob du Print-Anweisungen einfügst oder Logging-Breakpoints zum Debugging setzt, moderne Werkzeuge bieten Funktionen, um deine Debugging-Erfahrung zu verbessern. Mit diesem Beitrag wollte ich sicherstellen, dass du diese kleinen Tricks kennst, die den gesamten Prozess angenehmer gestalten.

Viel Erfolg beim Debugging!

all posts ->