Programiranje

Premisleki Java toString ()

Že razvijalci Java se zavedajo uporabnosti metode Object.toString (), ki je na voljo vsem primerkom razredov Java in jo je mogoče preglasiti, da zagotovi koristne podrobnosti o katerem koli določenem primerku razreda Java. Na žalost tudi izkušeni razvijalci Java iz različnih razlogov te močne funkcije Java občasno ne izkoristijo v celoti. V tej objavi v blogu pogledam skromno Javo toString () in opišite preproste korake, ki jih lahko naredite za izboljšanje uporabnosti toString ().

Izrecno implementiraj (razveljavi) toString ()

Morda najpomembnejši premislek, povezan z doseganjem največje vrednosti iz toString () je zagotoviti njihovo izvedbo. Čeprav koren vseh hierarhij razredov Java, Object, ponuja izvedbo toString (), ki je na voljo vsem razredom Java, privzeto vedenje te metode skoraj nikoli ni koristno. Javadoc za Object.toString () pojasnjuje, kaj je toString () privzeto na voljo, če za razred ni na voljo različica po meri:

Metoda toString za razred Object vrne niz, sestavljen iz imena razreda, katerega predmet je primerek, znaka at-sign `@` in nepodpisane šestnajstiške predstavitve hash kode predmeta. Z drugimi besedami, ta metoda vrne niz, ki je enak vrednosti:getClass (). getName () + '@' + Integer.toHexString (hashCode ())

Težko je najti situacijo, v kateri sta uporabna ime razreda in šestnajstiška predstavitev razpršene kode predmeta, ločena z znakom @. V skoraj vseh primerih je bistveno bolj koristno navesti eksplicitno po meri

toString ()

izvedba v razredu, da preglasi to privzeto različico.

Javadoc za Object.toString () nam pove tudi, kaj a toString () izvedba bi na splošno morala vključevati in daje tudi isto priporočilo, kot ga dajem tukaj: preglasiti toString ():

Na splošnotoString vrne niz, ki "besedilno predstavlja" ta objekt. Rezultat bi moral biti jedrnata, a informativna predstavitev, ki jo je človek lahko prebral. Priporočljivo je, da vsi podrazredi preglasijo to metodo.

Kadarkoli napišem nov razred, obstaja več metod, za katere menim, da jih dodajam kot del ustvarjanja novega razreda. Tej vključujejo

hashCode ()

in

je enako (objekt)

če je primerno. Vendar po mojih izkušnjah in po mojem mnenju izvajanje izrecno

toString ()

je vedno primerno.

Če "priporočilo" Javadoca, da "vsi podrazredi preglasijo to metodo", ne zadostuje (potem ne domnevam, da je tudi moje priporočilo), da bi razvijalcu Jave upravičil pomen in vrednost eksplicitnega toString () metode, potem priporočam, da si ogledate Učinkovito postavko Java Josh Bloch "Always Override toString" za dodatno ozadje o pomembnosti izvajanja toString (). Menim, da bi morali vsi razvijalci Java imeti kopijo Učinkovita Java, na srečo pa poglavje s to točko toString () je na voljo tistim, ki nimajo kopije: Metode, skupne vsem predmetom.

Vzdrževanje / posodabljanje toString ()

Moteče je eksplicitno ali implicitno poklicati predmet toString () v zapisniku dnevnika ali drugem diagnostičnem orodju in vrnite privzeto ime razreda in heksicimalno razpršeno kodo predmeta, ne pa kaj bolj uporabnega in berljivega. Skoraj enako moteče je imeti nepopolno toString () izvedba, ki ne vključuje pomembnih delov trenutnih značilnosti in stanja predmeta. Trudim se biti dovolj discipliniran in ustvarjati ter slediti navadi, da vedno pregledam toString () izvajanje skupaj s pregledom je enako (objekt) in hashCode () izvedbe katerega koli razreda, na katerem delam, ki je zame nov ali kadar dodam ali spremenim atribute razreda.

Samo dejstva (toda vse / večina!)

V poglavju Učinkovita Java prej omenjeni Bloch piše: "Ko je to mogoče, mora metoda toString vrniti vse zanimive informacije, ki jih vsebuje predmet." Dodajanje vseh atributov atributov težkega razreda njegovi izvedbi toString je lahko boleče in dolgočasno, toda vrednost tistih, ki poskušajo odpraviti napake in diagnosticirati težave, povezane s tem razredom, bo vredna truda. Običajno si prizadevam, da bi bili v ustvarjeni predstavitvi niza vsi pomembni atributi, ki niso nuli mojega primerka (in včasih vključujejo dejstvo, da so nekateri atributi nični). Za atribute običajno dodam tudi minimalno identifikacijsko besedilo. V mnogih pogledih gre bolj za umetnost kot za znanost, vendar poskušam vključiti dovolj besedila, da lahko atribute ločim, ne da bi pri tem bodoče razvijalce preveč obtičali. Najpomembneje mi je, da dobim vrednosti atributov in določeno vrsto identifikacijskega ključa.

Spoznaj svojo publiko

Ena najpogostejših napak, ki sem jih videl razvijalci Java, ki niso začetniki toString () pozablja kaj in kdo toString () je običajno namenjen. Na splošno, toString () je orodje za diagnostiko in odpravljanje napak, ki olajša beleženje podrobnosti o določenem primerku ob določenem času za kasnejše odpravljanje napak in diagnostiko. Običajno je napaka, če uporabniški vmesniki prikazujejo nize, ki jih generira toString () ali sprejemati logične odločitve na podlagi a toString () predstavitev (pravzaprav je logično odločanje za kateri koli niz krhko!). Videl sem dobronamerne razvijalce toString () vrne format XML za uporabo v nekaterih drugih XML prijaznih vidikih kode. Druga pomembna napaka je prisiliti stranke, da razčlenijo vrnjeni niz toString () za programski dostop do podatkovnih članov. Verjetno je bolje zagotoviti javni način pridobivanja / dostopa kot se zanašati na toString () nikoli se ne spreminja. Vse to so napake, ker ti pristopi pozabljajo na namen a toString () izvajanje. To je še posebej zahrbtno, če razvijalec iz. Odstrani pomembne lastnosti toString () (glej zadnji element), da bo videti boljše v uporabniškem vmesniku.

všeč mi je toString () izvedbe, da imajo vse ustrezne podrobnosti in zagotovijo minimalno oblikovanje, da bodo te podrobnosti bolj všečne. To oblikovanje lahko vključuje premišljeno izbrane znake novih vrstic [System.getProperty ("line.seperator");] in zavihki, dvopičja, podpičja itd. Ne vlagam toliko časa, kot bi želel rezultat, predstavljen končnemu uporabniku programske opreme, vendar poskušam narediti oblikovanje dovolj lepo, da je več berljivo. Poskušam izvajati toString () metode, ki niso preveč zapletene ali drage za vzdrževanje, vendar zagotavljajo zelo preprosto oblikovanje. S prihodnjimi vzdrževalci svoje kode poskušam ravnati tako, kot bi želeli, da me obravnavajo razvijalci, katerih kodo bom nekoč vzdrževal.

V svojem elementu dne toString () Bloch navaja, da se mora razvijalec odločiti, ali bo imel toString () vrne določeno obliko. Če je predvidena določena oblika, mora biti to dokumentirano v komentarjih Javadoc, Bloch pa nadalje priporoča, da je na voljo statični inicializator, ki lahko predmet vrne v njegove značilnosti primerka na podlagi niza, ki ga ustvari toString (). Strinjam se z vsem tem, vendar verjamem, da je to več težav, kot je večina razvijalcev pripravljena iti. Bloch tudi poudarja, da bodo kakršne koli spremembe tega formata v prihodnjih izdajah povzročale bolečino in jezo pri ljudeh, ki so odvisni od tega (zato mislim, da ni dobro, če je logika odvisna od toString () izhod). Z veliko discipline pri pisanju in vzdrževanju ustrezne dokumentacije, ki ima vnaprej določeno obliko za a toString () verjetno. Vendar se mi zdi težava in bolje je preprosto ustvariti novo in ločeno metodo za takšno uporabo in zapustiti toString () neobremenjen.

Nobenih stranskih učinkov ni dovoljeno

Tako pomembno kot toString () Izvajanje je na splošno nesprejemljivo (in zagotovo velja za slabo obliko), če imamo izrecno ali implicitno klicanje toString () vplivajo na logiko ali vodijo do izjem ali logičnih težav. Avtor a toString () metoda mora biti previdna, da se prepričate, da se sklici preverjajo za nule pred dostopom do njih, da se izognete NullPointerException. Mnogo taktik, ki sem jih opisal v prispevku Učinkovito ravnanje z NullPointerException, je mogoče uporabiti v toString () izvajanje. Na primer, String.valueOf (Object) ponuja enostaven mehanizem za nično varnost atributov dvomljivega izvora.

Podobno je pomembno tudi za toString () razvijalec, da preveri velikosti matrike in druge velikosti zbirke, preden poskuša dostopati do elementov zunaj te zbirke. Zlasti je vse preveč enostavno naleteti na StringIndexOutOfBoundsException, ko poskušate z String.substring manipulirati z vrednostmi Stringa.

Ker predmet toString () izvedbe je mogoče zlahka priklicati, ne da bi se razvijalci tega vestno zavedali, še posebej pomemben je ta nasvet, da ne povzroča izjem in ne izvaja logike (zlasti logike, ki spreminja državo). Zadnja stvar, ki si jo kdo želi, je, da dejanje beleženja trenutnega stanja primerka povzroči izjemo ali spremembo stanja in vedenja. A toString () izvedba bi morala biti dejansko samo za branje, pri kateri se stanje objekta bere, da se ustvari niz za vrnitev. Če se med postopkom spremenijo kakšni atributi, se verjetno zgodijo slabe stvari v nepredvidljivih časih.

Moje stališče je, da a toString () izvedba mora vključevati samo stanje v generiranem nizu, ki je dostopno v istem procesnem prostoru v času njegove generacije. Zame ni zaščitljivo imeti a toString () izvedba dostop do oddaljenih storitev za ustvarjanje niza primerka. Morda malo manj očitno je, da primerek ne sme zapolniti atributov podatkov, ker toString () je bil poklican. The toString () izvedba naj poroča le o tem, kako so stvari v trenutni instanci, in ne o tem, kako bi lahko bile ali bodo v prihodnosti, če se pojavijo nekateri drugačni scenariji ali če se stvari naložijo. Za učinkovito odpravljanje napak in diagnostiko je toString () mora pokazati, kako so razmere in ne, kako bi lahko bile.

Enostavno oblikovanje je iskreno cenjeno

Kot je opisano zgoraj, je lahko smiselna uporaba ločil in zavihkov vrstic koristna pri ustvarjanju dolgotrajnejših in zapletenih primerkov, ki so bolj všečni, kadar so ustvarjeni v obliki niza. Obstajajo še drugi "triki", s katerimi lahko stvari postanejo lepše. Ne samo, da String.valueOf (objekt) priskrbite nekaj nič zaščita, vendar tudi predstavlja nič kot niz "null" (kar je pogosto najprimernejša predstavitev niče v nizu, ustvarjenem s toString (). Arrays.toString (Object) je uporaben za enostavno predstavljanje nizov kot nizov (za dodatne podrobnosti glejte moj prispevek Stringifying Java Arrays).

V predstavitev toString vključite ime razreda

Kot je opisano zgoraj, je privzeta izvedba toString () poda ime razreda kot del predstavitve primerka. Ko to izrecno preglasimo, to ime razreda potencialno izgubimo. Običajno to ni veliko, če beleženje niza primerka, ker bo dnevniški okvir vključeval ime razreda. Vendar sem raje na varnem in imam vedno na voljo ime razreda. Ne skrbi, da bi privzeto ohranili šestnajstiško predstavitev zgoščene kode toString (), vendar je ime razreda lahko koristno. Dober primer tega je Throwable.toString (). Raje uporabljam to metodo kot getMessage ali getLocalizedMessage, ker prva (toString ()) vključuje Mečljivoime razreda, zadnji dve metodi pa ne.

alternative toString ()

Trenutno tega nimamo (vsaj ne o standardnem pristopu), govorili pa so o razredu Objects v Javi, ki bi se dolgo potrudil k varni in koristni pripravi String predstavitev različnih predmetov, podatkovnih struktur in zbirk. Nisem slišal nobenega nedavnega napredka na tem področju v JDK7. Standardni razred v JDK, ki je zagotavljal String predstavitev predmetov, tudi kadar definicije razredov predmetov niso podale eksplicitno toString () bi bilo koristno.

Apache Commons ToStringBuilder je morda najbolj priljubljena rešitev za gradnjo varnih implementacij toString () z nekaterimi osnovnimi kontrolniki za oblikovanje. Že prej sem pisal blog o ToStringBuilder in obstajajo številni drugi spletni viri o uporabi ToStringBuilder.

Tehnični nasvet Java Technology Glen McCluskey "Pisanje metod toString" vsebuje dodatne podrobnosti o tem, kako napisati dobro metodo toString (). V enem izmed komentarjev bralcev Giovanni Pelosi navaja, da daje prednost prenosu predstavitve niza primerka znotraj dednih hierarhij iz toString () v razred delegata, zgrajen v ta namen.

Zaključek

Mislim, da večina razvijalcev Java priznava vrednost dobrega toString () izvedb. Na žalost te izvedbe niso vedno tako dobre ali uporabne, kot bi lahko bile. V tem prispevku sem poskušal opisati nekaj premislekov za izboljšanje toString () izvedb. Čeprav a toString () metoda ne bo (ali vsaj ne bi smela) vplivati ​​na logiko kot je enako (objekt) ali hashCode () metoda lahko izboljša izboljšanje odpravljanja napak in diagnostično učinkovitost. Manj časa, porabljenega za ugotavljanje stanja predmeta, pomeni več časa za odpravljanje težave, prehod na bolj zanimive izzive in zadovoljevanje več potreb strank.

To zgodbo, "Razmisleki o Java toString ()", je prvotno objavil JavaWorld.

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