wtorek, kwietnia 11, 2017

Sztuczki tropiciela błędów - breakpoint na sterydach ;-)

Breakpoint to dobry przyjaciel tropiciela błędów.

Zatrzymuje wykonanie kodu (zwykle danego wątku) gdy napotka zaznaczony kawałek kodu, albo gdy poleci Exception, albo gdy zostanie zawołana jakaś metoda (strasznie wolne!).

Ale czasem chcielibyśmy mieć jakąś kontrolę nad tym zatrzymywaniem, bo np. nie chcemy by nam się kod zatrzymywał przy każdym wejściu do metody, ale tylko w pewnych warunkach.

Do tego mamy w InteliJ Idea i w Eclipse (a i w innych też) warunki aka conditiony dla breakpointów.
Zwykle są w stylu:

param==1
"specialCase".equals(text)

i podobne.
Czasem chcielibyśmy jednak czegoś lepszego ;-)

Ja ostatnio zapragnąłem by mi się zatrzymywał kod tylko gdy na stosie wywołań nie ma pewnej metody.
Chodziło o to, że już wiedziałem co przychodzi z tego miejsca, chciałem zobaczyć inne przypadki bez trzymania F9.

Najpierw spróbowałem użyć strumieni i lambd:

java.util.Arrays.stream(new Throwable().fillInStackTrace().stackTrace)
     .noneMatch(x -> "getWorker".equals(x.getMethodName()))

Czyli chciałem by warunek wystąpił gdy na StackTrace'ie nie będzie żadnej metody o nazwie getWorker.

Niestety IntelliJ poinformował mnie, że sorry Winnetou, ale lambd się nie da używać w warunkach breakpointa...

To stworzyłem sobie taką klasę ;-)

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

public class Terminator {

  public static boolean terminateIfNotCalledFrom(String... methodsNames) {
    Throwable t = new Throwable();
    t.fillInStackTrace();
    Set<String> methods = Arrays.stream(methodsNames).collect(Collectors.toSet());
    return Arrays.stream(t.getStackTrace()).noneMatch(x -> methods.contains(x.getMethodName()));
  }

  public static boolean terminateIfCalledFrom(String... methodsNames) {
    Throwable t = new Throwable();
    t.fillInStackTrace();
Set<String> methods = Arrays.stream(methodsNames).collect(Collectors.toSet()); return Arrays.stream(t.getStackTrace()).anyMatch(x -> methods.contains(x.getMethodName())); } }

Która to klasa dostarcza 2 metody statyczne, których możemy użyć w warunku:


I teraz kod zatrzymuje mi się tylko gdy osiągnęliśmy dany breakpoint nie przechodząc przez metody o nazwach, które przekazujemy w parametrze ;-)

Tropienie błędów staje się w takim przypadku dużo ciekawsze ;-)


Podobne postybeta
Sztuczki tropiciela błędów ;-)
Sztuczki tropiciela błędów, part 2 ;-)
Niecne wykorzystanie refleksji... czyli jak poszukać tekstu w drzewie obiektów? ;-)
Sztuczek Java'owy
Deklaratywnie czy imperatywnie... oto jest pytanie ;-)