NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Lekce 4 - IntelliJ IDEA - Debugging

V minulé lekci, IntelliJ IDEA - Scopes, Live Templates, Databáze, Pluginy, jsme si ukázali scopes, live templates, SQL Explorer a pluginy.

V dnešním Java tutoriálu si vysvětlíme, jak debugovat Java aplikace za pomocí IDE IntelliJ IDEA. Vše si vyzkoušíme na jednoduchém příkladu.

Debugging

Debugging je proces odstranění chyb v programu, které obvykle nejsou na první pohled vidět. Někdy se o něm hovoří také jako o "ladění" programu.

Proč a kdy debugovat?

Chyby v programu se většinou projevují tím, že je v nějaké proměnné nesprávná hodnota, která pak zapříčiní nefunkčnost programu. Určitě jste se již dostali do situace, když váš program nefungoval správně. Možná jste prováděli nějaké zdlouhavé kontrolní výpisy různých proměnných, abyste zjistili, kde je ještě vše správně a kde jsou již nesprávné hodnoty.

Chybu lze ovšem obvykle najít mnohem snadněji pomocí debugování. Program obvykle spustíme ve speciálním režimu, kde máme dovoleny určité "cheaty", jako např. program pozastavovat a nahlížet do obsahu proměnných. Právě to se dnes naučíme.

Není ovšem pravda, že debugger používáme jen když program nefunguje! Naopak, používáme jej co nejvíce to jde a to i třeba pro kontrolu správnosti na kritických místech.

Příklad - Krokování cyklu

Mějme jednoduchý cyklus, ve kterém budeme vypisovat čísla od 0 do 9:

public static void main(String[] args) {
    for (int i = 0; i < 10; i++) {
        System.out.println("Číslo: " + i);
    }
}

Jak si můžete zkusit, program funguje korektně. Přesto si jej zkusíme oddebugovat, než se pustíme na nefunkční kód.

Breakpointy

Breakpoint je základní stavební kámen při debugování. Je to "bod" označující řádek, na kterém se program zastaví. Nám, jako programátorům, se v tu chvíli zobrazí kompletní kontext programu, tedy např. co je v tu chvíli kde uloženo. Protože program stojí, můžeme si vše snadno zkontrolovat.

Přidání breakpointu

Nyní se naučíme vkládat breakpointy a zastavovat na nich program. V IntelliJ se breakpoint na daný řádek vkládá kliknutím do prostoru vlevo vedle čísla řádku. Breakpoint pak poznáme podle červeného kolečka. Vložme tedy breakpoint na řádek, kde se vypisuje číslo do konzole:

Breakpoint - IntelliJ IDEA / NetBeans / Eclipse - Pokročilá práce

Debug režim

Breakpoint máme přidaný. Když však program nyní spustíme, nic zvláštního se nestane. Aby se program opravdu zastavil, je potřeba ho spustit ve speciálním debugovacím režimu. K tomu slouží speciální tlačítko vedle tlačítka "Play":

Tlačítko pro debug - IntelliJ IDEA / NetBeans / Eclipse - Pokročilá práce

Klikneme na tlačítko pro debug. Program se spustí a až narazí na náš breakpoint, tak se zastaví:

Debuggovací okno - IntelliJ IDEA / NetBeans / Eclipse - Pokročilá práce

Červený puntík označující breakpoint se změnil na zelený. To znamená, že breakpoint je dosažitelný.

Záložka Debug

Otevřela se nová záložka nazvaná Debug, která obsahuje velké množství informací. Pojďme si popsat, co vidíme:

  • část ohraničená na obrázku výše zeleně obsahuje seznam všech aktuálně viditelných proměnných a jejich hodnoty; hodnoty lze změnit,
  • oranžově ohraničená část obsahuje zásobník volání všech funkcí, které se zavolaly před breakpointem

Všimněte si, že IntelliJ se snaží vkládat hodnoty proměnných přímo do editoru. V našem případě vidíme přímo výpis hodnot pole.

Dále jsou na obrázku zvýrazněny dvě části ohraničeny červeně.

Ovládání programu a breakpointů

V levé ohraničené červené části se nachází tlačítka pro kontrolu ovládání programu a breakpointů:

  1. rerun 'Main' Ctrl+F5 - Ukončí aktuální program a znovu ho spustí,
  2. modify run configuration - Zobrazí nastavení pro debug,
  3. resume program F9 - Uvolní program z breakpointu a nechá program běžet a případně se zastaví o další breakpoint,
  4. pause program - Pozastaví vykonávání vybraného vlákna - funguje podobně jako breakpoint, pouze se nezobrazí žádné proměnné,
  5. stop 'Main' Ctrl+F2 - Ukončí aktuální program,
  6. view breakpoints Ctrl+Shift+F8 - Zobrazí seznam všech breakpointů,
  7. mute breakpoints - Potlačí všechny breakpointy; Když program narazí na breakpoint v debug modu, breakpoint bude ignorován.
Krokování

Ve druhé červeně ohraničené části se nachází tlačítka pro krokování programu. Pomocí krokování můžeme nechat program pokročit na další řádek a zas se zastavit:

  1. step over F8 (krok přes) - Provedeme další krok přes danou řádku s breakpointem, na které program aktuálně stojí. Pokud se na řádce volá funkce, necháme ji jen vykonat a pak přejdeme na další řádek
  2. step into F7 (krok do) - Provedeme další krok "do" dané řádky. Dělá to samé co Step over až na rozdíl, že pokud se na řádku volá funkce, přejdeme na první řádek ve funkci
  3. force step into Alt + Shift + F7 (vynucený krok do) - Vynutí přechod do funkce na řádku i v případě, že se nejedná o naši metodu.
  4. step out Shift + F8 (krok ven) - Pomocí kroku ven vystoupíme z aktuálně prováděné funkce

My se nacházíme v cyklu, kde pouze vypisujeme jednu hodnotu. Když se podíváme do výpisu konzole, zatím neuvidíme žádný výpis (kromě možných hlášek od IDE).

Stiskem tlačítka krok přes se vypíše do konzole první číslo a my se v programu dostaneme na řádek s for cyklem. Když tlačítko stiskneme znovu, uvidíme, že se inkrementovala pomocná proměnná i z hodnoty 0 na hodnotu 1. Tímto způsobem si můžeme odkrokovat celý cyklus:

Debugging - IntelliJ IDEA / NetBeans / Eclipse - Pokročilá práce

Příklad - Debugování programu

Nakonec si dáme příklad opravdu k procvičení debugování. Máme dva vnořené cykly, které by měly vypsat malou násobilku:

public static void main(String[] args) {
    for (int j = 1; j <= 10; j++) {
        for (int i = 1; j <= 10; j++) {
            System.out.print(i * j + "\t");
        }
        System.out.println();
    }
}

Výsledek by měl vypadat takto:

Konzolová aplikace
1   2   3   4   5   6   7   8   9   10
2   4   6   8   10  12  14  16  18  20
3   6   9   12  15  18  21  24  27  30
4   8   12  16  20  24  28  32  36  40
5   10  15  20  25  30  35  40  45  50
6   12  18  24  30  36  42  48  54  60
7   14  21  28  35  42  49  56  63  70
8   16  24  32  40  48  56  64  72  80
9   18  27  36  45  54  63  72  81  90
10  20  30  40  50  60  70  80  90  100

Problém ale je, že se vypíší pouze čísla od 1 do 10:

Konzolová aplikace
1   2   3   4   5   6   7   8   9   10

Chybu budeme samozřejmě chtít najít a opravit za pomoci breakpointů a krokování. I když uvidíte chybu na první pohled, neotálejte a také si to odkrokujte! Ve složitějších aplikacích chyba snadno vidět nebude a debugování bude nutné.

Postup řešení

Očekáváme, že vnější cyklus se provede 10x, zatímco vnitřní cyklus se provede celkem 100x. Vložíme breakpoint na řádek s vnějším for cyklem:

for (int j = 1; j <= 10; j++) {

A spustíme program v debug režimu. Bude nás zajímat, jak se proměnné i a j zvyšují. Tlačítkem krok do budeme postupně procházet přes oba cykly a pozorovat proměnné i a j. Vnější cyklus pracuje s proměnnou j, která by se měla změnit pouze 10x. Vnitřní cyklus pracuje s hodnotou i, která by se měla při každé změně j upravit 10x.

Postupným krokováním však zjistíme, že vnitřní cyklus inkrementuje proměnnou j namísto i. Ve vnitřním cyklu upravíme j++ na i++ a program opět spustíme v debug režimu:

for (int i = 1; j <= 10; i++)

Krokujeme opět tlačítkem krok do. Sledujeme proměnnou i. Po čase začne nabývat neočekávaných hodnot, které se neustále o jedničku zvyšují. Pokud teď necháte program běžet, začne se vám počítač sekat. To je z důvodu, že ve vnitřním cyklu je podmínka, která nikdy nebude splněna.

V cyklu for (int i = 1; j <= 10; i++) máme proměnnou i, kterou už správně inkrementujeme, ale podmínka je špatná. Proměnná i se inkrementuje, dokud platí j <= 10. Tato podmínka nikdy nebude splněna, protože proměnná j se modifikuje pouze ve vnějším cyklu. Opravíme podmínku vnitřního cyklu z j <= 10 na i <= 10 a program už spustíme bez breakpointů:

public static void main(String[] args) {
    for (int j = 1; j <= 10; j++) {
        for (int i = 1; i <= 10; i++) {
            System.out.print(i * j + "\t");
        }
        System.out.println();
    }
}

Výsledkem již je očekávaná malá násobilka:

Konzolová aplikace
1   2   3   4   5   6   7   8   9   10
2   4   6   8   10  12  14  16  18  20
3   6   9   12  15  18  21  24  27  30
4   8   12  16  20  24  28  32  36  40
5   10  15  20  25  30  35  40  45  50
6   12  18  24  30  36  42  48  54  60
7   14  21  28  35  42  49  56  63  70
8   16  24  32  40  48  56  64  72  80
9   18  27  36  45  54  63  72  81  90
10  20  30  40  50  60  70  80  90  100

V další lekci, IntelliJ IDEA - Pokročilý debugging, si rozšíříme znalosti debugování v IntelliJ IDEA.


 

Předchozí článek
IntelliJ IDEA - Scopes, Live Templates, Databáze, Pluginy
Všechny články v sekci
IntelliJ IDEA / NetBeans / Eclipse - Pokročilá práce
Přeskočit článek
(nedoporučujeme)
IntelliJ IDEA - Pokročilý debugging
Článek pro vás napsal Petr Štechmüller
Avatar
Uživatelské hodnocení:
28 hlasů
Autor se věnuje primárně programování v Javě, ale nebojí se ani webových technologií.
Aktivity