Trucchi per il debug di IntelliJ

1. Panoramica

In questo tutorial, esamineremo alcune funzionalità avanzate di debug di IntelliJ .

Si presume che le basi del debug siano già note (come avviare il debug, Step Into , Step Over , ecc.). In caso contrario, fare riferimento a questo articolo per maggiori dettagli in merito.

2. Passaggio intelligente

Ci sono situazioni in cui più metodi vengono chiamati su una singola riga di codice sorgente, come doJob (getArg1 (), getArg2 ()) . Se chiamiamo Step Into action (F7), il debugger entra nei metodi nell'ordine utilizzato dalla JVM per la valutazione: getArg1 - getArg2 - doJob .

Tuttavia, potremmo voler saltare tutte le chiamate intermedie e procedere direttamente al metodo di destinazione . L' azione Smart Step Into consente di farlo.

È associato a Shift + F7 per impostazione predefinita e ha questo aspetto quando viene richiamato:

Ora possiamo scegliere il metodo di destinazione per procedere. Si noti inoltre che IntelliJ mette sempre il metodo più esterno in cima all'elenco. Ciò significa che possiamo accedervi rapidamente premendo Maiusc + F7 | Entra .

3. Drop Frame

Potremmo renderci conto che alcune elaborazioni a cui siamo interessati sono già avvenute (ad esempio il calcolo dell'argomento del metodo corrente). In questo caso, è possibile eliminare gli stack frame JVM correnti per rielaborarli.

Considera la seguente situazione:

Supponiamo di essere interessati al debug dell'elaborazione getArg1 , quindi rilasciamo il frame corrente ( metodo doJob ):

Ora siamo nel metodo precedente :

Tuttavia, gli argomenti della chiamata sono già calcolati a questo punto, quindi dobbiamo eliminare anche il frame corrente :

Ora possiamo rieseguire l'elaborazione chiamando Step Into .

4. Punti di interruzione del campo

A volte i campi non privati ​​vengono modificati da altre classi, non tramite setter ma direttamente (questo è il caso delle librerie di terze parti in cui non controlliamo il codice sorgente).

In tali situazioni, potrebbe essere difficile capire quando la modifica è stata eseguita. IntelliJ consente di creare punti di interruzione a livello di campo per tenerne traccia.

Sono impostati come al solito: fai clic con il pulsante sinistro del mouse sul margine sinistro dell'editor sulla riga del campo. Dopodiché, è possibile aprire le proprietà del punto di interruzione (fare clic con il pulsante destro del mouse sul segno del punto di interruzione) e configurare se siamo interessati alle letture, alle scritture o a entrambe del campo :

5. Registrazione dei punti di interruzione

A volte sappiamo che c'è una condizione di competizione nell'applicazione ma non sappiamo dove sia esattamente. Potrebbe essere una sfida inchiodarlo, specialmente mentre si lavora con un nuovo codice.

Possiamo aggiungere istruzioni di debug ai sorgenti del nostro programma. Tuttavia, non esiste tale capacità per le librerie di terze parti.

L'IDE può essere d'aiuto qui: consente di impostare punti di interruzione che non bloccano l'esecuzione una volta raggiunti, ma producono invece istruzioni di registrazione .

Considera il seguente esempio:

public static void main(String[] args) { ThreadLocalRandom random = ThreadLocalRandom.current(); int count = 0; for (int i = 0; i < 5; i++) { if (isInterested(random.nextInt(10))) { count++; } } System.out.printf("Found %d interested values%n", count); } private static boolean isInterested(int i) { return i % 2 == 0; }

Supponiamo che siamo interessati a registrare i parametri della chiamata isInterested effettivi .

Creiamo un punto di interruzione non bloccante nel metodo di destinazione ( Maiusc + clic sinistro sul margine sinistro dell'editor a sinistra). Dopodiché apriamo le sue proprietà (clic destro sul punto di interruzione) e definiamo l'espressione di destinazione da registrare :

Quando si esegue l'applicazione (si noti che è ancora necessario utilizzare la modalità Debug), vedremo l'output:

isInterested(1) isInterested(4) isInterested(3) isInterested(1) isInterested(6) Found 2 interested values

6. Punti di interruzione condizionali

Potremmo avere una situazione in cui un particolare metodo viene chiamato da più thread contemporaneamente e dobbiamo eseguire il debug dell'elaborazione solo per un particolare argomento.

IntelliJ consente di creare punti di interruzione che sospendono l'esecuzione solo se viene soddisfatta una condizione definita dall'utente .

Ecco un esempio che utilizza il codice sorgente sopra:

Ora il debugger si fermerà sul punto di interruzione solo se l'argomento specificato è maggiore di 3.

7. Marchi oggetto

Questa è la funzione IntelliJ più potente e meno conosciuta. In sostanza è abbastanza semplice: possiamo allegare etichette personalizzate agli oggetti JVM .

Diamo un'occhiata a un'applicazione che useremo per dimostrarli:

public class Test { public static void main(String[] args) { Collection tasks = Arrays.asList(new Task(), new Task()); tasks.forEach(task -> new Thread(task).start()); } private static void mayBeAdd(Collection holder) { int i = ThreadLocalRandom.current().nextInt(10); if (i % 3 == 0) { holder.add(i); } } private static class Task implements Runnable { private final Collection holder = new ArrayList(); @Override public void run() { for (int i = 0; i < 20; i++) { mayBeAdd(holder); } } } }

7.1. Creazione di marchi

Un oggetto può essere contrassegnato quando un'applicazione viene arrestata su un punto di interruzione e la destinazione è raggiungibile dagli stack frame.

Selezionalo, premi F11 ( azione Mark Object ) e definisci il nome del target:

7.2. Visualizza marchi

Ora possiamo vedere le nostre etichette di oggetti personalizzate anche in altre parti dell'applicazione:

La cosa interessante è che anche se un oggetto contrassegnato non è al momento raggiungibile dagli stack frame, possiamo comunque vederne lo stato : apri una finestra di dialogo Valuta espressione o aggiungi un nuovo orologio e inizia a digitare il nome del contrassegno.

IntelliJ offre di completarlo con il suffisso _DebugLabel :

Quando lo valutiamo, viene mostrato lo stato dell'oggetto target:

7.3. Contrassegna come condizioni

È anche possibile utilizzare i segni in condizioni di punto di interruzione:

8. Conclusione

Abbiamo verificato una serie di tecniche che aumentano notevolmente la produttività durante il debug di un'applicazione multi-thread.

Questo di solito è un compito impegnativo e non possiamo sottovalutare l'importanza dell'aiuto degli utensili qui.