Programavimas

124 „Java“ patarimas: atsekite veiksmus atlikdami „Java 1.4“

Aš nežinau apie tave, bet man labai patinka žinoti, kur esu. Būdamas vaikinas, aš niekada pasimetęs, bet kartais tiesiog nežinau, kur esu. Kai kuriose vietose, pavyzdžiui, prekybos centruose, yra žemėlapiai su indikatoriais „Tu esi čia“. Panašiai „Java“ dabar leidžia mums išsiaiškinti savo vietą su sistemos pagalba. Šiame patarime aš jums parodysiu, kaip nuosekliai ir patikimai ištraukti šią vietos informaciją iš sistemos.

Aš tvirtai tikiu, kad vykdymo laiko sistema turėtų pateikti pakankamai metaduomenų apie pačią sistemą, kad programos galėtų priimti geresnius sprendimus ir atlikti užduotis. „Java“ jau kurį laiką galėjo domėtis klasėmis ir apmąstyti jas, tačiau iki šiol jai trūko paprastos galimybės susieti vykdymo laiko kodą į savo vietą šaltinio kodo faile. Ankstesnis nei „Java 1.4“ sprendimas buvo rankiniu būdu išanalizuoti išimties kamino pėdsakus. Dabar su „Java 1.4“ turime geresnį sprendimą.

Ištraukti kamino pėdsaką?

Ankstesnis nei „Java 1.4“ būdas rinkti informaciją apie vietą turėjo rankiniu būdu išanalizuoti išimtis „printStackTrace“ () produkcija. Štai paprasto kamino pėdsakų pavyzdys:

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

Minėto kodo ištraukimas nėra pagrindinė analizės problema. Bet kaip apie tai?

java.lang.Metamas adresu boo.hoo.StackTrace $ FirstNested $ SecondNested. (StackTrace.java:267) ne boo.hoo.StackTrace $ FirstNested. (StackTrace.java:256) adresu boo.hoo.StackTrace. (StackTrace.java : 246) adresu boo.hoo.StackTrace.main (StackTrace.java:70) 

Ugh. Ką iš tikrųjų reiškia visas tas keistasis gobliukas-gukas ir kodėl man žemėje turėčiau jį analizuoti? Akivaizdu, kad sistema jau stebi tą vietos informaciją, nes ji gali sukurti tuos kamino pėdsakus. Tai kodėl tos vietos informacijos negalima tiesiogiai gauti? Na, su „Java 1.4“ pagaliau yra.

Be to, nepamirškite, kad susidūrus su JIT (just-in-time) kompiliatoriais ir dinamiškais, optimizuojančiais kompiliatoriais, tokiais kaip „Sun Microsystems“ „HotSpot“, failų ir eilučių numerių informacijos gali nebūti. Tikslas „pasirodymas ar biustas“ tikrai gali varginti.

„Java 1.4“ mesti į pagalbą!

Po daugelio metų skundų „Sun Microsystems“ pagaliau išplėtė java.lang.Metamas klasė su „getStackTrace“ () metodas. „getStackTrace“ () grąžina masyvą „StackTraceElement“s, kur kiekvienas „StackTraceElement“ objektas suteikia priemones daugiau ar mažiau tiesiogiai išgauti informaciją apie vietą.

Norėdami gauti šią žemėlapių informaciją, vis tiek sukuriate Metamas egzempliorius jūsų kodą dominančioje vietoje:

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

Šis kodas žymi tašką, prasidedantį pagrindinis ().

Žinoma, nenaudinga tą informaciją tiesiog rinkti, nieko su ja nedarant. Šiam patarimui naudosime kiekvieną pagrindinį metodą „StackTraceElement“s išgauti ir parodyti visą informaciją, kurią galime.

Programos pavyzdys, „StackTrace.java“, parodyta, kaip išskleisti informaciją apie vietą su keliais pavyzdžiais. Norint sudaryti ir paleisti programos pavyzdį, jums reikės J2SE („Java 2 Platform“, „Standard Edition“) 1.4 SDK.

Norėdami išgauti ir rodyti žemėlapio informaciją, kodo pavyzdyje naudojamas pagalbinis metodas, displayStackTraceInformation (), su šia pagrindine vartojimo idėja:

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

displayStackTraceInformation () kodas yra gana paprastas:

 public static Boolean displayStackTraceInformation (Throwable ex, boolean displayAll) {if (null == ex) {System.out.println ("Nulinio kamino pėdsako nuoroda! Užstatas ..."); grąžinti klaidingą; } System.out.println ("Šūsnis pagal printStackTrace (): \ n"); ex.printStackTrace (); System.out.println (""); „StackTraceElement“ [] stackElements = ex.getStackTrace (); if (displayAll) {System.out.println ("" + stackElements.length + "elementas" + ((stackElements.length == 1)? "": "s") + "kamino pėdsako: \ n" ); } else {System.out.println ("Viršutinis elemento" + stackElements.length + "elemento kamino pėdsakas: \ n"); } for (int lcv = 0; lcv <stackElements.length; lcv ++) {System.out.println ("Failo pavadinimas:" + stackElements [lcv] .getFileName ()); System.out.println ("Linijos numeris:" + stackElements [lcv] .getLineNumber ()); String className = stackElements [lcv] .getClassName (); String packageName = extractPackageName (klasės pavadinimas); Eilutė simpleClassName = extractSimpleClassName (className); System.out.println ("Paketo pavadinimas:" + ("" .equals (packageName)? "[Numatytasis paketas]": packageName)); System.out.println ("Visas klasės pavadinimas:" + klasėsPavadinimas); System.out.println ("Paprastas klasės pavadinimas:" + simpleClassName); System.out.println ("Nepaleistas klasės pavadinimas:" + unmungeSimpleClassName (simpleClassName)); System.out.println ("Tiesioginis klasės pavadinimas:" + extractDirectClassName (simpleClassName)); System.out.println ("Metodo pavadinimas:" + stackElements [lcv] .getMethodName ()); System.out.println ("Gimtoji metodika ?:" + stackElements [lcv] .isNativeMethod ()); System.out.println ("toString ():" + stackElements [lcv] .toString ()); System.out.println (""); if (! displayAll) return true; } System.out.println (""); grįžti tiesa; } // „DisplayStackTraceInformation“ () pabaiga. 

Iš esmės mes skambiname „getStackTrace“ () ant pravažiavimo Metamasir tada suraskite asmenį „StackTraceElement“s, išgaunant kuo daugiau žemėlapių informacijos.

Atkreipkite dėmesį į truputį rodyti Viskas parametras įveda. rodyti Viskas leidžia skambinančiai svetainei nuspręsti, ar rodyti visus „StackTraceElement“s arba tiesiog aukščiausias kamino elementas. Programos pavyzdyje naudojamas rodyti Viskas parametras, kad išvestis būtų apribota iki pagrįstos sumos.

Dauguma informacijos apie kamino pėdsakus yra tiesiogiai naudinga. Pavyzdžiui, „StackTraceElement.getMethodName“ () pateikia eilutę, kurioje yra metodo pavadinimas, o „StackTraceElement.getFileName“ () grąžina eilutę su pirminiu šaltinio failo pavadinimu. Skaityti „StackTraceElement“ Javadoc už visą metodų sąrašą.

Klasių pavadinimai gausu!

Kaip tikriausiai pastebėjote, displayStackTraceInformation () kodas naudoja keletą papildomų pagalbininkų metodų, kad išskaidytų grąžintą vertę „StackTraceElement.getClassName“ (). Tie pagalbininkų metodai reikalingi, nes „StackTraceElement.getClassName“ () grąžina pilną klasės pavadinimą ir „StackTraceElement“ neturi kitų būdų pateikti pagrindines visiškai kvalifikuoto klasės pavadinimo dalis. Sužinosime apie kiekvieną papildomą pagalbininko metodą, nagrinėdami įvairius naudojimo būdus displayStackTraceInformation ().

Numatytieji ir pavadinti paketai

Atsižvelgiant į visiškai kvalifikuotą klasės pavadinimą, extractPackageName () pateikia pakuotės, kurioje gyvena klasė, pavadinimą:

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

Iš esmės, extractPackageName išskiria viską, kas yra prieš paskutinį tašką pilnai kvalifikuotame klasės pavadinime. Ankstesnė informacija yra paketo pavadinimas.

Pastaba: Viršuje galite pakomentuoti / panaikinti paketo teiginį „StackTrace.java“ išnagrinėti skirtumą tarp programos pavyzdžio vykdymo numatytuoju, neįvardytu paketu ir jos paleidimo boo.hoo pakuotė. Pvz., Kai nekomentuojamas, rodomas aukščiausias kamino elementas, skirtas skambinti juosta () nuo foo () nuo pagrindinis () turėtų atrodyti taip:

Failo pavadinimas: StackTrace.java Eilutės numeris: 227 Paketo pavadinimas: boo.hoo Visas klasės pavadinimas: boo.hoo.StackTrace Paprastas klasės pavadinimas: StackTrace Nepraleistas klasės pavadinimas: StackTrace Tiesioginis klasės pavadinimas: StackTrace Metodo pavadinimas: juosta Native method ?: false toString ( ): boo.hoo.StackTrace.bar (StackTrace.java:227) 

Arba, jei pakomentuosite paketo teiginį, aukščiau pateiktas kamino elementas turėtų būti panašus į tai:

Failo pavadinimas: StackTrace.java Eilutės numeris: 227 Paketo pavadinimas: [numatytasis paketas] Visas klasės pavadinimas: StackTrace Paprastas klasės pavadinimas: StackTrace Neišjungto klasės pavadinimas: StackTrace Tiesioginis klasės pavadinimas: StackTrace Metodo pavadinimas: juosta Native method ?: false toString (): StackTrace .bar („StackTrace.java:227“) 

Ar klasių pavadinimai kada nors gali būti paprasti?

Kitas mūsų naudojamas pagalbininkų metodas yra extractSimpleClassName (). Kaip pamatysite, šio metodo rezultatai nebūtinai yra paprasti, tačiau noriu aiškiai atskirti šį supaprastintą klasės pavadinimą nuo visiškai kvalifikuoto klasės pavadinimo.

Iš esmės, extractSimpleClassName () papildo extractPackageName ():

 public static String extractSimpleClassName (String fullClassName) ("" .equals (fullClassName))) return ""; int lastDot = fullClassName.lastIndexOf ('.'); if (0> lastDot) grąžinti fullClassName; grąžinti fullClassName.substring (++ lastDot); 

Kitaip tariant, extractSimpleClassName () grąžina viską po to paskutinis taškas (.) nuo visiškai kvalifikuoto klasės pavadinimo. Pavyzdžiui, nuo to paties skambučio iki juosta () aukščiau matome, kad paprastas klasės pavadinimas yra teisingas „StackTrace“, neatsižvelgiant į tai, ar kodas yra numatytojo paketo, ar pavadinto paketo dalis.

Įdomesnių rezultatų gauname, kai atkreipiame dėmesį į įdėtas klases. Programos pavyzdyje sukūriau du lygius lizdų, pavadintų klases (PirmasisNested ir „FirstNested“. „SecondNested“) kartu su papildoma, anonimine vidine klase (viduje „FirstNested“. „SecondNested“).

Visas įdėtas naudojimas prasideda taip:

 public StackTrace (loginė na) {StackTrace.FirstNested įdėta = nauja StackTrace.FirstNested (); } 

Atkreipkite dėmesį, kad loginis parametras (na) nieko nereiškia. Aš ką tik pridėjau, nes reikia atskirti kitus konstruktorius.

Čia yra įdėtos klasės:

 public class FirstNested {public FirstNested () {StackTrace.displayStackTraceInformation (new Throwable ()); „StackTrace.FirstNested.SecondNested yan = new StackTrace.FirstNested.SecondNested (); System.out.println ("Išpylimas iš kiaulienos vidaus ():"); yan.hogwash (); } public class 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 ()); }}; // Anoniminių narių klasės pabaiga. daužytas.mušti (); } // Kiaurymės pabaiga (). } // FirstNested.SecondNexted narių klasės pabaiga. } // „FirstNested“ narių klasės pabaiga. 

Viršutinis kamino elementas AntrasisNestedkonstruktorius atrodo taip:

Failo pavadinimas: StackTrace.java Eilutės numeris: 267 Paketo pavadinimas: boo.hoo Pilnas klasės pavadinimas: boo.hoo.StackTrace $ FirstNested $ SecondNested Paprastas klasės pavadinimas: StackTrace $ FirstNested $ SecondNested Neperjungtas klasės pavadinimas: StackTrace.FirstNested.SecondNested Tiesioginis klasės pavadinimas: „SecondNested“ metodo pavadinimas: Gimtasis metodas ?: klaidingas toString (): boo.hoo.StackTrace $ FirstNested $ SecondNested. (StackTrace.java:267) 

Galite pastebėti, kad paprastas klasės pavadinimas šiuo atveju nėra toks paprastas. Įdėtosios klasės skiriamos nuo aukštesnio lygio įdėtųjų klasių ir nuo aukščiausio lygio, naudojant dolerio ženklo simbolį ($). Taigi techniškai „paprastas“ antrosios įdėtos klasės pavadinimas yra „StackTrace $ FirstNested $ SecondNested“.

Aš pateikiau unmungeSimpleClassName () metodas pakeisti dolerio ženklus visiškumo laikotarpiais.

Kadangi esu užsispyrusi, vis tiek norėjau gauti tikrai paprastą klasės pavadinimą, todėl ir sukūriau extractDirectClassName ():

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