Ślad stosu - 1

– Cześć! Dzisiaj opowiem Ci o tym, czym jest ślad stosu. Ale najpierw porozmawiajmy o tym, czym w ogóle jest stos.

– Wyobraź sobie stos kartek z poleceniami dla pewnego pracownika. Możesz dołożyć kolejne zadanie na górę stosu albo jakieś zdjąć – również z samej jego góry. To oznacza, że zadania nie będą wykonywane w kolejności, w jakiej zostały przydzielane. Zadanie, które położono na stosie jako ostatnie, będzie jednocześnie pierwszym, które zostanie wykonane. Taki sposób strukturyzowania elementów kolekcji tworzy stos.

Java posiada na to specjalną kolekcję – Stack. Jest to kolekcja, która posiada metody, które „dodają” i „pobierają („gettują”) elementy”. Jak zapewne się domyślasz, element, który został dodany jako ostatni, zostaje zdjęty jako pierwszy.

– Brzmi dość logicznie.

– Świetnie. A teraz wytłumaczę Ci, czym jest śledzenie stosu.

– Wyobraź sobie, że w programie Java metoda A wywołuje metodę B, która wywołuje metodę C, która z kolei wywołuje metodę D. Aby wyjść z metody B, musimy najpierw wyjść z metody C, ale aby to zrobić – musimy przedtem wyjść z metody D. To działa tak, jak stos.

– Dlaczego tak, jak stos?

– Ponieważ aby dostać się do jakiegoś zadania znajdującego się w środku stosu papierów, musisz najpierw wykonać wszystkie zadania, które leżą na nim.

– Teraz dostrzegam podobieństwo, ale nie jestem pewien, czy wszystko rozumiem.

– Spójrz. Stos jest zbiorem elementów. Jak kartki na stosie papierów. Aby wyciągnąć trzecią kartkę od góry, musisz najpierw wyciągnąć tę drugą, ale aby to zrobić, należy przedtem zdjąć ze stosu pierwszą. Może zawsze zdjąć lub położyć kartkę papieru, ale musisz zacząć od samej góry.

– Tak samo działają wywołania funkcji. Metoda A wywołuje metodę B, która wywołuje metodę C. Aby wyjść z A, musisz najpierw wyjść z B, ale aby to zrobić, należy przedtem wyjść z C.

– Zaczekaj. Jeśli dobrze zrozumiałem, cała idea sprowadza się do „zdejmij kartkę papieru, która została położona na stosie jako ostatnia” i „możesz wyjść tylko z tej metody, w którą wszedłeś jako ostatnią”. Zgadza się?

– Tak. Sekwencja wywołań funkcji jest nazywana także „stosem wywołań” bądź po prostu „stosem”. Ostatnia wrzucona funkcja jest zdejmowana jako pierwsza. Przeanalizujmy jakiś przykład.

Pobierz i wyświetl następujący stos wywołań:
public class ExceptionPrzyklad
{
  public static void main(String[] args)
  {
    method1();
  }

  public static void method1()
  {
    method2();
  }

  public static void method2()
  {
    method3();
  }

  public static void method3()
  {
     StackTraceElement[] sladStosuElementy = Thread.currentThread().getStackTrace();
    for (StackTraceElement element : sladStosuElementy)
    {
       System.out.println(element.getMethodName());
    }
  }
}
Wynik:
getStackTrace
method3
method2
method1
main

– OK. Wiem już wszystko o wywołaniach funkcji. Ale czym jest ten StackTraceElement?

– Maszyna Java przechowuje informacje dotyczące wywołań wszystkich funkcji. W tym celu używa specjalnej kolekcji – stosu (ang. stack). Kiedy jedna funkcja wywołuje inną, Maszyna Java dokłada do stosu nowy obiekt StackTraceElement. Kiedy funkcja kończy swoje działanie, element ten zostaje ze stosu usunięty. To oznacza, że stos zawsze przechowuje aktualne informacje o bieżącym stanie „stosu wywołań funkcji”.

– Każdy obiekt StackTraceElement zawiera informacje o wywołanej metodzie. Przede wszystkim, używając metody getMethodName, możesz uzyskać nazwę metody.

– W powyższym przykładzie wygląda to tak:

1) Pobieramy stos wywołań.

2) Aby przez niego przejść, używamy pętli for-each. Mam nadzieję, że pamiętasz jeszcze, czym ona jest.

3) Przekazujemy nazwy metod do System.out.

– Fascynujące! I wcale nie takie skomplikowane. Dziękuję, Raszi!