Java savjet 99: Automatizirajte stvaranje toString ()

Programeri koji rade na velikim projektima obično provode sate pišući korisne toStringmetode. Čak i ako svaka klasa ne dobije vlastitu toStringmetodu, svaka klasa spremnika podataka će. Dopuštanje svakom programeru da napiše toStringsvoj način može dovesti do kaosa; svaki će programer nesumnjivo smisliti jedinstveni format. Kao rezultat, korištenje izlaza tijekom uklanjanja pogrešaka postaje teže nego što je potrebno bez očite koristi. Stoga bi se svaki projekt trebao standardizirati u jednom formatu za toStringmetode, a zatim automatizirati njihovo stvaranje.

Automatizirajte toString

Sada ću pokazati uslužni program pomoću kojeg možete upravo to učiniti. Ovaj alat automatski generira redoviti i robustan

toString

metoda za određenu klasu, gotovo eliminirajući vrijeme provedeno u razvoju metode. Također centralizira

toString()

format. Ako promijenite format, morate ponovno generirati

toString

metode; međutim, to je još uvijek puno lakše nego ručno mijenjati stotine ili tisuće klasa.

Održavanje generiranog koda je također jednostavno. Ako dodate više atributa u klase, možda ćete morati izvršiti promjene i u toStringmetodi. Budući da je generiranje toStringmetoda automatizirano, trebate samo ponovo pokrenuti uslužni program na klasi da biste izvršili promjene. Ovo je jednostavnije i manje sklono pogreškama od ručnog pristupa.

Kod

Ovaj članak nije namijenjen objašnjavanju API-ja Reflection; sljedeći kod pretpostavlja da barem razumijete koncepte koji stoje iza Refleksije. Možete posjetiti

Resursi

odjeljak za dokumentaciju API-ja Reflection. Uslužni program napisan je kako slijedi:

paket fareed.publications.utilities; uvoz java.lang.reflect. *; javna klasa ToStringGenerator {public static void main (String [] args) {if (args.length == 0) {System.out.println ("Navedite ime klase kao argument naredbenog retka"); System.exit (0); } pokušajte {Class targetClass = Class.forName (args [0]); if (! targetClass.isPrimitive () && targetClass! = String.class) {Polja polja [] = targetClass.getDeclaredFields (); Klasa cSuper = targetClass.getSuperclass (); // Dohvaćanje rezultata super klase ("StringBuffer međuspremnik = novi StringBuffer (500);"); // Izgradnja međuspremnika if (cSuper! = Null && cSuper! = Object.class) {output ("buffer.append (super.toString ());"); // toString ()} super klase za (int j = 0; j <polja.duljina; j ++) {output ("buffer.append (\" "+ polja [j].getName () + "= \"); "); // Dodaj ime polja if (polja [j] .getType (). isPrimitive () || polja [j] .getType () == String.class) // Provjerite ima li primitiv ili izlaz niza ("buffer.append (this." + Polja [j] .getName () + ");"); // Dodaj vrijednost primitivnog polja else {/ * NIJE primitivno polje pa to zahtijeva provjeru NULL vrijednosti za agregirani objekt * / output ("if (this." + polja [j] .getName () + "! = null)"); output ("buffer.append (this." + polja [j] .getName () + ".toString ());"); output ("else buffer.append (\" vrijednost je null \ ");");} // kraj drugog} // kraj od for output petlje ("return buffer.toString ();");}} catch (ClassNotFoundException e) {System.out.println ("Klasa nije pronađena na putu do klase"); System.exit (0);}} privatni statički izlaz praznine (podaci niza) {System.out.println (podaci); }}

Izlazni kanal koda

Format koda također ovisi o zahtjevima vašeg projektnog alata. Neki programeri možda više vole imati kod u korisnički definiranoj datoteci na disku. Ostali programeri su zadovoljni s

system.out

konzola koja im omogućuje ručno kopiranje i ugradnju koda u stvarnu datoteku. Jednostavno vam prepuštam te mogućnosti i koristim se najjednostavnijom metodom:

system.out

izjave.

Ograničenja pristupa

Postoje dva važna ograničenja ovog pristupa. Prva je da ne podržava objekte koji sadrže cikluse. Ako objekt A sadrži referencu na objekt B, koji zatim sadrži referencu na objekt A, ovaj alat neće raditi. Međutim, taj će slučaj biti rijedak za mnoge projekte.

Drugo ograničenje je da dodavanje ili oduzimanje varijabli člana zahtijeva regeneraciju toStringmetode. Budući da se to mora raditi s alatom ili bez njega, to nije problem specifičan za ovaj pristup.

Zaključak

U ovom sam članku objasnio mali uslužni program za automatizaciju koji zaista može poboljšati produktivnost programera i igrati malu, ali važnu ulogu u smanjenju ukupnih vremenskih rokova projekta.


Savjeti za praćenje

Nakon objavljivanja ovog savjeta, dobio sam nekoliko prijedloga čitatelja o tome kako poboljšati kôd. U ovom nastavku objašnjavam kako sam ažurirao uslužni program na temelju tih prijedloga i vlastitih uvida. Izvorni kod za ova poboljšanja možete pronaći u Resursima.

Poboljšanje br. 1, predložila Sangeeta Varma

U svom izvornom kodu nisam obrađivao tipove polja za objektni i primitivni tip podataka; novi kod sada obrađuje podatke niza. Međutim, kôd ide samo do jednodimenzionalnih nizova i neće raditi za višedimenzionalne nizove. Nisam uspio smisliti generičko rješenje za ovaj problem jer, koliko znam, ne postoji ograničenje broja dimenzija za tipove podataka u Javi (jedino ograničenje je dostupna memorija). Pozdravljam sve povratne informacije koje možete ponuditi za rješenje.

Poboljšanje br. 2, predložio Chris Sanscraint

Izvorno sam predložio uslužni program za vrijeme razvoja, a ne za vrijeme izvođenja. Omogućavanje izvođenja uslužnog programa tijekom izvođenja može biti vrlo korisno, ali može potrajati još nekoliko ciklusa procesora. Međutim, odbacivanje / ispravljanje pogrešaka (osnovna upotreba toString()) obično se vrši tijekom vremena izrade i isključuje se za proizvodno okruženje. U nekim slučajevima ovo isključivanje u proizvodnom okruženju možda neće biti primjenjivo jer se neki projekti mogu koristiti toString()u svrhe poslovne logike. Predlažem da tu odluku donesete od projekta do projekta.

Prije razvijanja ovog uslužnog programa, već sam imao u vidu ovu fleksibilnost izvršavanja. Prvo sam razvio zasebnu klasu delegiranja koju je koristila bilo koja klijentska klasa za generiranje toString(). Klasa ga je generirala koristeći poziv metode poput return ToStringGenerator.generateToString(this), gdje thispokazuje na trenutnu instancu klijentske klase, a naredba koda je napisana u toString()implementaciji metode. Ali taj pristup nije uspio jer API Reflection nema mogućnost dobivanja vrijednosti za privatne članove u vrijeme izvođenja. Dakle, čas je bio koristan samo za članove javnosti, što ja nisam želio.

Ali tada je gospodin Sanscraint istaknuo da isti Reflection API kod dobiva vrijednost privatnih članova u vrijeme izvođenja kada je kôd napisan u metodi iste klase pozivatelja. Stoga sam ažurirao uslužni program koji će se koristiti tijekom izvođenja, a osim toga, toString()metodu nikada neće trebati ažurirati ili uređivati ​​za oduzimanje ili dodavanje bilo kakvih atributa u ciljnoj klasi.

Poboljšanje br. 3, predložio Eric Ye

Izvorno sam koristio thisprefiks za pristup varijablama člana u generiranom kodu, ali gospodin Ye je naglasio da se kôd također može koristiti u statičkoj metodi ili čak za izlaz statičkih članova. Tako ažurirani kod sada može rukovati i članovima klase i instance. Gospodin Ye također je identificirao grešku koja je ispravljena u ovoj verziji zbog koje je klasa generirala beskoristan kôd za klase bez atributa.

Izmjene koda

Nakon omogućavanja runtime alata, frustriralo me je što sam morao kopirati / zalijepiti metode u svaku klasu, što je postalo teško jer se novi kôd sastojao od više metoda.

Jedno od rješenja bilo bi stvaranje sučelja / apstraktne osnovne klase koja bi barem riješila problem potpisa metode, ali kopiranje / lijepljenje i dalje bi bilo potrebno. Apstraktno rješenje osnovne klase također bi klijentu ograničilo izvođenje iz druge klase.

Međutim, unutarnja klasa ima mogućnost pristupa privatnim članovima roditeljske klase, tako da bi kôd odraza, koji se izvodi unutar njezinih metoda, mogao dobiti i privatne vrijednosti. Stoga sam odlučio uslužni program promijeniti u unutarnju klasu koja se može umetnuti u bilo koju roditeljsku klasu klijenta. Također sam pružio ToStringGeneratorExample.java koji koristi ToStringGenerator.java kao unutarnju klasu za implementaciju toString()metode.

Na kraju, želim zahvaliti onima koji su dali svoje prijedloge za poboljšanje ovog pristupa.

Syed Fareed Ahmad Java je programer, dizajner i arhitekt u Lahoreu u Pakistanu. Uključen je u razvoj rješenja za e-poslovanje zasnovano na Javi (Servlets, JSP i EJB), WebSphere i XML.

Saznajte više o ovoj temi

  • Za daljnji izvorni kod

    //images.techhive.com/downloads/idge/imported/article/jvw/2000/08/jw-javatip99.zip

  • Dokumentacija za razmišljanje na web mjestu Sun

    //java.sun.com/products/jdk/1.1/docs/guide/reflection/index.html

  • Pogledajte sve prethodne Java savjete i pošaljite svoje

    //www.javaworld.com/javatips/jw-javatips.index.html

Ovu je priču "Java tip 99: Automatizirajte stvaranje niza ()" izvorno objavio JavaWorld.