Programovanie

Java Tip 124: Sledujte svoje kroky v prostredí Java 1.4

Neviem ako vy, ale ja by som naozaj rád vedel, kde som. Keď som chlap, tak som nikdy stratený, ale niekedy jednoducho neviem, kde som. Niektoré miesta, napríklad obchodné centrá, majú mapy s indikátormi „Ste tu“. Podobne nám teraz Java umožňuje pomocou systému zistiť polohu. V tomto tipe vám ukážem, ako dôsledne a spoľahlivo extrahovať tieto informácie o polohe zo systému.

Pevne verím, že runtime systém by mal poskytovať dostatok metadát o samotnom systéme, aby programy mohli robiť lepšie rozhodnutia a plniť úlohy. Java bola už istý čas schopná prehliadať a premýšľať o triedach, ale doteraz jej chýbala jednoduchá schopnosť mapovať runtime kód späť na svoje miesto v súbore zdrojového kódu. Riešením pred Java 1.4 bolo manuálne analyzovať trasovanie zásobníka výnimky. Teraz s Java 1.4 máme lepšie riešenie.

Oddeliť stopu od zásobníka?

Riešením starším ako Java 1.4 bolo zhromažďovanie informácií o polohe spočívajúce v manuálnej analýze výnimky printStackTrace () výkon. Tu je príklad jednoduchého trasovania zásobníka:

java.lang.Throwable at boo.hoo.StackTrace.bar (StackTrace.java:223) at boo.hoo.StackTrace.foo (StackTrace.java:218) at boo.hoo.StackTrace.main (StackTrace.java:54) 

Oddelenie vyššie uvedeného kódu nie je veľkým problémom pri analýze. Ale čo takto?

java.lang. Hoditeľné na boo.hoo.StackTrace $ FirstNested $ SecondNested. (StackTrace.java:267) na boo.hoo.StackTrace $ FirstNested. (StackTrace.java:256) na boo.hoo.StackTrace. (StackTrace.java) : 246) na adrese boo.hoo.StackTrace.main (StackTrace.java:70) 

Uf. Čo vlastne znamená ten čudný goobley-guk a prečo by som to preboha musel analyzovať? Je zrejmé, že systém už sleduje tieto informácie o polohe, pretože je schopný tieto stopy zásobníka vytvoriť. Prečo teda nie sú tieto informácie o mieste k dispozícii priamo? No, s Java 1.4 to konečne je.

Okrem toho nezabúdajte, že tvárou v tvár kompilátorom JIT (just-in-time) a dynamickým optimalizujúcim prekladačom, ako je HotSpot spoločnosti Sun Microsystems, informácie o súbore a riadku nemusia existovať. Cieľ „predstavenia alebo poprsia“ môže byť určite nepríjemný.

Java 1.4 hoditeľný na záchranu!

Po tolerovaní rokov sťažností spoločnosť Sun Microsystems konečne rozšírila java.lang. Hoditeľné trieda s getStackTrace () metóda. getStackTrace () vráti pole StackTraceElements, kde každý StackTraceElement objekt poskytuje prostriedky na viac-menej priamu extrakciu informácií o polohe.

Ak chcete získať tieto mapové informácie, stále vytvoríte a Hoditeľné napríklad v bode záujmu vo vašom kóde:

 // ... public static void main (String [] args) {Throwable ex = new Throwable (); // ... 

Tento kód umiestňuje tento bod na začiatok hlavný().

Samozrejme, je zbytočné iba zhromažďovať tieto informácie bez toho, aby ste s nimi niečo robili. Pre tento tip použijeme každú základnú metódu StackTraceElements na získanie a zobrazenie všetkých informácií, ktoré môžeme.

Ukážkový program, StackTrace.java, ukazuje, ako extrahovať informácie o polohe pomocou niekoľkých príkladov. Na zostavenie a spustenie ukážkového programu budete potrebovať sadu SDK J2SE (Java 2 Platform, Standard Edition) 1.4 SDK.

Na extrahovanie a zobrazenie mapovacích informácií používa vzorový kód pomocnú metódu, displayStackTraceInformation ()s nasledujúcim základným spôsobom používania:

 // ... public void crashAndBurnout () {// ... displayStackTraceInformation (new Throwable ()); // ...} // ... 

The displayStackTraceInformation () kód je celkom jednoduchý:

 public static boolean displayStackTraceInformation (Throwable ex, boolean displayAll) {if (null == ex) {System.out.println ("Odkaz na stopu nulového zásobníka! Kaucia ..."); návrat nepravdivý; } System.out.println ("Zásobník podľa printStackTrace (): \ n"); napr. printStackTrace (); System.out.println (""); StackTraceElement [] stackElements = ex.getStackTrace (); if (displayAll) {System.out.println ("The" + stackElements.length + "element" + ((stackElements.length == 1)? "": "s") + "trasovania zásobníka: \ n" ); } else {System.out.println ("Najvyšší prvok trasovania zásobníka prvkov" + stackElements.length + ": \ n"); } for (int lcv = 0; lcv <stackElements.length; lcv ++) {System.out.println ("Filename:" + stackElements [lcv] .getFileName ()); System.out.println ("Číslo riadku:" + stackElements [lcv] .getLineNumber ()); Reťazec className = stackElements [lcv] .getClassName (); Reťazec packageName = extractPackageName (className); Reťazec simpleClassName = extractSimpleClassName (className); System.out.println ("Názov balíka:" + ("" .equals (názov_balíka)? "[Predvolený balík]": názov_balíka)); System.out.println ("Celý názov triedy:" + názov triedy); System.out.println ("Jednoduchý názov triedy:" + simpleClassName); System.out.println ("Unmunged názov triedy:" + unmungeSimpleClassName (simpleClassName)); System.out.println ("Priamy názov triedy:" + extractDirectClassName (simpleClassName)); System.out.println ("Názov metódy:" + stackElements [lcv] .getMethodName ()); System.out.println ("Natívna metóda ?:" + stackElements [lcv] .isNativeMethod ()); System.out.println ("toString ():" + stackElements [lcv] .toString ()); System.out.println (""); if (! displayAll) return true; } System.out.println (""); návrat pravdivý; } // Koniec displayStackTraceInformation (). 

V podstate voláme getStackTrace () na podaný Hoditeľné, a potom prechádzajte jednotlivcom StackTraceElements, ktorá vyťažila čo najviac mapovacích informácií.

Všimnite si kúsok cruft the displayAll parameter zavádza. displayAll umožňuje volajúcemu miestu rozhodnúť sa, či má alebo nemá zobrazovať všetky StackTraceElements alebo iba najvrchnejší prvok zásobníka. Ukážkový program používa displayAll parameter na obmedzenie produkcie na rozumné množstvo.

Väčšina informácií o sledovaní zásobníka je priamo užitočná. Napríklad StackTraceElement.getMethodName () vráti reťazec, ktorý obsahuje názov metódy, zatiaľ čo StackTraceElement.getFileName () vráti reťazec s pôvodným zdrojovým názvom súboru. Čítať StackTraceElement Javadoc pre kompletný zoznam metód.

Názvy tried veľa!

Ako ste si pravdepodobne všimli, displayStackTraceInformation () kód používa niekoľko ďalších pomocných metód na oddelenie hodnoty vrátenej parametrom StackTraceElement.getClassName (). Tieto pomocné metódy sú potrebné, pretože StackTraceElement.getClassName () vráti plne kvalifikovaný názov triedy a StackTraceElement nemá žiadne iné metódy na zabezpečenie základných častí plne kvalifikovaného názvu triedy. Dozvieme sa o každej ďalšej pomocnej metóde prepracovaním rôznych príkladov použitia displayStackTraceInformation ().

Predvolené a pomenované balíčky

Vzhľadom na úplný názov triedy, extractPackageName () dáva názov balíka, v ktorom je trieda umiestnená:

 public static String extractPackageName (String fullClassName) ("" .equals (fullClassName))) return ""; int lastDot = fullClassName.lastIndexOf ('.'); if (0> = lastDot) return ""; return fullClassName.substring (0, lastDot); 

V podstate extractPackageName extrahuje všetko pred poslednou bodkou v úplnom názve triedy. Predchádzajúcou informáciou je iba názov balíka.

Poznámka: Výpis balíka môžete komentovať / odkomentovať v hornej časti stránky StackTrace.java preskúmať rozdiel medzi spustením ukážkového programu v predvolenom nepomenovanom balíku a spustením v programe boo.hoo balíček. Napríklad, ak nie je uvedené, zobrazenie najvyššieho prvku zásobníka pre volanie bar () od foo () od hlavný() by mal vyzerať takto:

Názov súboru: StackTrace.java Číslo riadku: 227 Názov balíka: boo.hoo Celý názov triedy: boo.hoo.StackTrace Jednoduchý názov triedy: StackTrace Názov nezamenenej triedy: StackTrace Priamy názov triedy: StackTrace Názov metódy: bar Natívna metóda ?: false toString ( ): boo.hoo.StackTrace.bar (StackTrace.java:227) 

Prípadne, ak komentujete vyhlásenie o balíku, potom by mal vyššie uvedený prvok zásobníka vyzerať takto:

Názov súboru: StackTrace.java Číslo riadku: 227 Názov balíka: [predvolený balík] Celý názov triedy: StackTrace Jednoduchý názov triedy: StackTrace Názov nezamenenej triedy: StackTrace Priamy názov triedy: StackTrace Názov metódy: bar Nativní metóda ?: false toString (): StackTrace .bar (StackTrace.java:227) 

Môžu byť názvy tried niekedy jednoduché?

Ďalšia pomocná metóda, ktorú používame, je extractSimpleClassName (). Ako uvidíte, výsledky tejto metódy nie sú nevyhnutne jednoduché, ale chcem jasne odlíšiť tento zjednodušený názov triedy od plne kvalifikovaného názvu triedy.

V podstate extractSimpleClassName () doplnkov extractPackageName ():

 public static String extractSimpleClassName (String fullClassName) ("" .equals (fullClassName))) return ""; int lastDot = fullClassName.lastIndexOf ('.'); if (0> lastDot) return fullClassName; návrat fullClassName.substring (++ lastDot); 

Inými slovami, extractSimpleClassName () vráti všetko po posledná bodka (.) z plne kvalifikovaného názvu triedy. Napríklad z rovnakého hovoru na bar () vyššie vidíme, že jednoduchý názov triedy je len StackTrace, či je alebo nie je kód súčasťou predvoleného balíka alebo pomenovaného balíka.

Zaujímavejšie výsledky dosiahneme, keď obrátime pozornosť na vnorené triedy. V ukážkovom programe som vytvoril dve úrovne vnorených pomenovaných tried (FirstNested a FirstNested.SecondNested) spolu s ďalšou anonymnou vnútornou triedou (vo vnútri FirstNested.SecondNested).

Celé vnorené použitie začína:

 public StackTrace (boolean na) {StackTrace.FirstNested vnorené = nové StackTrace.FirstNested (); } 

Všimnite si, že boolovský parameter (na) nič neznamená. Práve som to pridal, pretože treba rozlišovať ostatných konštruktérov.

Tu sú vnorené triedy:

 verejná trieda FirstNested {public FirstNested () {StackTrace.displayStackTraceInformation (new Throwable ()); StackTrace.FirstNested.SecondNested yan = nový StackTrace.FirstNested.SecondNested (); System.out.println ("Dumping from inside hogwash ():"); yan.hogwash (); } verejná trieda SecondNested {public SecondNested () {StackTrace.displayStackTraceInformation (new Throwable ()); } public void hogwash () {StackTrace.displayStackTraceInformation (new Throwable ()); Whackable whacked = new Whackable () {public void whack () {StackTrace.displayStackTraceInformation (new Throwable ()); }}; // Koniec triedy anonymných členov. praštil.prásk (); } // Koniec hogwash (). } // Koniec triedy člena FirstNested.SecondNexted. } // Koniec triedy člena FirstNested. 

Najvyšší prvok zásobníka pre Druhý vnorenýKonštruktér vyzerá takto:

Názov súboru: StackTrace.java Číslo riadku: 267 Názov balíka: boo.hoo Celý názov triedy: boo.hoo.StackTrace $ FirstNested $ SecondNested Jednoduchý názov triedy: StackTrace $ FirstNested $ SecondNested Názov nemenovanej triedy: StackTrace.FirstNested.SecondNested Priamy názov triedy: Názov metódy SecondNested: Natívna metóda ?: false toString (): boo.hoo.StackTrace $ FirstNested $ SecondNested. (StackTrace.java:267) 

Vidíte, že jednoduchý názov triedy nie je v tomto prípade taký jednoduchý. Vnorené triedy sa odlišujú od vnorených tried vyššej úrovne a od triedy najvyššej úrovne pomocou znaku dolára ($). Technicky teda „jednoduchý“ názov druhej vnorenej triedy je StackTrace $ FirstNested $ SecondNested.

Poskytla som unmungeSimpleClassName () metóda nahradenia znakov dolára bodkami pre úplnosť.

Keďže som tvrdohlavý, stále som chcel získať skutočne jednoduchý názov triedy, a tak som vytvoril extractDirectClassName ():

$config[zx-auto] not found$config[zx-overlay] not found