Programiranje

Java Nasvet 124: Sledite korakom v Javi 1.4

Ne vem zate, ampak res rad vem, kje sem. Ker sem fant, sem nikoli izgubljen, včasih pa preprosto ne vem, kje sem. Nekateri kraji, na primer nakupovalna središča, imajo zemljevide s kazalniki "Tu si". Podobno tudi Java zdaj omogoča, da s pomočjo sistema ugotovimo svojo lokacijo. V tem nasvetu vam bom pokazal, kako dosledno in zanesljivo pridobivati ​​te informacije o lokaciji iz sistema.

Trdno sem prepričan, da bi moral izvajalni sistem zagotavljati dovolj metapodatkov o samem sistemu, da lahko programi sprejemajo boljše odločitve in dokončujejo naloge. Java že nekaj časa lahko samopregleduje in razmišlja o razredih, vendar do zdaj ni imela preproste sposobnosti preslikave izvajalne kode nazaj na njen položaj v datoteki izvorne kode. Rešitev pred Java 1.4 je bila ročno razčleniti sled skladenj izjem. Zdaj imamo z Javo 1.4 boljšo rešitev.

Želite odstraniti sled sklada?

Rešitev za zbiranje informacij o lokaciji pred Java 1.4 je bila ročna razčlenitev izjem printStackTrace () izhod. Tu je primer preproste sledove skladov:

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

Razstavljanje zgornje kode ni večji problem razčlenjevanja. Kaj pa tole?

java.lang.Throwable 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 boo.hoo.StackTrace.main (StackTrace.java:70) 

Uf. Kaj v resnici pomeni ves ta čuden goobley-guk in zakaj bi ga moral razčleniti? Očitno sistem že spremlja te informacije o lokaciji, saj je sposoben zgraditi te sledi skladov. Zakaj torej te informacije o lokaciji niso na voljo neposredno? No, z Javo 1.4 končno je.

Poleg tega ne pozabite, da ob JIT-jevih (ravno pravočasnih) prevajalnikih in dinamičnih, optimizirajočih prevajalnikih, kot je HotSpot Sun Microsystems, informacije o številki datotek in vrstic morda ne obstajajo. Cilj "uspešnost ali propad" je zagotovo moteč.

Java 1.4 Na pomoč!

Po prenašanju let pritožb je Sun Microsystems končno razširil java.lang.Hitljivo razred z getStackTrace () metoda. getStackTrace () vrne polje StackTraceElements, kjer je vsak StackTraceElement objekt zagotavlja sredstva za bolj ali manj neposredno pridobivanje informacij o lokaciji.

Če želite pridobiti te podatke o preslikavi, še vedno ustvarite Mečljivo primer na mestu zanimanja za vašo kodo:

 // ... javna statična void main (String [] args) {Throwable ex = new Throwable (); // ... 

Ta koda je postavljena na točko na začetku glavni ().

Seveda je neuporabno samo zbirati te informacije, ne da bi z njimi kaj naredili. Za ta namig bomo uporabili vsako osnovno metodo StackTraceElements za pridobivanje in prikaz vseh informacij, ki jih lahko.

Primer programa, StackTrace.java, prikazuje način pridobivanja informacij o lokaciji z več primeri. Za sestavljanje in zagon primera programa boste potrebovali paket SDK J2SE (Java 2 Platform, Standard Edition) 1.4.

Za ekstrakcijo in prikaz podatkov o preslikavi primer kode uporablja pomožno metodo, displayStackTraceInformation (), z naslednjim osnovnim idiomom uporabe:

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

The displayStackTraceInformation () koda je precej enostavna:

 javna statična logična displayStackTraceInformation (Throwable ex, boolean displayAll) {if (null == ex) {System.out.println ("Referenca sledi ničelnega sklada! Bailing ..."); vrni false; } System.out.println ("Niz skladno s printStackTrace (): \ n"); ex.printStackTrace (); System.out.println (""); StackTraceElement [] stackElements = ex.getStackTrace (); if (displayAll) {System.out.println ("The" + stackElements.length + "element" + ((stackElements.length == 1)? "": "s") + "sledov sklada: \ n" ); } else {System.out.println ("Vrhnji element sledi" + stackElements.length + "elementa: \ n"); } za (int lcv = 0; lcv <stackElements.length; lcv ++) {System.out.println ("Ime datoteke:" + stackElements [lcv] .getFileName ()); System.out.println ("Številka vrstice:" + stackElements [lcv] .getLineNumber ()); Niz className = stackElements [lcv] .getClassName (); Niz paketName = extractPackageName (className); Niz simpleClassName = extractSimpleClassName (className); System.out.println ("Ime paketa:" + ("" .equals (ime-paketa)? "[Privzeti paket]": ime-paketa)); System.out.println ("Polno ime razreda:" + ime-razreda); System.out.println ("Enostavno ime razreda:" + simpleClassName); System.out.println ("Nespremenjeno ime razreda:" + unmungeSimpleClassName (simpleClassName)); System.out.println ("Neposredno ime razreda:" + extractDirectClassName (simpleClassName)); System.out.println ("Ime metode:" + stackElements [lcv] .getMethodName ()); System.out.println ("Izvorna metoda ?:" + stackElements [lcv] .isNativeMethod ()); System.out.println ("toString ():" + stackElements [lcv] .toString ()); System.out.println (""); if (! displayAll) return true; } System.out.println (""); vrni res; } // Konec displayStackTraceInformation (). 

V bistvu pokličemo getStackTrace () o predanem Mečljivo, in nato skozi posameznika StackTraceElements, pridobivanje čim več informacij o kartiranju.

Bodite pozorni na bit craft displayAll parameter uvede. displayAll omogoča, da se klicno mesto odloči, ali bo prikazalo vse StackTraceElementali samo zgornji element sklada. Primer programa uporablja displayAll parameter, da izhod omeji na razumno vrednost.

Večina informacij o sledovih skladov je neposredno uporabnih. Na primer StackTraceElement.getMethodName () vrne niz, ki vsebuje ime metode, medtem ko StackTraceElement.getFileName () vrne niz z izvirnim imenom izvorne datoteke. Preberi StackTraceElement Javadoc za celoten seznam metod.

Imena razredov na pretek!

Kot ste verjetno opazili, displayStackTraceInformation () koda uporablja več dodatnih pomožnih metod za ločevanje vrednosti, ki jo vrne StackTraceElement.getClassName (). Te pomožne metode so potrebne, ker StackTraceElement.getClassName () vrne polno kvalificirano ime predavanja in StackTraceElement nima drugih metod za zagotavljanje osnovnih delov popolnoma kvalificiranega imena razreda. O vsaki dodatni pomožni metodi bomo izvedeli na podlagi različnih primerov uporabe displayStackTraceInformation ().

Privzeti in imenovani paketi

Glede na polno ime predavanja, extractPackageName () daje ime paketa, v katerem je razred:

 javni statični niz extractPackageName (String fullClassName) ("" .equals (fullClassName))) return ""; int lastDot = fullClassName.lastIndexOf ('.'); if (0> = lastDot) vrne ""; vrni fullClassName.substring (0, lastDot); 

V bistvu, extractPackageName izvleče vse pred zadnjo piko v popolnoma kvalificiranem imenu razreda. Predhodne informacije so samo ime paketa.

Opomba: Izkaz paketa lahko komentirate / razkomentirate na vrhu StackTrace.java raziskati razliko med zagonom programa v privzetem, neimenovanem paketu in zagonom v boo.hoo paket. Na primer, kadar se ne komentira, prikaz najvišjega elementa sklada za klic bar() iz foo () iz glavni () bi moral izgledati takole:

Ime datoteke: StackTrace.java Številka vrstice: 227 Ime paketa: boo.hoo Polno ime razreda: boo.hoo.StackTrace Preprosto ime razreda: StackTrace Nepremenjeno ime razreda: StackTrace Neposredno ime razreda: StackTrace Ime metode: bar Native method ?: false toString ( ): boo.hoo.StackTrace.bar (StackTrace.java:227) 

Če komentirate izjavo o paketu, mora biti zgornji element sklada podoben temu:

Ime datoteke: StackTrace.java Številka vrstice: 227 Ime paketa: [privzeti paket] Polno ime razreda: StackTrace Preprosto ime razreda: StackTrace Nepremenjeno ime razreda: StackTrace Neposredno ime razreda: StackTrace Ime metode: bar Native method ?: false toString (): StackTrace .bar (StackTrace.java:227) 

Ali so imena razredov lahko kdaj preprosta?

Naslednja pomožna metoda, ki jo uporabljamo, je extractSimpleClassName (). Kot boste videli, rezultati te metode niso nujno preprosti, vendar želim jasno ločiti to poenostavljeno ime razreda od popolnoma kvalificiranega imena razreda.

V bistvu, extractSimpleClassName () dopolnila extractPackageName ():

 javni statični niz extractSimpleClassName (String fullClassName) ("" .equals (fullClassName))) return ""; int lastDot = fullClassName.lastIndexOf ('.'); if (0> lastDot) vrne fullClassName; vrni fullClassName.substring (++ lastDot); 

Z drugimi besedami, extractSimpleClassName () vrne vse po zadnja pika (.) iz popolnoma kvalificiranega imena predavanja. Na primer od istega klica do bar() zgoraj vidimo, da je preprosto ime razreda pravično StackTrace, ali je koda del privzetega ali imenovanega paketa ali ne.

Bolj zanimive rezultate dobimo, ko pozornost usmerimo na ugnezdene razrede. V primeru programa sem ustvaril dve ravni ugnezdenih, imenovanih razredov (FirstNested in FirstNested.SecondNested) skupaj z dodatnim, anonimnim notranjim razredom (znotraj FirstNested.SecondNested).

Celotna ugnezdena uporaba se začne z:

 javni StackTrace (logična vrednost) {StackTrace.FirstNested ugnezdena = nova StackTrace.FirstNested (); } 

Upoštevajte, da je logični parameter (na) ne pomeni ničesar. Pravkar sem ga dodal, ker je treba razlikovati druge konstruktorje.

Tu so ugnezdeni razredi:

 javni razred FirstNested {public FirstNested () {StackTrace.displayStackTraceInformation (new Throwable ()); StackTrace.FirstNested.SecondNested yan = novo StackTrace.FirstNested.SecondNested (); System.out.println ("Odmetavanje iz notranjosti svinjine ():"); yan.hogwash (); } javni razred 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 ()); }}; // Konec razreda anonimnih članov. whacked.whack (); } // Konec svinjarije (). } // Konec razreda članov FirstNested.SecondNexted. } // Konec razreda prvega člana. 

Najvišji element sklada za SecondNestedkonstruktor je videti takole:

Ime datoteke: StackTrace.java Številka vrstice: 267 Ime paketa: boo.hoo Polno ime razreda: boo.hoo.StackTrace $ FirstNested $ SecondNested Preprosto ime razreda: StackTrace $ FirstNested $ SecondNested Nepremenjeno ime razreda: StackTrace.FirstNested.SecondNested Direct ime razreda: Ime SecondNested metode: Native method ?: false toString (): boo.hoo.StackTrace $ FirstNested $ SecondNested. (StackTrace.java:267) 

Vidite lahko, da preprosto ime razreda v tem primeru ni tako preprosto. Vgnezdene razrede ločimo od ugnezdenih razredov višje ravni in od razreda najvišje ravni z uporabo znaka za dolar ($). Torej, tehnično je "preprosto" ime drugega ugnezdenega razreda StackTrace $ FirstNested $ SecondNested.

Priskrbel sem unmungeSimpleClassName () metoda zamenjave dolarskih znakov z obdobji popolnosti.

Ker sem trmast, sem še vedno hotel dobiti resnično preprosto ime razreda, zato sem ustvaril extractDirectClassName ():

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