Professional Documents
Culture Documents
Misliti Na Javi PDF
Misliti Na Javi PDF
Misliti Na Javi PDF
na
Javi
Prevod etvrtog izdanja
Bruce Eckel
MindVievv, Inc., p re d s e d n ik
Preveo
Miljenko uur
P R E N T IC E
H ALL
M isliti na Javi, prevod etv rto g izdanja
G lavn i u re d n ik O lg a M ila n k o
R e d a k to ri Stela Spasi
S n ean a B iseni
T ehniki u re d n ik S an ja Tasi
L e k to r i k o re k to r Vesna u k i
R ealizacija k o ric a N ataa Pavlov
P relom tek sta i o b r a d a slika San ja Tasi
M iiica D ean sk i
N ataa Pavlov
ta m p a P u b lik u m , B eograd
M ik ro k n jig a
P. fah 20 -87
11030 B eog rad
tel: 01 1/3 5 4 0 -5 4 4
pi sma@mi k ro k n j i g a . r s
llo p v rig h t 2 007 M ik ro k n jig a . Sva p rav a z a d r a n a . N ije d o z v o lje n o d a ije d a n d eo ove knjige b u d e re p ro d u k o v a n
ili e m ito v a n n a bilo koji n a in , e le k tro n sk i ili m e h a n i k i, u k lju u iu i fo to k o p ira n je , s n im a n je ili b ilo koji d ru g i sistem
za beleen je, b ez p r e th o d n e p ism e n e d o z v o le izdavaa.
T ra n sla tio n c o p v rig h t - 2007 by M ik ro k n jig a , T h in k in g in Java, F o u r th E d itio n b y B ru ce Eckel, C o p y rig h t <0 2006,
All R ights Reserved. P u b lish e d by a rra n g e m e n t vvith th e o rig in a l p u b lish e r, P earso n F d u c a tio n , Inc., p u b lish in g as P re n tic e
H a ll, In c, a C o m p a n y .
004.438JAVA
001.42:00-4.738.5
EK EJl. Bpvc
M isliti n a Javi / B ru ee Eckel ; p rev o d
4. izd. M iljenko ueur. - B eograd : Mikro
knjiga, 2007 (B e o g ra d : P ub lik u m ) -
XIII, 1201 s tr . graf. prikazi : 24 cn i
ISBN 978-86-7555-308-3
Razvoj apstrakcije..........................15 P r a v l j e n j e p r o g r a m a n a J a v i . . . .5 2
Vidljivost i m e n a .....................................52
O bjekat im a in te rfe js................... 17
Korienje d rugih k o m p o n e n a ta . . . . 52
O bjekat prua u slu g e................... 19 Rezervisana re s t a t i c ............................53
Skrivena realizacija........................20 V a p r v i p r o g r a m n a J a v i ................. 5 4
Ponovno korienje realizacije.. .21 Prevodenje i iz v rav a n je ....................... 56
N asleivanje...................................22 K o m e n ta ri i u g ra e n a
Relaeije !! i IE-KAO.......................25 d o k u m e n t a c i j a ........................................ 5 7
Virtuelizacija objekata preko D okum entacioni k o m e n ta ri................ 58
p o lim o rfiz m a................................ 26 S in ta k s a .....................................................58
H ijerarhija s jedinstvenim U gradeni H T M L .....................................59
P rim eri o z n a k a ....................................... 60
k o r e n o m ......................................... 29
P rim er d o k u m e n ta c ije ......................... 62
K ontejneri.......................................29
S til p r o g r a m i r a n j a ............................... 6 3
Paramctri/uvani (generieki) tipuvi .. 30
S a e t a k ........................................................... 6 3
O brada izuzetaka: postupanje
V e b e .............................................................. 6 3
s grekam a.......................................33
vi Misliti na Javi
3: O p e r a t o r i 65 N a r e d b a s w i t c h ................................ 112
S a e ta k .................................................... 114
Jednostavnije naredbe
za ispisivanje.................................. 65 5: I n i c i j a l i z a c i j a i i e n je 115
Korienje operatora u Jav i.........66
P rio rite ti.........................................66 G a r a n t o v a n a in ic ija liz a c ija
Dodela v re d n o s ti..........................67 p o m o u k o n s t r u k t o r a .................. 115
Pojava pseudonima P r e k l a p a n je m e t o d a ........................ 117
pri pozivanju metode.....................68 Razlikovanje preklopljenih m etoda ..1 1 9
Matematiki o p erato ri................. 69 Preklapanje i prosti t i p o v i ................ 120
Unarni operatori minus i plus.........71 Preklapanje p o v ra tn ih v re d n o s ti. . . 123
Osnovni p o jm o v i........................306 P r o n a l a e n j e s l i n i h i z u z e t a k a . .3 8 2
1 6 :N iz o v i 593 I z b o r r e a l i z a c i j e ..................................... 6 8 3
S tru k tu ra za ispitivanje
ta to nizove ini p o se b n im .. . .593 p e rfo rm a n s i............................................684
Nizovi su prvorazredni objekti. .595 Perform anse razliitih L is ta ..............688
Vraanje niza v re n o sti............. 597 O p asn o sti od m ik roporedenja
p e rfo r m a n s i............................................694
Viedimenzionalni n iz o v i.........599
Iz b o rsk u p a
Nizovi i generiki tipovi............. 603 (realizacije interfejsa S e t ) .................. 696
Pravljenje podataka Izb or m apa
za testiran je...................................605 (realizacija interfejsa M a p )................ 698
Arrays.fill()................................. 605 U s l u n e m e t o d e .................................. 7 01
Generatori podataka..................... 606 U redivanje i p retraivanje lista
Pravljenje nizova od Generatora... 612 (realizacija interfejsa L i s t ) ................ 705
M etode klase A rrays....................616 Kako kolekciju ili m a p u uiniti
Kopiranje niza..............................617 n e p ro m e n ljiv o m .................................. 706
Poreenje nizova.......................... 618 Sinhronizovanje kolekcije ili m a p e . .708
Poreenje elemenata niza..............619 uvanje referen ci ............................... 7 0 9
Ureivanje niza............................ 623 K ontejner W e a k H a s h M a p ................ 712
Pretraivanje ureenog niza.......... 624 Kontejneri Jave 1 . 0 / 1 . 1 ....................7 1 3
Saetak........................................... 626 V ector i E n u m e r a t i o n .......................713
Klasa H a s h t a b l e .................................. 714
17: D e t a l j n o r a z m a t r a n j e Klasa S ta c k ..............................................714
Klasa B itS e t........................................... 716
k o n te jn e ra 628
Saetak .........................................................7 1 8
Potpuna taksonomija
kontejnera.....................................628 18: J a v in u la z n o - iz la z n i
2 1 : P a ra le ln o iz v r a v a n je 885
Uzajam na b lo k a d a ......................978
Nove kom ponente biblioteke . .983
Svi aspekti paralelnog C o u n tD ovvnL atch - brava
izvravanja.....................................886 sa o d b ro ja v a n je m ................................ 983
Bre iz v rav a n je .....................................886 C y c lic B a rrie r..........................................986
Poboljan d izajn k o d a ......................... 889 D e Ia y Q u e u e ............................................ 988
O s n o v e v i e n itn o g P rio rity B lo c k in g Q u e u e ..................... 991
p r o g r a m i r a n j a ........................................ 8 9 0 K ontroler staklenika napravljen
Definisanje z a d a ta k a ............................890 po m o u S c h e d u le d E x e c u to ra ......... 994
Klasa T h r e a d ......................................... 891 S e m a f o r ................................................... 997
U p o treb a izvrilaca E x c h a n g e r............................................ 1001
(interfejsa E x e c u to r)............................893 S i m u l a c i j a ..........................................1003
D obijanje p o v ra tn ih v redn osti Sim ulacija alterskog slubenika . . 1003
o d z a d a ta k a ............................................896 Sim ulacija r e s to r a n a ......................... 1008
S p a v a n je ...................................................897 R aspodela p o s la .................................. 1013
P r i o r i t e t ...................................................899 O p t i m iz a c ij a p e r f o r m a n s i . . . .1 0 1 8
P rep u ta n je .............................................. 901 Poreenje tehnologija u zajam no
Servisne n i t i ............................................901 iskljuivih brava ( m u t e x a ) .............. 1018
V arijante p ro g ra m ira n ja .....................906 K ontejneri bez z a k lju a v a n ja ......... 1027
T erm inologija..........................................911 O p tim istik o z a k lju a v a n je ............1034
Kako se p rid ru iti postojeoj n i t i . . . 912 R ea d W rite L o c k .................................. 1036
Korisniko o k ruenje koje A k tiv n i o b j e k t i ............................... 1039
brzo re a g u je ............................................913
S a e t a k ................................................. 1042
G ru p e n iti................................................ 914
L iteratura za dalje usavravanje . . . 1044
H vatanje iz u z e ta k a .............................. 915
Deljenje r e s u r s a .......................... 918
N epravilno p ristu p a n je resursim a . . 918
22: Grafika korisnika
R azreavanje takm ienja okruenja 1045
za deljene re s u rse ...................................921
A tom ske operacije i tre n u tn a A pleti........................................... 1047
v id ljiv o st...................................................926 Osnove Svvinga..........................1047
A tom ske k l a s e ....................................... 932 Alatka za p rik aziv an je....................... 1050
K ritini o d e ljc i....................................... 933 Pravljenje d ugm eta................... 1051
S inhronizacija s d ru g im
I Ivatanje d o g a d a ja ................... 1052
o b je k tim a ................................................ 939
Lokalno skladite n i t i ......................... 940
Vieredna polja za te k s t...........1054
G a e n j e z a d a t a k a ............................... 9 4 2
Rasporeivanje elem enata. . . .1056
U krasna b a ta ......................................... 942
R asporediva 1056
B o r d e r L a y o u t.........
R asporediva 1057
F lo w L a y o u t..............
G aenje blo kiran ih z ad a ta k a ..............945
R asporediva 1058
G r id L a y o u t..............
Prekidanje izv rsav anja......................... 946
R asporediva G ridB agL avout . . . . 1058
Provera postoji li p r e k id .....................954
A p solutno p o z ic io n ira n je ................ 1059
M e u s o b n a s a ra d n ja
R asporediva B o x I,a y o u t................ 1059
z a d a t a k a ...................................................... 9 5 6 Koji je p ristu p najbolji?..................... 1059
w ait() i n o tity A lI() ..............................957
Model dogaaja
n o tify () u o d n o su na n o tify A ll(). . . 962
Proizvoai i p o tr o a i....................... 965
grafike biblioteke Svving.........1059
T ipovi dogadaja i p rije m n ik a ......... 1060
Proizvodai, p otroai i redovi
Praenje vi.e d o g a d a ja ..................... 1066
za e k a n je ................................................ 971
Cevi za ulazno/izlazne operacije Primeri Svving kom ponenata. . 1068
izm edu z a d a ta k a .................................. 976 D u g m a d ................................................ IO(->9
Ik o n ic e ................................................... 1071
Sadraj x iii
A li, k a k o je v r e m e o d m i c a l o I St o s a m je v i Se p r o u a v a o ,p o C e o s a m d a u v i a m d a
je osnovna nam ena Jave drugaija od nam ene svih drugih jezika koje sam sretao.
Program iranje je snalaenje u sloenosti: sloenost problem a koji elite da reite dodaje
se na sloenost raunara na kome se problem reava. Zbog ove sloenosti veina naih pro-
gramskih projekata propadne.- Pa ipak, za gotovo nijedan program ski jezik za koji znam
nije odlueno da bi njegov glavni cilj trebalo da bude savladavanje sloenosti razvoja i or-
avanja program a.1Naravno, mnoge odluke pri stvaranju program skih jezika donete su sa
sloenou na umu, ali u nekom trenutku uvek bi se nale neke druge stvari za koje se sma-
tralo da su neophodne u meavini. Te druge stvari neizbeno prouzrokuju da program er
koji koristi dati jezik na kraju udari glavom o zid. Na primer, C ++ je m orao da bude kom -
patibilan sa starijim jezikom C (da bi se omoguio lak prelazak C program erim a), a pri
tom i efikasan. I jedno i drugo su veoma korisni ciljevi i um nogom e zasluni za uspeh je-
zika C++, ali takoe unose dodatnu sloenost zbog koje neki projekti ne bivaju zavreni
(naravno, moete kriviti program ere i upravu, ali, ako jezik moe da pom ogne tako to e
otkrivati vae greke, zato to ne bi i radio). Evo jo jednog prim era. Visual Basic (VB) je
bio vezan za BASIC, koji ba nije bio proiriv jezik, tako da su sva proirenja nagom ilana u
VB-u proizvela zaista zastraujuu sintaksu koja se veoma teko odrava. Perl je vertikalno
kom patibilan sa Avvkom, Sedom, Grepom i drugim Unixovim alatima koje je trebalo da
zameni, a posledica je bila da je esto optuivan kako proizvodi ,,kod sam o za pisanje" (tj.
posle nekoliko meseci ne moete ga vie itati). S druge strane, pri stvaranju jezika kao to
su C++, VB, Perl i Smalltalk, deo napora je usmeren na reavanje problem a sloenosti, pa
oni veoma uspeno izlaze na kraj sa odreenom vrstom problema.
Dok sam uio Javu, ini mi se da je na m ene najvie uticalo to to je Sun m eu svojim
ciljevima pri projektovanju imao i princip smanjenja sloenosti zaprograrnera. Kao da su
rekli: Vano nam je da ubrzam o i pojednostavim o pravljenje robusnog koda. U ranim
danim a, ovaj princip je rezultovao kodom koji se nije brzo izvravao (iako se to s vreme-
nom popravilo), ali je zaista zadivljujue skratio vreme potrebno za pisanje program a
- za izradu program a na lavi potrebno je upola m anje vrem ena nego za pravijenje odgo-
varajueg C ++ programa. Ovaj rezultat sam po sebi moe da utedi m nogo vrem ena i
novca, ali lava se tu ne zaustavlja. O na nastavlja da pakuje sve vane i sloene zadatke, kao
to su vienitni rad i mreno program iranje, u svojstva jezika ili bibliotcke koji pojedno-
stavljuju te zadatke. Najzad, latila se nekih zaista veoma sloenih problem a kakvi su me-
duplattonnsko programiranje, dinamika prom ena koda, ak i pitanja zatite od kojih
se svaki na vaoj lestviei sloenosti moe svrstati od prepreka'1do potpuno nemogue".
Stoga, uprkos problem ima s perform ansam a koje smo susreli, Java silno obeava: moe
od nas da napravi znatno produktivnije programere.
Java na sve naine poveava opseg komunikacije tneu Ijudima: stvaranjem program a,
tim skim radom na stvaranju program a, izgradnjom korisnikog okruenja kao veze iz-
m eu program a i l<orisnika, izvravanjem program a na razliitim tipovim a raunara i
lakim pisanjem program a kojima se pristupa preko Interneta.
Mislim da ogrom na koliina inform acija koje putuju Internetom nije najvaniji po-
kazatelj znaaja kom unikacione revolucije; prava revolucija je u tom e to emo moi
m nogo lake da razgovaramo - pojedinano, u grupam a, i sa celom planetom . Pria se da
bi naredna revolucija iznedrila svojevrstan globalni um proizaao iz iskustva vie ljudi
i njihove m edusobne povezanosti. Java moe ali i ne m ora, biti alat koji e podstai tu
revoluciju - i zbog same takve m ogunosti, oseam kako je znaajno da i drugi naue ovaj
jezik.
Java SE6
Ova knjiga je bila ogrom an projekat koji je zahtevao mnogo vremena, i pre nego to je
izala, pojavila se beta verzija Jave SE6 (pod radnim im enom mustartg). lako je lava SF.6
donela nekoiiko manjih izmena koje su poboljale neke prim ere u knjizi, uglavnom nije
uticala na sadraj ove kniige; glavna obeleja Jave SE6 su poveanje brzine izvravanja i
novi elementi biblioteka, koja nisu tem a ove knjige.
Program i navedeni u knjiz.i uspeno su testirani na kandiatskoj verziji Jave SF.6, pa ne
oekujem da e ona doneti izmene koje bi uticale na sadraj ove knjige. Ukoliko u vreme
objavljivanja zvanine verzije Jave SE6 bude vanih iz.mena, njih emo uvaiti u izvornom
kodu knjige koji se moe preuzeti na adresi www.MiiidVicw.nct.
Na koricama knjige pie da je ona ,,za Javu SE5/6", to znai napisana za |avu SF.5 i
veoma vane iz.mene koje je ta verzija unela u jezik, ali jednako primenljiva i na Javu SE6.
Predgovor 3
etvrto izdanje
Zadovoljstvo pisanja novog izdanja knjige donosi injenica se stvari m ogu uraditi kako
treba, u skladu sa onim to sam saznao od izlaska poslednjeg izdanja. esto su ti uvidi
tipa Kada ne dobije ono to si hteo, dobije pouku" a za m ene je to prilika da popravim
ono to je pogreno ili prosto zamorno. fednako tako, pisanje novog izdanja dovodi do fa-
scinantnih novih zamisli, a stid zbog pogreaka m nogo je manji od uivanja u otkriu i
m ogunosti da se zamisli izraze bolje nego pre.
Tu je i izazov da knjigu napiem tako da i vlasnici prethodnih izdanja poele da je ku-
pe. To me tera da poboijavam ,preraujem i premetam sve to mogu da bi knjiga postala
novo i vredno iskustvo za posveene itaoce.
Izmene
U ovom izdanju nem a CD-a. Osnovni deo tog CD-a, m ultim edijski sem inar Thinking in
C (koji je za MindVievv napravio Chuck Allison), sada se moe preuzeti u obliku Flash
prezentacije. Polaznici tog seminara koji nedovoljno poznaju sintaksu C-a obuavaju se
da ovladaju m aterijalom iz ove knjige. Iako dva poglavlja ove knjige daju pristojan uvod
u sintaksu, ona m oda nee biti dovoljna osobam a bez adekvatnog predznanja, a prezen-
tacija Thinking in C upravo njima pomae da dostignu potreban nivo.
Poglavlje Paralelno izvravanje(ranijeVienitno izvravanje11) potpuno je preraeno da
bi odraziio velike izmene u odgovarajuim bibliotekama Jave SE5, ali jo uvek prua temelj
za osnovne koncepte paralelnog izvravanja. Bez tog jezgra, teko ete razumeti sioenije
oblasti paralelnog izvravanja. Mnogo sam meseci radio na tome, uronjen u taj drugi para-
lelan svet, i na kraju je ispalo da to poglavlje daje ne samo osnovu, nego i naprednije uvide.
Znaajnim novim m ogunostim a Jave SE5 posveena su nova poglavlja, a ostale su
utkane u izmene postojeeg materijala. Poto ja neprestano prouavam projektne obra-
sce, povean je i njihov broj u knjizi.
U knjizi je biio m nogo premetanja, u dobroj meri nadahnutih predavakom praksom
i sa/.nanjem da bi se moje poimanje onoga to treba da stane u je d n o poglavlje moglo raz-
borito kritikovati. I5io sam sklon nepromiljenom verovanju da tema m ora biti dovoljno
velika" kako bi zasluila sopstveno poglavlje. Ali, naroito tokom predavanja projektnih
obrazaca, uvideo sam da polaznici seminara najbolje shvataju kada uvodim jedan po je-
dan obrazac i odm ah uradim odgovarajuu vebu, ak i ako zbog toga tek nakratko go-
vorim . (Otkrio sam da je taj tempo prijatniji i za m ene kao predavaa.) Zato sam u ovoj
verziji knjige pokuao da poelim poglavlja na teme i da ne brinem koliko su duga. ini
m i se da je tako bolje.
Uvideo sani i kolika je vanost testiranja programa. Ukoliko nem ate ugraen sistem za
testiranje, u kojem se testiranjeobavlja svaki put kada generiete program, ne moete znati
koliko je va program pouzdan. Da bih izbegao tu nesigurnost, napravio sam sistem za te-
stiranje koji prikazuje i vrednuje rezultate svakog programa. (Sistem je napisan na Pvtho-
nu; nai ete ga u kodu ove knjige koji se moe preuzeti na lokaciji www.MindView.net.)
Testiranje uopte razm otreno je u dodatku objavljenom na adresi http://M indView.net/
Books/Bctterjavn; tu su objanjene osnovne vetine kojima bi, po m om miljenju, svi pro-
gram eri trebalo da vladaju.
4 Misliti na Javi
Pored toga, proeljao sam sve prim ere u knjizi i zapitao se: Zato sam to uradio ba
ovako?" U veini sluajeva neto sam izm enio i poboljao, da bi prim eri bili dosledniji i da
bih pokazao ono to sm atram najboljom praksom u pisanju Java koda (koliko se to moe
u tekstu uvodnog nivoa). Dizajn i realizacija m nogih postojeih prim era, znaajno su iz-
menjeni. Uklonjeni su prim eri koji su izgubili smisao i dodati novi.
itaoci su imali zaista divne kom entare na prva tri izdanja ove knjige to mi je bilo
veoma drago. Tu i tamo, poneko bi im ao i prim edbu i iz nekog razloga, periodino se ja-
vljala ista prim edba knjiga je preobimna". Po m eni, ako itaocu smeta samo obim dela,
to i nije tako strano (prisetim o se prim edbe austrijskog cara o M ocartovom delu: Pre-
vie nota!, iako se ja ni na koji nain ne poredim s M ocartom ). M ogu sam o da pretpo-
stavim kako takvu prim edbu upuuje onaj ko e se tek upoznati sa irinom Jave i ko nije
video ostale knjige o ovom jeziku. Ipak, pokuao sam da u ovom izdanju skratim delove
koji su postali nepotrebni ili barem ne previe znaajni. Po praviiu, pokuao sam da uklo-
nim sve to vie nije potrebno, ubacim izmene i poboljam sve to sam mogao. Mislim da
sam to mogao slobodno da uradim , jer je originalni m aterijal i dalje na Internetu (na
adresi www.MindView.net), u obliku prva tri izdanja koje se m ogu besplatno preuzeti, i
dodataka za ovu knjigu.
Iskreno se izvinjavam svima koji jo uvek ne mogu da podnesu veliinu ove knjige. Ve-
rovali ili ne, naporno sam radio da bih je smanjio.
ovde uhvaene i, po svoj prilici, ubijene u tegli za uzorke i smetene u male izlobene ku-
tije: sve ovo nagovetava Javinu sposobnost da pronalazi, prikazuje i obuzdava bubice
(to je zbilja jedan od njenih najjaih aduta).
Za ovo izdanje naslikao sam akvarel prikazan na koricama, ispod stilizovane kutije.
Zahvalnice
Prvo, hvala saradnicim a koji su radili sa m nom na sem inaru, u konsultacijam a i pri ost-
varivanju nastavnih projekata. To su: Dave Bartlett, Bill Venners, Chuck Allison, Jeremy
Meyer i Jamie King. Cenim vae strpljenje, dok i dalje pokuavam da napravim najbolji
model za m eusobnu saradnju nezavisnih ljudi kao to smo mi.
O dnedavno, bez sum nje zaslugom interneta, povezao sam se sa iznenadujue velikim
brojem ljudi koji m i pom au u poslu, uglavnom radei u svojim kunim kancelarijama.
U prolo vreme, m orao bih da iznajmim prilino veliki kancelarijski prostor gde bih sme-
stio sve te ljude, ali zahvaljujui Mrei, ekspres poti i telefonu, koristim njihovu pomo
bez tih dodatnih trokova. Tokom m ojih pokuaja da nauim da se lepo igram sa ostali-
ma svi vi ste bili veom a susretljivi, i nadam se da u i dalje bolje raditi svoj posao uz tuu
pomo. Paula Steuer je neprocenjiva zato to je preuzela m oju ofrlje poslovnu praksu i
postavila je na zdrave temelje (hvala Paula, to mi ne da mira kada me mrzi da neto ura-
dim ). Jonathan Wilcox, Esq. proeljao je struk turu mog preduzea, prevrnuo svaki ka-
men ispod kojeg se m oda kriju korpioni i naterao nas da proem o kroz postupak
pravno valjanogorganizovanja. Hvala ti na staranju i upornosti. Sharlynn Cobaugh je na-
pravila od sebe strunjaka za obradu zvuka i postala je bitan deo tim a za pravljenje mul-
timedijskih kurseva, kao i za reavanje drugih problema. Hvala na upornosti koju
pokazuje suoena s nepredvidivim raunarskim problem im a. Ljudi iz prake firme
Amaio izvukli su m e iz neprilika u nekoliko projekata. Daniel W ill-Harris me je prvi
upoznao s radom preko Interneta, a i glavni je dizajner svih grafikih reenja.
Tokom mnogih godina, Gerald VVeinberg je putem svojih konferencija i radioriica
postao moj nezvanini trener i m entor, na emu mu zahvaljujem.
Ervin Varga mi je izuzetno m nogo pom ogao svojim tehnikim ispravkama 4. izdanja
- iako su drugi pomagali u pojedinim poglavljima i prim erim a, Ervin je bio osnovni
tehniki recenzent cele knjige, a preradio je i vodi s reenjima za 4. izdanje. Ervin je
pronaao greke i uneo poboljanja u knjigu koja su nemerljiv doprinos ovom tekstu.
Njegova temeljnost i panja koju obraa na pojedinosti zauujue su, i on je najbolji re-
cenzent kog sam imao. Hvala ti, Ervine.
Moj blog na lokaciji www.Artiiiia.coin Bila Vennersa bio je izvor pom oi kada sam
traio tua miljenja. Hvala itaocima koji su mi slali kom entare na osnovu kojili sam
razjasnio pojmove - to su James VVatson, Hovvar Lovatt, Michael Barker i drugi, poseb-
no oni koji su pomogli s generikim tipovima.
Hvala Marku VVelshu na njegovoj stalnoj pomoi.
Evan Cofskv mi stalno prua veliku podrku svojim poznavanjem (napamet!) svih
zam renih pojedinosti o podeavanju i odravanju Web servera na Linuxu. On se stara da
MindVievvov server bude podeen i bezbedan.
6 Misliti na Javi
Posebno hvala m om novom prijatelju, kafi, koja mi je ulila gotovo neogranien entu-
zijazam za ovaj projekat. Kafi Camp4 u gradu Crested Butte u Koloradu bio je stalno
sastajalite ljudi koji su dolazili na MindVievvove seminare, a tokom sem inarskih odm ora
pruao nam je najbolju opskrbu hranom i piem koju sam ikada dobio. Hvala mom
drugaru Alu Smithu to ga je stvorio i od njega napravio tako zanimljivo i zabavno mesto.
I svim barm enim a kafia koji tako veselo toe pie.
Hvala ljudima u Prentice Hallu na tolerantnosti i ogrom nom strpljenju kojim mi
obezbeuju sve to traim.
Odreene alatke su se pokazale nezamenljivim tokom procesa razvoja program a i ja
osetim veliku zahvalnost prema njihovim stvaraocima svaki put kada ih upotrebim . Cyg-
win (www.cygwin.com) reio mi je bezbroj problem a koje W indows nee/ne moe, svakog
dana sam m u sve vie privren (da sam ga sam o imao pre 15 godina kada je moj mozak jo
bio ,,zalemljen za GNU Emacse). IBM-ov Eclipse (www.eclipse.org) zaista je divan dopri-
nos zajedni projektanata softvera, pa oekujem da e i ubudue davati velike rezultate,
poto se i dalje razvija. (Od kad je to IBM postao kul? M ora da mi je neto promaklo.) Jet-
Brains IntelliJ Idea nastavlja da kri nove kreativne puteve m eu razvojnim alatkama.
Na ovoj knjizi poeo sam da koristim Sparxsystemsov Enterprise Architect i on je brzo
postao m oja omiljena UML alatka. U raznim prilikam a dobro je posluio form ater koda
Jalopy Marca Hunsickera (www.triemax.com), a Marco je bio veoma susretljiv i konfigu-
risao ga prem a mojim specifinim potrebam a. Katkada je bio koristan i JEdit Slava Pesto-
va ( www.jedit.org) sa svojim softverskim dodacim a, i to je sasvim dobar editor za
poetnike na seminarima.
1 naravno, ako to nisam ve dovoljno puta rekao na svim moguim mestim a, za rea-
vanje problem astalnokoristim Pvthon ( www.Pytlion.org). On je delo m o g drugara Guida
Van Rossuma i grupe uvrnutih genija s kojima sam trao nekoliko divnih dana (Tim e Pe-
tersu, uram io sam mia kojeg si pozajmio i zvanino ga nazvao TimBotM i"). Vi, m om -
ci, treba da nadete neko zdravije mesto za ruak. (Takoe, hvala celoj Pvthon zajednici,
oni su fenom enalna gomila ljudi.)
Mnogi su mi slali ispravke i svima sam dunik, ali posebnu zahvalnost zasluuju (za prvo
izdanje): Kevin Raulerson (koji je pronaao obilje sjajnih bubica), Bob Resendes (zaista ne-
verovatan), (ohn Pinto, Joe Dante, Joe Sharp (sva trojica su bili udesni), David Combs
(tnnoge gramatike ispravke i razjanjenja), dr Robert Stephenson, John Cook, Franklin
Chen, Zev Griner, David Karr, Leander A. Stroschein, Steve Clark, Charles A. Lee, Austin
Maher, Dennis P. Roth, Roque Oliveira, Douglas Dunn, Dejan Risti, Neil Galarneau, Da-
vid B. Malkovsky, Steve VVilkinson i mnogi drugi. Prot. dr Marc Meurrens uloio je veliki
n ap o rd a u Evropi objavi i uitii dostupnom elektronsku verziju prvog izdanja knjige.
Hvala svitna koji su mi pomogli da ponovo napiem prim ere uz korienje biblioteke
Swing (za 2. izanje) i za svu drugu pomo. To su Jon Shvarts, Thom as Kirsch, Rahim
Adatia, Rajesh Jain, Ravi M anthena, Banu Rajamani, Jens Brandt, Nitin Shivaram, Mal-
colm Davis i svi koji su tni daii podrku.
U 4. izdanju, Chris G rinstaff je m nogo pom ogao tokom razvoja odeljka o SVVT-u, a
Sean Neville je za mene napisao prvu verziju odeljka o Flexu.
Predgovor 7
Kad god pomislim da sam najzad sve nauio o program iranju za paraleleno izvra-
vanje, otvore se neka nova vrata i pokae se da im a jo planina koje m oram prei. Hvala
Brianu Goetzu to mi je pom ogao da savladam sve prepreke u novoj verziji poglavlja Pa-
ralelno izvravanje i to je otkrio (nadam se!) sve greke.
Nije iznenaenje to mi je poznavanje Delphija pom oglo da razum em Javu, budui da
ta dva jezika imaju puno zajednikih koncepata i dizajnerskih reenja. Moji prijatelji koji
se bave Delphijem pom ogli su mi da proniknem u unutranjost tog sjajnog programskog
okruenja. To su Marco Cantu (jo jedan Italijan: da li dobro poznavanje latinskog dopri-
nosi sklonosti ka program skim jezicima?), Neil Rubenking (koji se bavio jogom, vegeta-
rijanstvom i zenom dok nije-otkrio raunare) i, naravno, Zack Urlocker (prvi direktor
projekta Delphi), stari prijatelj s kojim sam proputovao svet. Svi mi sm o dunici briljant-
nom A ndersu Hejlsbergu, koji se i dalje mui sa C#-om (a taj jezik je bio glavni uzor za
Javu SE5, u ta ete se uveriti u knjizi).
Moj pronicljivi prijateij Richard Hale Shaw pruio mi je vrlo korisnu podrku (i Kim
takoe). Richard i ja smo proveli vie meseci zajedno, drei seminare, pokuavajui da
osm islim o savren m etod uenja za polaznike.
Dizajn knjige, dizajn korica i sliku na koricam a uradio je moj priiatelj Daniel Will-
Harris, priznati autor i dizajner ( www.Will-Harris.com), koji se igrao sa samolepljivim
slovima u osnovnoj koli dok je ekao da raunari i stono izavatvo budu otkriveni, i koji
se alio na moje gunanje zbog algebarskih problem a. Ipak, knjigu sam sloio sam tako
da sve greke u slaganju idu na moj raun. Pisao sam u M icrosoftovom W ordu XP, a fo-
toslog je priprem ljen u Adobeovom Acrobatu. Desilo se da sam bio u inostranstvu oba
puta kada sam pravio finalnu verziju knjige - prvo izdanje sam slao iz Kejptauna u Junoj
Africi, a drugo iz Praga (to je moj doprinos eri elektronike). Tree i etvrto sam poslao iz
Creste Butta u Koloradu. Font korien na koricam a je ITC Rennie Mackintosh.
Posebno zahvaljujem svojim uiteljima i svim svojim studentim a (koji su istovremeno
i moji uitelji).
Dok sam radio na ovom izdanju, u krilu mi je esto leala maka Mollv i tako davala
svoju toplu, krznenu podrku.
Listu prijatelja koji su me podravali ine izmedu ostalih i: Patty Gast (izvanredna ma-
serka), Andrew Birnstock, Steve Sinofskv, (D Flildebrandt, Tom Keffer, Brian McElhin-
ney, Brinklev Barr, Liill Gates iz asopisa M idnight Engineering, Larry C onstantine i Lucv
Lockvvood, Gene Wang, Dave Mayer, David Intersim one, Chris i Laura Strand, porodica
AImquist, Brad Jerbic, Marilvn Cvitanic, M ark Mabry, porodice Robbins, porodice Mo-
elter (i McMillan), Michael Wilk, Dave Stoner, porodica Cranston, Larry Fogg, Mike Se-
queira, Cary Entsminger, Kevin i Sonda D onovan, Joe Lordi, Dave i Brenda Bartlett, Patti
Gast, Blake, Annette i Jade, porodica Rentschler, porodica Sudek, Dick, Patty i Lee Eckel,
Lvnn i Todd i njihove porodice. I, naravno, moji m ania i tata.
Uvod
oveku je dao jezik, a jezik je stvorio misao, koja jc mera Univerzuma Osloboeni Pro-
metej, eli
Ljudska bia... sasvim su pod vlau odreenog jezika koji je postao sredstvo izraavanja u nji-
hovotn drutvu. U zabludi je ko misli da u prilagodavanju pojedinca stvarnosti jezik ne igra
znaajnu ulogu i da je jezik samo sluajno sredstvo reavanja specifinih problema optenja i
miljenja. injenica je da je stvarni svet u velikoj meri nesvesno izgraden na osnovu jezikih
navika grupe.
Status lingvistike kao nauke, Edvard Sapir 1929.
Preduslovi
U ovoj knjizi podrazumeva se da koliko-toliko poznajete programiranje: shvatate da je pro-
gram skup naredaba, poznajete princip potprogram a/tunkcije/m akroa, kontrolnih struk-
tura kao to je ,,if konstrukcija za petlje kao to je vvhile" itd. Sve ovo ste mogli nauiti na
raznim mestima, recimo pri program iranju na nekom makro-jeziku ili pri radu sa alatom
kao to je Perl. Bez obzira na to koliko ste u dosadanjem programiranju ovladali osnovnim
idejama, moi ete da radite po ovoj knjizi. Naravno, kniiga e biti laka C programerima,
i jo vie C ++ program erim a, ali ne otpisujte sebe ako nemate iskustva u ovim jezicima -
samo budite sprem ni da naporno radite. Takode, uz pomo multimedijalnog seminara
Thinking in Ckoji moete preuzeti s Iokacije mvw.MiudView.net, ovladaete u potpunosti
osnovama potrebnim za uenje Jave. Kroz knjigu u postepeno uvoditi koncepte objektno
orijentisanog program iranja (OOP) i osnovnih Javinih kontrolnih ntehanizama.
Cesta pozivanja na osobine jezika C i C ++ ni.su kom entari poznavaoca, ve su pomo
program erim a da uporede Javu s tim jezicima iz kojih je potekla. Trudiu se da ta po-
reenja budu jednostavna i objasniu sveto mislim da ne zna neko ko ne koristi C/C++.
Uvod 9
Uenje Jave
O tprilike u isto vreme kada se pojavila moja prva knjiga, Using C++ (Osborne/McGravv-
Hill, 1989), poeo sam da predajem taj jezik. Predavanje program skih jezika postala je
m oja profesija: gledao sam glave koje klimaju, bele poglee i zbunjene izraze u publici i-
rom sveta jo od 1987. Kada sam poeo privatno da obuavam m anje grupe Ijudi, tokom
vebi sam otkrio da mnoga pitanja zbunjuju ak i one koji su se smeili i klimali glavom.
Vie godina predsedavao sam na odseku za C ++ na Konferenciji za razvoj softvera (ka-
snije i na odseku za Javu), i prim etio sam kako sm o i ja i drugi govornici sldoni da pro-
senoj publici serviramo p reV ie informacija za kratko vreme. Zbog razliitih nivoa
publike i naina na koji sam predstavljao materijal, na kraju bih izgubio deo slualaca.
M oda previe traim , ali poto oseam otpor prem a tradicionalnom nainu predavanja
(a verujem da veina slualaca takav otpor osea zbog dosade), pokuao sam da uinim da
m oja predavanja nikom e ne budu dosadna.
Jedno vreme sam pravio dosta raznih prezentacija u relativno kratkom periodu. Tako
sam doao u situaciju da uim m etodom pokuaja i pogreaka" (to je dobar nain i za
projektovanje program a). Na kraju sam iskoristio sve to sam nauio kao predava- i na-
pravio kurs koji bih rado drao due vreme. Sada ovaj kurs drim na javnim i privatnim
sem inarim a o Javi; to je moj glavni uvodni seminar, koji prua osnovu za naprednije se-
m inare. O tim sem inarim a moete saznati vie na adresi www.MindView.net. (Uvodni se-
m inar je dostupan i u obliku CD-a Hands on Java. Podaci o njem u su na istoj Web
lokaciji.)
Povratne informacije koje dobijam na svakom sem inaru pom au mi da m enjam i pre-
raujem materijal sve dok nc zakliuim da je podesan kao sredstvo pouavanja. Ovu knji-
gu ne ine samo beleke sa seminara: u nju sam pokuao da spakujem to vie inform acija
i spojio sam ih tako da vas vode od jednog do drugog predmeta. Zamislio sam da ova knji-
ga slui usam ljenom itaocu koji se bori s novim program skim jezikom.
Ciljevi
Kao i moja prethodna knjiga, Misliti na jczikit C++, i ova knjiga je pisana u skladu s na-
inom na koji Ijudi ue jezik Java. Poglavlje u knjizi zamiljao sam kao jednu dobru lek-
ciju na sem inaru. Povratne intormacije od slualaca na sem inarim a pom ogle su mi da
otkrijem koji su delovi tei i zahtevaju dodatna objanjenja. U oblastim a gde sam bio pre-
am biciozan i uvrstio previe novih pojmova odjednom , spoznao sam - kroz proces pri-
kaza materijala - da vie novih pojmova zahteva vie objanjavanja, a to lako zbunjuje
sluaoca.
Cilj svakog poglavlja je da savladate jedan pojam , ili m anje grupe povezanih pojmova,
bez obzira na sve ostalo to se tu pominje. Na taj nain moete da prihvatite svaki eli
teorije, u zavisnosti od vaeg dotadanjeg znanja, pre nego to produite dalje.
10 Misliti na Javi
Dokumentacija na Webu
Jezik Java i njegove biblioteke iz Sun Microsystemsa (besplatno se preuzim aju s Weba)
im aju okum entaciju u elektronskom obliku, kojoj moete pristupati koristei ita We-
ba; gotovo svaka druga nezavisna distribucija Jave ima takav ili slian sistem dokum enta-
cije. U veini knjiga o Javi kopira se taj sistem. Stoga takvu dokum entaciju ili ve imate,
ili je m oete preuzeti s Weba, i ukoliko to zaista nije neophodno, u ovoj knjizi je neemo
ponavljati. O bino m nogo bre moete da naete opis neke klase pom ou itaa Weba,
nego da ga traite po knjizi (a dokum entacija na Webu je verovatno aurnija). Jednostav-
no u vas uputiti nadokum entaciju JDK-a. O vaknjiga e obezbediti dodatne opise klasa
samo kada je neophodno dopuniti dokum entaciju da biste shvatili odredeni prim er.
Vebe
Prim etio sam da jednostavne vebe pom au studentim a da shvate seminarsko gradivo, pa
dajem nekoliko vebi na kraju svakog poglavlja.
Vei broj vebi moe relativno lako i u razum nom roku da se uradi u uionici, pod
nadzorom instruktora koji proverava da li su svi studenti usvojili izloenu m ateriju. Neke
vebe su malo izazovnije, a li nijedna nije nereiva.
Reenja izabranih vebi nalaze se u elektronskom dokum entu pod im enom Thc Thin-
king iu java Annotatcd Solution Guide, koji se moe kupiti na lokaciji www.Mind-
Vicw.com.
Javini temelji
Sa ovom knjigom dobijate i besplatan m ultim edijalni sem inar koji moete preuzeti sa
w w w .M in dV iew .L O in . To je sem inar T h i n k in g in C, koji vas uvodi u sintaksu, operatore i
funkcije jezika C na osnovu kojih je Java napravljena. U prethodnim izdanjima ove knjige
na engleskom, to se nalazilo na CD-u Foundations for Java, ali sada se moe besplatno
preuzeti.
Prvobitno sam od Chucka Allisona naruio da napravi Thinking in C k ao nezavisan
proi/.vod, aii sam odluio da ga priloim uz drugo izdanje knjige Thinkingin C++ i drugo
i tree izdanje knjige Thinking in Java, poto su mi na sem inar stalno dolazili Ijudi bez do-
voljnog poznavanja osnovne sintakse C-a. Izgleda da takva osoba misli: ,,Ja sam pam etan
program er i neu da uim C, nego C ++ ili Javu, pa u C preskoiti i odm ah prei na C + + /
Javu. Po dolasku na seminar, ljui polako shvataju da sam imao veoma dobar razlog to
sam poznavanje C-a proglasio za preduslov za pohaanje.
Tehnologije se menjaju, i bilo je bolje preraditi Thinking in C u Flash prezentaciju koja
se moe preuzeti sa Interneta, nego prilagati ga na CD-u. Poto je taj seminar na Inter-
netu, svi mogu dobro da se priprem e prc nego to dou na moj seminar.
Sem inar Thinking in C i ovoj knjizi pribavlja veu publiku. Iako njena poglavlja Ope-
ralori i Kontrolisanjc izvravanja obuhvataju osnove Jave koje potiu iz C-a, mreni semi-
nar postepenije uvodi itaoca, a za njega je potrebno jo manje program erskog
predznanja nego za knjigu.
12 Misliti na Javi
Izvorni kod
Kompletan izvorni kod iz ove knjige dostupan je kao slobodan softver zatien autorskim
pravom, u jednom paketu, na adresi www.MindView.net. Ovo je zvanina Web lokacija za
distribuciju koda i elektronskog izdanja knjige, pa m oete biti sigurni da ete tu uvek nai
najnoviju verziju. Kod m oete deliti i koristiti u uionicam a i u druge obrazovne nam ene.
Osnovni cilj zadravanja autorskog prava jeste da se poreklo koda ispravno navede i da
se sprei objavljivanje koda u tam panim medijim a bez dozvole. (Ukoliko je poreklo koda
ispravno navedeno, prim eri iz knjige m ogu se navoditi u veini medija.)
U svakoj datoteci sa izvornim kodom nai ete sledeu napom enu o autorskim pravi-
ma (obino na engleskom):
//:! A u t o r s k a P r a v a . t x t
Ovaj rau n a r s k i iz vorni kod z a t i e n j e a u t o r s k i m p r a v i m a (c)2006 MindView,
Inc.
Sva pra v a zadrana.
3. D o z v o l u za k o r i e n j e I z v o r n o g ko da u t a m p a n i m m e d i j i m a m o e t e pr i b a v i t i
ako se o b r a t i t e na adresu:
Ako m i s l i t e da s te u I z v o r n o m kodu p r o n a l i g r e k u , m o l i m v as da i s p r a v k u
poaljete preko sistema povratnih informacija koji m o e t e pr onai na lo ka ci ji
www.MindView.com.
///:-
Kod moete koristiti u svojim nastavnim projektim a (ukljuujui i vae materijale za
prezentaciju), dokle god zadravate poruku o autorskim pravim a koja se pojavljuje u sva-
koj izvornoj datoteci.
Ova knjiga se zasniva na Javi SE5/6, i na njoj je i testirana. Ako hoete da nauite neto
o ranijim varijantama jezika, a to nije obuhvaeno ovim izdanjem, prvo, drugo i tree iz-
danje knjige (na engleskom) moete besplatno preuzeti s lokacije www.MindView.net.
Greke
Bez obzira na to koliko trikova pisac koristi da otkrije greke, neke se uvek provuku, a nov
italac ih esto odm ah primeti. Ako otkrijete bilo ta to sm atrate grekom, m olim vas da
iskoristite hipervezu za ovu knjigu na lokaciji www.MindView.net, prijavite greku i
poaljete predlog za ispravku. Ceniu vau pomo.
Upoznavanje sa objektima
Prirodu parceliemo i razvrstavamo u koncepte kojima pripisujemo znaenja, uglavnom
zato to se drimo dogovora koji vai u naoj jezikoj zajednici i kodifikovan je u obrascima
naeg jczika ... uoptc nc moetnogovoriti ukoliko se nepridravamo organizacije i klasifika-
cije podataka koje taj dogovorpropisuje. Benjamin Lee W h o rf ( 1897-1941)
R a u n a r s k a REVOLUCIj'A je n a s t a l a u m a S in i. N a S i p r o g r a m s k i je z ic i s t o g a t e e d a
izgledaju kao ta maina.
Ali raunari nisu toliko maine koliko pojaala um a (tokovi za um kako Steve Jobs
voli da kae) i drugi nain izraavanja. Zbog toga ti alati sve m anje lie na maine, a sve
vie na delove naeg uma, i na druge oblike izraavanja, kakvi su pisanje, slikanje, vajanje,
anim iranje i snim anje filmova. O bjektno orijentisano program iranje (OOP) deo je ovog
pom eranja ka korienju raunara kao sredstva izraavanja.
Ovo poglavlje vas uvodi u osnovne koncepte OOP-a, ukljuivi i pregled m etoda raz-
voja, uz pretpostavku da imate iskustva s program iranjem , iako to ne m ora biti na jeziku
C. Ako mislite da treba da se jo priprem ate za program iranje pre nego to se uhvatite u
kotac sa ovom knjigom, prouite multimedijski sem inar Thinking in C, koji moete
preuzeti na adresi mvw.MitidView.net.
Ovo pogtavlje je i podloga i dodatni materijal. M nogi se ne oseaju prijatno u svetu
ol>iektno orijentisanog program iranja ako pre toga ne razum eju celinu. Stoga je ovde dat
bogat pregled koncepata OOP-a. Drugi ne mogu da shvate glavne principe dok prvo ne
upoznaju barem neke mehanizme. Ako pripadate toj grupi i etjni ste da otkrijete speci-
finosti jezika, slobodno preskoite ovo poglavlje - u ovom trenutku to vas nee spreiti
da piete program e ili nauite jezik. M eutim, poeleete da se vratite na ovaj deo knjige
da biste dopunili svoje znanje i shvatili zato su objekti vani i kako da ih koristite pri
pisanju programa.
Razvoj apstrakcije
Svi programski jezici obezbeuju apstrakoiju. Moglo bi se raspravljati o tom e da li je slo-
enost problema koje ste u stanju da reite direktno povezana s vrstom i kvalitetom ap-
strakcije. Pod vrstom" mislim na to ta apstrahujete. Mainski jezik je mala apstrakcija
maine na kojoj se programi izvravaju. Mnogi takozvani ,,proceduralni jezici koji su sle-
dili mainski (kao FORTRAN, RASIC i C) bili su apstrakcija mainskog jezika. Ovi jezici
su veliki napredak u odnosu na mainski jezik, ali njihova prim arna apstrakcija ipak za-
hteva od vas da razmiljate iz ugla strukture raunara um esto iz ugla probiem a koji rea-
vate. Program er mora da uspostavi vezu izmedu modela tnaine (u prostoru reenja
koji predstavlja mesto gde realizujete reenje problem a, na prim er, u raunaru) i modela
problem a koji se reava (u prostoru problema" koji predstavlja mesto gde problem po-
stoji, recimo poslovanje). Napor koji iziskuje ovo preslikavanje i injenica da je ono ne-
bitno za programski jezik proizvode program e koji se teko piu i ije je odravanje
skupo, a kao sporedni elekat nastaje celokupna industrija program skih metoda".
16 Misliti na Javi
5. Svi objekti odreenog tipa m ogu da primaju iste poruke. Ovo je, u stvari, vie-
znana izjava, kao to ete kasnije videti. Kako je objekat tipa ,,krug istovremeno
objekat tipa ,,oblik, krug e zasigurno moi da prim a poruke za oblik. To znai da
moete da napiete kod koji kom unicira sa oblicima i autom atski podrava i sve
drugo to potpada pod opis oblika. Ova zamenljivost je jedna od najm onijih oso-
bina OOP-a.
Booch daje jo krau definiciju objekta:
O bjekat im a stanje, ponaanje i identitet.
To znai da objekat m oe imati interne podatke (koji definiu njegovo stanje) i m etode
(koje definiu njegovo ponaanje), i da je svaki objekat jedinstven (razlikuje se od svih
drugih objekata) - konkretno, svaki objekat im a jedinstvenu adresu u m em oriji.2
Poto klasa opisuje skup objekata koji imaju identine karakteristike (elementi s po-
dacima) i jednako se ponaaju (funkcionalnost), klasa ie zaista tip podatka, jer i broj u
form atu pokretnog zareza, na prim er, takoe im a skup karakteristika i ponaanja. Razlika
je u tom e to program er definie klasu koja odgovara problem u, um esto da bude prinu-
en da koristi postojei tip koji predstavlja m em orijsku jedinicu unutar raunara. Pro-
gramski jezik proirujete dodavanjem novih tipova podatka, specifinih za vae potrebe.
Programski sistem prihvata nove klase, o njim a vodi rauna i proverava tipove, kao to
radi i sa ugraenim tipovima.
O bjektno orijentisan pristup ne ograniava se sam o na pravljenje simulacija. Bez ob-
zira na to da li se slaete sa stavom da je svaki program simulacija sistema koji projektu-
jete, upotrebom tehnika, O O P-a veliki skup problem a lako se moe da svesti na
jednostavna reenja.
Kada se klasa ustanovi, moete da napravite koliko god elite objekata te klase, a zatim
da radite s tim objektim a kao da su elementi u problem a koji pokuavate da reite. Zaista,
jedan od izazova objektno orijentisanog program iranja jeste ostvarivanje jednoznanog
preslikavanja izm eu elemenata u prostoru problem a i objekata u prostoru reenja.
Kako da naterate objekat da uradi koristan posao? M ora postojati nain da postavite
zahtev objektu da neto uradi, na prim er, da zavri transakciju, iscrta neto na ekranu ili
ukljui prekida. A svaki objekat moe da zadovolji samo izvesne zahteve. Zahtevi koje
moete da postavite objektu efinisani su preko njegovog interfcjsa, koji je odreen
tipom . Prost prim er bi mogla biti sijalica:
Ime tipa
Interfejs
S i j a l i c a sj = n ew S i j a l i c a ( ) ;
sj .ukl juci ();
pozovete nevv, ime zahtevate novi objekat tog tipa. Da biste poslali poruku objektu, na-
vedite ime objekta i poveite ga s porukom - zahtevom, razdvajajui ih takom. S take
gledita korisnika unapred definisane klase, to je skoro sve to vam treba da biste progra-
m irali sa objektima.
Gornja slika je napravljena u skladu s form atom koji koristi unifikovani jezik za mode-
lovanje (engl. Unified Modeling Languagc, UML). Svaka klasa je predstavljena pravouga-
onikom , ime tipa je u gornjem delu, podaci lanovi koje treba opisati nalaze se u srednjem
delu, a u donjem delu pravougaonika su metode (funkcije koje pripadaju tom objektu,
koje prim aju poruke koje aljete tom objektu). esto se u UML dijagramima prikazuju
sam o im e klase i javne m etode, a srednji deo ne tako je i na prethodnoj slici. Ako vas za-
nim a sam o ime klase, nem a potrebe da prikazujete ni donji deo.
Jako ete pojednostaviti sebi ivot ako objekte budete sm atrali davaocima usluga. To e
koristiti ne sam o vama tokom procesa projektovanja, nego i drugim a koji b u d u pokua-
vali da razum eju va kod ili upotrebe neki od vaih objekata. Ako b u d u mogli da utvrde
vrednost objekta na osnovu usluge koje on prua, bie im m nogo lake da ga uklope u
svoje projekte.
Skrivena realizacija
Vrlo je korisno podeliti polje delatnosti na autore klasa (one koji prave nove tipove poda-
taka) i programere klijente4 (korisnike klasa koji te tipove upotrebljavaju u svojim aplika-
cijama). Cilj program era kJijenta je da sakupi klase u kutiju sa alatom", koju e koristiti
za brzi razvoj aplikacija. Cilj autora klasa je da napravi klasu koja otkriva sam o ono to je
neophodno program eru klijentu, a sve ostalo dri sakriveno. Zato? P rogram er Idijent ne
moe da koristi sakrivene delove, to znai da autor klase m oe da prom eni skriveni deo
kad god hoe, ne razmiljajui da li e se to odraziti na ostale. Skriveni deo obino pred-
stavlja osetljivu unutranjost objekta koju lako moe da oteti neobazriv ili neobaveten
program er ldijent, pa sakrivanje realizacije sm anjuje m ogunost da se pojave greke u
program im a.
U svakom odnosu je vano da sve ukljuene strane potuju granice. Kada pravite bi-
blioteku, vi stvarate odnos sa kJijentom koji je takoe program er, ali koji sastavlja aplika-
ciju koristei vau biblioteku, da bi, moda, napravio veu biblioteku.
Ako bi svi lanovi klase bili dostupni svakome, onda bi program er klijent mogao da
uradi bilo ta s klasom i ne bi postojao nain da se nam etnu pravila. Jako biste vi voleli da
program er Jdijent ne radi direktno s nelcim lanicama vae klase, bez kontrole pristupa ne
bi postojao nain da to spreite. Sve bi bilo izloeno javnosti.
Stoga je prvi razlog za uvoenje kontrole pristupa onem oguavanje program era kli-
jenta da pristupa delovima koje ne sme da dira, a koji su neophodni za interni rad s tipom
podataka. Ti delovi nisu deo interfejsa koji je potreban korisnicim a za reavanje njihovih
problem a. Ovo je u isto vreme usluga program erim a klijentima, jer lako rnogu da razlue
ta je za njih vano, a o emu ne treba da misle.
Kontrolu pristupa treba uvesti i da bi se dozvolilo projektantu biblioteke da prom eni
nain na koji klasa interno radi, a da ne m ora da brine kako e se to odraziti na progra-
mere klijente. Na primer, moete realizovati neku klasu na jednostavan nain, a kasnije
otkriti da je treba ponovo napisati kako bi radila bre. Ako su interfejs i realizacija jasno
razdvojeni i zatieni, ovo moete lako da izvedete.
Java koristi tri rezervisane rei da postavi granice un u tar klase: public, private i pro-
tected. Ovi specifikatoripristupaodreuju ko moe da koristi definicije koje slede iza njih.
public (javni) znai da je naredni elem ent dostupan svakome. Rezervisana re private
(privatni) znai da tom elementu ne moe da pristupi niko sem autora klase, unutar me
toda tog tipa. private predstavlja zid izmeu autora i program era klijenta. Onaj ko poku
a da pristupi lanici oznaenoj kao private, izazvae greku prilikom prevodenja.
Rezervisana re protected (zatieni) deluje kao private, s tom razlikom to klase nasled-
nice im aju pristup zatienim lanicama, ali ne i privatnim lanicama. O nasleivanju
emo govoriti uskoro.
Java ima i ,,podrazum evani pristup koji se koristi ako ne zadate nijedan od navedenih
specifikatora. Ovo se obino naziva paketskipristup, jer klase m ogu da pristupe lanicama
drugih klasa u istom paketu, ali izvan tog paketa te iste lanice vide se kao privatne.
(Na ovom UML dijagram u kompoziciju oznaava popunjen romb, koji kazuje da po-
stoji jedan auto. Kad oznaavam spajanje, obino u koristiti jednostavniji oblik: sam o li-
niju, bez rom ba.)1
Kompozicija je vrlo fleksibilna. Objekti lanovi vae nove klase obino su privatni, to
ih ini nedostupnim program erim a Idijentima koji koriste klasu. Ovo omoguava da iz-
menite te lanove ne remetei postojei klijentski kod. Moete m enjati objekte lanove i
u vreme izvravanja da biste dinamiki menjali ponaanje svog program a. Nasleivanje
koje malo dalje opisujemo, nem a ovu fleksibilnost poto prevodilac m ora da ugradi ogra-
nienja za prevoenje u klase stvorene nasleivanjem.
Poto je nasledivanje veoma bitno, u objektno orijentisanom program iranju esto se
veoma naglaava, i nov program er moe pom isliti da nasleivanje treba koristiti svuda.
Kaii rezultat moe se dobiti veoma nezgrapan i veoma sloen program . Umesto toga, prvo
treba videti da li pri pravljenju novih klasa moe da se iskoristi kompozicija, poto je ona
jednostavnija i fleksibilnija. Ako prim enite ovaj pristup, program e biti istiji. Kada stek-
nete neto iskustva, bie vam oigledno kada treba da koristite nasleivanje.
Nasleivanje
Sam po sebi, koncept objekta je veoma koristan. On omoguava da podatke i funkcional-
nost grupiete po konceptu, tako da moete prestaviti odgovarajuu ideju u prostoru
problem a, um esto da budete prinueni da koristite izraze raunara na kome radite. Kada
se prim eni rezervisana re class, te ideje su izraene kao osnovne jedinice u ovom pro-
gram skom jeziku.
Bila bi teta da se nam uite i napravite neku klasu a da onda budete prim orani da pra-
vite p otpuno novu klasu koja im a slinu funkcionalnost. Bilo bi jednostavnije da uzme-
m o postojeu klasu, da je kloniram o, a zatim dopunjujem o i m enjam o kloniranu klasu.
Ovo se zapravo postie nasleivanjem (engl. inheritance), osim kada se originalna klasa
(koja se naziva osnovna klasa ili natklasa ili klasa roditelj) izmeni, a te izmene se odraze i
na ,,klonu (koji se naziva izvedena ili nasleena klasa ili potklasa ili klasa naslednik; engl.
derived class).
(Strelica u ovom UML dijagram u polazi od izvedene klase ka osnovnoj klasi. Kao to
ete videti, moe da postoji vie izvedenih klasa.)
Tip ne oznaava samo ogranienja skupa objekata; on ima odnose i s drugim tipovi-
ma. Dva tipa m ogu imati neke zajednike karakteristike i jednako se ponaati, ali pri tom
jedan tip moe imati jo neke dodatne karakteristike i moe obraivati vie poruka (ili ih
drugaije obradivati). Kod nasleivanja, ova slinost izmeu tipova se izraava preko
koncepta osnovnih i izvedenih tipova. Osnovni tip sadri sve karakteristike i ponaanja
koja su zajednika za tipove izvedene iz njega. Pravei osnovni tip, izraavate sutinu svo-
jih ideja o nekim objektim a u sistemu. Iz osnovnog tipa izvodite ostale tipove i pokazujete
razliite naine realizacije ove sutine.
Na prim er, maina za recikliranje rasporeuje komadie otpada. Osnovni tip je ,,ot-
pad a svaki pojedini otpadak ima teinu, vrednost itd. i moe biti iseen, istopljen ili ra-
stavljen. Iz osnovnog tipa izvodimo posebne vrste otpada s dodatnim karakteristikama
(boca im a boju), ili ponaanjim a (alum inijum ska konzerva moe da se zdrobi, eline
konzerve privlai magnet). Ponaanja mogu biti razliita (vrednost papira zavisi od nje-
gove vrste i stanja). Koristei nasledivanje moete izgracliti hijerarhiju tipova. Ta hijerar-
hija opisuje problem koji pokuavate da reile preko tipova koji se u problem u pojavljuju.
Drugi prim er je klasian ,,oblik koji moe da se koristi u CAD sistemu (engi. Compu-
ter-Aided Design) ili u nekoj kom pjuterskoj igri. Osnovni tip je ,,oblik a svaki oblik ima
veliinu, boju, poziciju itd. Svaki oblik moe da se iscrta, obrie, pom era, oboji itd. Odav-
de izvodimo (nasledujem o) pojedine vrste oblika - krug, kvadrat, trougao i druge - od
Poglavjje 1: Upoznavanje sa objektima 23
kojih svaki moe imati dodatne karakteristike i ponaanje. Neki oblici, na prim er, m ogu
da se okreu. Neka ponaanja m ogu biti drugaija, recimo kada elite da izraunate po-
vrinu oblika. H ijerarhija tipova objedinjuje slinosti i razlike izmeu oblika.
Predstavljanje reenja i problem a u istom obliku veoma je korisno jer vam ne treba ve-
liki broj m eum odela da biste od opisa problem a doli do opisa reenja. Kod objekata, hi-
jerarhija tipova je osnovni model tako da sa opisa sistema u realnom svetu direktno
prelazite na opis sistema kodom. Jedna od tekoa sa objektno orijentisanim program i-
ranjem jeste ta da je previe jednostavno stii od poetka od kraja. Um treniran da trai
sloena reenja esto spoetka zbunjuje ova jednostavnost.
Kada iskoristite nasleivanje iz postojeeg tipa, stvarate novi tip. Taj novi tip ne samo
da sari sve lanice postojeeg tipa (iako su privatne lanice sakrivene i neostupne),
ve, to je mnogo vanije, kopira interfejs osnovne klase. Znai, sve poruke koje moete
da poaljete objektima osnovne klase, takoe moete poslati i objektim a izvedene klase.
Poto se tip klase odreduje na osnovu poruka koje joj m oem o poslati, to znai da je iz-
vedena klasa istog tipa kao i osnovna klasa. U prethodnom prim eru krug je oblik. Ekvi-
valencija tipova dobijena nasledivanjem je osnovni korak na p utu ka razum evanju smisla
objektno orijentisanog program iranja.
Poto i osnovna klasa i izvedena klasa imaju isti osnovni interfejs, m ora da postoji rea-
lizacija koja ide uz taj interfejs. Znai, mora postojati kod koji se izvrava kada objekat
prim i odreenu poruku. Ako nasledite klasu i nita vie ne uradite, m etode interfejsa
osnovne klase e prei i u izvedenu klasu. To znai da objekti izvedene klase imaju i isti tip
i isto ponaanje, to i nije previe korisno.
Postoje dva naina da napravite raziiku izmeu svoje nove izvedene klase i osnovne
klase. Prvi je jasan: izvedenoj klasi dodate potpuno nove metode. Te nove m etode nisu
deo interfejsa osnovne klase, to znai da osnovna klasa nije radila sve ono to ste hteli, pa
ste joj zato dodali jo m etoda. Ovaj jednostavan nain korienja nasledivanja ponekad je
savreno reenje problem a. M edutim, paljivo prouite da li su i vaoj osnovnoj klasi po-
trebne te dodatne metode. Ovaj proces otkrivanja i iteracije program a redovna je pojava
u objektno orijentisanom program iranju.
24 Misliti na Javi
Relacije JE i JE-KAO
Moe se postaviti jedno pitanje o nasledivanju: ,,Da li nasleivanje treba da redefinie
samo m etode osnovne klase (i da ne dodaje nove m etode koje ne postoje u osnovnoj kla-
si)? To bi znailo da je izvedena klasa potpimo istog tipa kao osnovna klasa, jer ima isto-
vetan interfejs. Kao rezultat, objekat izvedene klase moe se svesti na tip objekta osnovne
klase. Ovo je tzv. ista supstitucija, ili princip supstitucije. Unekoliko, ovo je idealan nain
prim ene nasleivanja. U ovom sluaju, m i se esto pozivamo na relaciju izm eu osnovne
i izvedene klasekao na relaciju je, jer m oem o reikrug;eoblik. Pokuaj da utvrdim o da
li m oem o da uspostavim o relaciju je izm edu klasa, a da to ima smisla, predstavlja svoje-
vrstan test nasleivanja.
Ponekad m orate da dodate nove elemente u interfejs izvedenog tipa i tim e proirite
postojei interfejs. Novi tip i dalje m oe biti sveden na osnovni tip, ali supstituja nije sa-
vrena, jer nove m etode nisu dostupne iz osnovnog tipa. Ovo se moe opisati kao relacija
je-kao (moj term in). Novi tip ima interfejs starog tipa ali sadri i druge m etode, tako da
se ne moe rei kako je potpuno isti. Uzmimo za prim er ureaj za klimatizaciju. Pretpo-
stavim o da su po kui razvedene kontrole za hlaenje, odnosno, kua im a interfejs koji
om oguava da kontroliete hlaenje. Zamislite da se ureaj za klimatizaciju pokvari i da
ga zam enite toplotnom pum pom koja moe i da greje i da hladi. Toplotna pum pa je kao
ureaj za hlaenje, ali ona moe i vie. Poto je kontrolni sistem vae kue projektovan
sam o da kontrolie hlaenje, on je ogranien na kom unikaciju s delom za hlaenje novog
objekta. Interfejs novog objekta je proiren, a postojei sistem ne poznaje nita drugo
osim originalnog interfejsa.
Cim prouite ovaj plan, postae jasno da osnovna klasa sistem za hlaenje" nije do-
voljno opta i da treba da se preim enuje u sistem za kontrolu temperature", kako bi m o-
gla da sadri i grejanje - nakon ega bi princip supstitucije vaio. Ovaj dijagram prikazuje
ta u stvarnom svetu moe da se desi tokom projektovanja.
Kada upoznate princip supstitucije, lako moete pomisliti da je taj pristup (ista sup-
stitucija) jedini nain da se neto uradi, i zaista jeste dobro da program napravite na taj
nain. Ali shvatiete da u interfejs izvedene klase ponekad m orate da dodate nove metode.
Nakon to ispitate problem , trebalo bi da bude prilino oigledno o kojem se od ta dva
sluaja radi.
26 Misliti na Javi
v oid r a d i N e s t o ( O b l i k oblik) {
o b 1 i k.obri si S e ( ) ;
II ...
obli k.i s c r t a j S e ( ) ;
}
ta m etoda se obraa bilo kom O bliku, pa ne zavisi od specifinog tipa objekta koji se is-
crtava i brie. Ako u nekom drugom delu program a pozovemo funkciju radiN esto():
pozivi m etode radiN esto() autom atski rade ispravno, bez obzira na taan tip objekta.
28 Misliti na Javi
radiNesto(krug);
Ovde je Krug prosleden metodi koja oekuje Oblik. Poto Krug jeste Oblik, funkcija
radiNesto() moe tako da ga tretira. O dnosno, bilo koju poruku koju m etoda radiNe-
sto() m oe da poalje Obliku, Krug moe da prihvati. Zato je gornji poziv p o tp u n o sigu-
ran i logian.
Proces pri kome izvedeni tip tretiram o kao osnovni tip, nazivamo svoenje navie
(engl. npcasting). Ime castje iskorieno zato to oznaava ubacivanje u kalup (engl. ca-
sting into a tnold-ubacivan je u kalup), a up potie od naina na koji se obino organizuje
dijagram nasleivanja, sa osnovnim tipom na vrhu i izvedenim klasama koje se lepezasto
ire nanie. Prema tome, konverzija u osnovni tip je penjanje uz dijagram nasleivania:
svoenje navie ili upcasting.
U objektno orijentisanom program u uvek postoji svoenje navie, jer pri tom ne mo-
rate znati taan tip s kojim radite. Pogledajte funkciju radiN esto():
o b l i k.obri s i S e ( ) ;
II ...
o b l ik . is c r t a j S e f ) ;
O bratite panju na to da se nigde ne govori:,, Ako si Krug, radi ovo, ako si Kvadrat radi
onoitd." Tako napisan kod koji proverava sve mogue tipove koje O blik moe da pokrije
prljav je i m orate da ga m enjate svaki put kada dodate novu vrstu O blika. U naem slu-
aju, kaemo: ,,Ti si oblik, ja znam da moe da se iscrta i obrie, to i uradi, i sam vodi
rauna o detaljima".
Vano je da se naredbe u funkciji raiN esto() izvravaju na pravi nain. Sam poziv
m etode iscrtajSe() za K rug prouzrokuje izvravanje drugaijeg koda nego kada poziva-
mo m etodu iscrtajSe() za Kvadrat ili Liniju; ali kada poruku iscrtajSe() poaljemo ne-
poznatom O bliku, dobija se ispravno ponaanje, zasnovano na stvarnom tipu Oblika.
Ovo je dobra osobina, kao to je ranije pom enuto, jer kada prevodilac prevodi m etodu ra-
diN esto(), on ne zna tip s kojim radi. Stoga bismo obino oekivali da on pozove verziju
m etoda obrisiSe() i iscrtajSe() za osnovnu klasu O blik, a ne za odreeni Krug, Kvadrat
Poglavjje 1: Upoznavanje sa objektima 29
ili Liniju. Zbog polim orfizm a se sve ipak ispravno odvija. Prevodilac i sistem za izvrava-
nje vode rauna o svim detaljima. Zasa je dovoljno da znate da polim orfizam funkcio-
nie i kako da piete program e koristei taj pristup. Kada poaljete poru k u objektu,
objekat e uraditi ta treba, ak i kada treba svoditi navie.
Kontejneri
Po pravilu, ne moete znati koliko objekata e vam biti potrebno za reavanje nekog
zadatka, niti koliko dugo oni treba da postoje u m emoriji. Ne znate ni kako da uskladitite
te objekte. Ako pre izvravanja program a ne znate ni broj objekata ni njihov vek trajanja,
kako da odredite koliinu memorijskog prostora za njihovo skladitenje?
Reenje veine problem a u objektno orijentisanom program iranju ponekad deluje
neozbiljno: stvoriti jo jedan tip objekta. Novi tip objekta koji reava pom enuti problem
uva reference na druge objekte. Naravno, to isto moete da uradite i pom ou nizova, koji
postoje u veini jezika. Ali taj novi objekat, obino pod im enom kontejner (naziva se i fco-
lekcija, ali poto Javine biblioteke koriste taj term in u drugom smislu, ova knjiga e se
30 Misliti na Javi
drati im ena ,,kontejner), irie se po potrebi da bi prim io sve to u njega stavite. Stoga
ne m orate da znate koliko ete objekata uvati u kontejneru. Samo napravite kontejnerski
objekat i prepustite njemu da se stara o detaljima.
Sreom, dobar OOP jezik sadri skup kontejnera kao deo paketa. U jeziku C ++ on je
deo standardne C ++ biblioteke i esto se naziva standardna biblioteka ablona (engl.
Standard Template Library, STL). Smalltalk ima prilino dobar skup kontejnera. I Java
ima m nogo kontejnera u svojoj standardnoj biblioteci. U nekim bibliotekama jedan ili
dva generika kontejnera dovoljni su za sve potrebe, dok u drugim bibliotekama (na pri-
m er u Javi) postoje razliiti tipovi kontejnera za razliite potrebe: vie razliitih klasa
spiskova (tipova Lista) za uvanje sekvenci, tipova M apa (koje neki nazivaju asocijativni
tiizovi) zapridruivanje jednih objekata drugim a, tipova skupova (Set) za uvanje po jed-
nog prim erka raznih tipova objekata i druge kom ponente m eu kojima su redovi e-
kanja, stabla, stekovi itd.
Sa stanovita program a, za vas je vaan kontejner s kojim moete da radite i reite pro-
blem. Ako kontejner jednog tipa zadovoljava vae potrebe, nem a razloga da uvodite druge.
Izbor treba da vam bude ponuen iz dva razloga. Prvo, kontejneri obezbeuju razliite ti-
pove interfejsa i naina rada. Stek ima interfejs i nain rada razliit od reda ekanja, koji se
razlikuje od skupa ili liste. Za reenje vaeg problem a jedan od njih je obino bolji od osta-
lih. Drugo, razliiti kontejneri obavljaju iste operacije s razliitom efikasnou. Na primer,
postoje dve osnovne vrste lista: ArrayList i LinkedList. I jedna i druga su jednostavne se-
kvence koje mogu imati identine interfejse i, spolja gledano, naine rada. No, postoji bit-
na razlika u trajanju i zahtevima odredenih operacija nad njima. Prim era radi, nasum ino
pristupanje elementima kontejnera ArrayList je operacija s konstantnim vremenom izvr-
avanja; bez obzira na to koji element izaberemo, potrebno je isto vreme. Meutim, pom e-
ranje kroz listu LinkedList do nasum ino izabranog elementa je komplikovanije i treba
vie vremena da se pristupi elementim a to su oni dalje od poetka liste. S druge strane,
ako elite da ubacite element usred sekvence, to je mnogo jednostavnije i bre u iisti Lin-
kedList, nego u ArrayList. Ove i druge operacije nisu jednako efikasne, to zavisi od struk-
ture koja se nalazi u osnovi pojedine sekvence. U fazi pisanja program a, moete krenuti od
kontejnera LinkedList a kada budete popravljali perform anse, prebacite se na kontejner
ArrayList. Zahvaljujui apstrakciji preko interfejsa List, prebacivanje iz jedne strukture 11
drugu imae minim alan uticaj na va kod.
objekat u kontejner, ona se svodi navie na O bject i gubi identitet. Kada je izvadite iz kon-
tejnera, dobijate referencu na Object, a ne referencu na tip koji ste stavili unutra. Kako onda
da tu referencu vratite u neto to ima konkretan tip objekta koji ste stavili u kontejner?
Ovde se ponovo koristi eksplicitna konverzija (pretvaranje) tipova, ali ovog p u ta se ne
penjete uz hijerarhiju nasleivanja do optijeg tipa, ve se sputate niz hijerarhiju do od-
reenijeg tipa. Ovaj nain eksplicitne konverzije naziva se svoenje nanie (engl. dovvnca-
sting). Pri svoenju navie, na primer, znate da je K rug tipa O blik, pa moete slobodno
da izvrite svoenje navie; m eutim , neki O bject nije obavezno K rug ili O blik, pa svo-
enje nanie nije ba sigurno, osim ako znam o s im im am o posla.
Ovo i nije previe opasno: ako izvrite pogreno svoenje nanie, javlja se greka pri iz-
vravanju - izuzetak (engl. exception), o kome uskoro govorimo. Kada iz kontejnera uzi-
m ate reference, m orate obezbediti neki nain da zapam tite na ta se te reference odnose
kako biste mogli da izvrite pravilno svoenje nanie.
Svoenje nanie i provere pri izvravanju zahtevaju dodatno vreme za izvravanje pro-
gram a i dodatni napor za program era. Zar ne bi bilo logino da nekako napravim o kon-
tejner tako da on zna koje tipove uva, ime se iskljuuje potreba za svoenjem nanie
kao i m ogue greke. Ovo se reava pom ou parametrizovanih tipova, a to su klase koje
prevodilac autom atski moe da prilagodi tako da rade sa odreenim tipom . Na prim er,
param etrizovani kontejner prevodilac bi mogao da prilagodi tako da prihvata i vraa
sam o klasu Oblik.
ledna od velikih prom ena koje je donela Java SE5 jesu param etrizovani tipovi, koje u
Javi nazivamo generiki tipovi. Prepoznaete ih po uglastim zagradam a u n u tar kojih se
navode; recimo, ovako se moe napraviti ArrayList koji sadri Oblik:
A r r a y L i s t < 0 b l i k > oblici = new A r r a y L i s t < 0 b i i k > ( );
Moda imate i neki drugi sistem za zapisivanje podataka o avionim a o kojima ne treba
neposredno voditi rauna. M oda je to evidencija o planovim a leta malih aviona koji na-
putaju aerodrom . Znai, trebao bi vam drugi kontejner za male avione i kad god napra-
vite objekat aviona, ako je to mali avion, stavili biste ga takoe i u ovaj drugi kontejner.
Zatim bi neki pozadinski proces obavljao operacije nad objektim a iz tog kontejnera kada
raunar ne radi nita drugo.
Sada je problem neto tei: kako uopte moete znati kada da unitite objekte? Kada za-
vrite sa objektom, nekom drugom delu sistema m oda je jo uvek potreban. Isti problem
se moe pojaviti i postati vrlo sloen u m nogim drugim situacijam a i u program skim si-
stemim a (kao to je C++) u kojima m orate izriito da obriete objekat kada s njim zavrite.
Gde se nalaze podaci iz objekta i kako se kontrolie trajanje objekta? C ++ zauzima stav
da je najvanija efikasnost, pa program eru preputa izbor. Da bi se postigla maksimalna
brzina izvravanja, uvanje i trajanje m ogu biti odreeni prilikom pisanja program a, tako
to se objekti stavljaju na stek (oni se ponekad nazivaju i automatske ili vidljive- engl. sco-
ped -pro m enljive) ili u statiku oblast za uvanje. Ta mesta im aju viso k p rio ritet i prostor
se u njim a brzo zauzima i oslobaa, pa je kontrola nad njim a veoma znaajna u nekim si-
tuacijama. M eutim , tim e rtvujete fleksibilnost jer m orate da znate taan broj, trajanje
i tip objekata prilikom pisanja program a. Ako pokuavate da reavate optiji problem , na
prim er projektovanje pom ou raunara (CAD), upravljanje skladitem ili kontrolu va-
zdunog saobraaja, ova m etoda je previe restriktivna.
Drugi pristup je dinamiko stvaranje objekata u dinamikoj oblasti memorije (engl.
heap). Pri ovom pristupu, sve dok ne pone izvravanje, ne znate koliko vam objekata tre-
ba, koliko e trajati, niti kog su tipa. Sve se to odreuie kada program ve radi (ovakav na-
in pravljenja objekata zove se dinam iki). Ako vam zatreba novi objekat, napravite ga u
dinamikoj memoriji, u trenutku kada vam je zatrebao. Poto se oblau za uvanje upra-
vlja dinamiki, prilikom izvravanja, zauzimanje memorijskog prostora traje znatno due
od odvajanja prostora na steku. Odvajanje prostora na steku esto se postie samo asem
blerskom naredbom da se pokaziva steka pom eri nanie i da se vrati nazad. Vreme za koje
se odvoji prostor u dinamikoj m em oriji, zavisi od dizajna m ehanizm a za skladitenje.
Dinamiki pristup se zasniva na najee opravdanoj pretpostavci da su objekti sloe-
ni, tako da dodatni reijski trokovi za nalaenje prostora i njegovo oslobaanje nee bit-
no uticati na stvaranje objekata. Vea fleksibilnost dinam ikog pristupa je neophodna za
reavanje optijih program skih problem a.
Java iskljuivo koristi drugi pristup.' Svaki p u t kada elite da stvorite objekat, koristite
rezervisanu re new da biste napravili dinam iki prim erak tog objekta.
Namee se jo i pitanje trajanja objekata. U jezicima koji dozvoljavaju da se objekti stva-
raju na steku, prevodilac odreuje koliko dugo objekti traju i moe automatski da ih uniti.
Meutim, kada objekat stvorite dinamiki, prevodilac nema informacije o njegovom i-
votnom veku. U jeziku kao to je C ++ m orate programski da odredite kada eteda unitite
objekat, to moe dovesti docurenja" m em orije ako se to ne uradi ispravno (to je est pro-
blem u program im a pisanim na C + + -u). Java obezbeuje tzv. sakuplja smea (engl. gar-
bage collector) koji automatski otkriva koji se objekat vie ne upotrebljava i unitava ga.
Sakupljanje smea je veoma korisno, jer sm anjuje broj stavki na koje m orate da mislite i
koliinu koda koji m orate da napiete. Jo je bitnije to sakupljanje smea obezbeuje
m nogo vii nivo zatite od podm uklih problem a sa curenjem" m em orije (koje je mnoge
projekte pisane na jeziku C++ oborOo na kolena).
U Javi, sakuplja smea vodi rauna o problem u oslobaanja m em orije'(iako u to ne
spadaju drugi aspekti ienja objekta). Sakuplja smea ,,zna kada se objekat vie ne ko-
risti i autom atski oslobaa m em oriju koju je zauzim ao taj objekat. To, uz injenicu da su
svi objekti izvedeni iz jedne osnovne klase O bject, kao i da postoji samo jedan nain za
pravljenje objekata - dinam iki - ini proces program iranja u Javi m nogo jednostavnijim
od program iranja na jeziku C ++. M nogo je m anje odluka koje treba da donesete i pre-
preka koje m orate da prevaziete.
Paralelni rad
Osnovni koncept u raunarskom program iranju jeste obrada vie od jednog zadatka isto-
vremeno. Mnogi programski poslovi zahtevaju da program moe da zaustavi rad, poza-
bavi se nekim drugim problem om a zatim se vrati glavnom procesu. Problem u se
pristupalo na vie naina. Na poetku, program eri koji su poznavali raunar do najsit-
nijih pojedinosti, pisali su prekidne servisne rutine, a suspenzija glavnog procesa je inici-
rana preko hardverskog prekida. Iako je sve to dobro radilo, bilo je teko i neprenosivo, jer
je prebacivanje program a na novi tip raunara bilo sporo i skupo.
Ponekad su za obradu zadataka koji se m oraju odm ah izvriti prekidi rada neophodni,
ali postoji velika klasa poslova u kojoj problem pokuavam o da izdelimo na vie delova
koji se izvravaju zasebno i paralelno, da bi ceo program bre reagovao. Delovi koji se za-
sebno izvravaju unutar program a nazivaju se niti (engl. thread), a ceo koncept paralelni
rad (engl. concurrency). Tipian p rim er paralelnog rada je korisniko okruenje. Zbog
podele program a na niti, korisnik m oe da pritisne dugm e i da dobije brz odziv, umesto
da bude prinuen da eka dok program ne zavri tren u tn i zadatak.
N itim a se obino raspodeljuje vreme jednog (i jedinog) procesora. M eutim , ako ope-
rativni sistem podrava vieprocesorski rad, svaka nit moe biti dodeljena razliitim pro-
cesorima, i tada one zaista m ogu da rade paralelno. Jedna od korisnih osobina paralelnog
rada na nivou jezika jeste sledea: program er ne m ora da brine postoji li jedan ili vie pro-
cesora. Program je logiki podeljen na niti i ako raunar ima vie od jednog procesora,
program e se bre izvravati, bez ikakvih posebnih prilagoavanja.
Nakon svega ovoga, paralelni rad zvui prilino jednostavno. Postoji ipak jedna za-
koljica: deljeni resursi. Ako se sim ultano izvrava vie niti koje oekuju da pristupe istom
resursu, pojavie se problem. Na prim er, dva procesa ne mogu istovrem eno da alju po-
datke istom tampau. Da bi se reio problem , resursi koji mogu biti deljeni, kao to je
tam pa, m oraju biti zakljuani dok se koriste. Znai, nit zakljua resurs, zavri zadatak,
a zatim otkljua resurs, posle ega neko drugi moe da ga koristi.
Paralelni rad je ugraen u Javu, a Java SE5 ga d odatno podrava svojom bililiotekom.
Java i Internet
Ako je Java zapravo samo jo jedan raunarski program ski jezik, m oete se zapitati zato
je toliko vana i zato se predstavlja kao revolucionarni korak u raunarskom programi
ranju. Odgovor nije odmah oigledan, ukoliko se posm atra iz tradicionalne program er-
ske perspektive. Iako je Java veoma korisna za reavanje uobiajenih zasebnih
program skih problem a, jo je vanije to to pom ou nje moete reiti i program ske pro-
bleme koji se tiu Weba.
ta je Web?
Isprva Web moe da deluje pom alo tajanstveno, uz celu priu o krstarenju, ,,prisustvu
i Iinim prezentacijama. Korisno je malo se udaljiti i sagledati ta Web zaista jeste, ali za
to m orate da razumete sisteme klijent/server, jo jedan aspekt raunarske obrade koji je
pun zbunjujuih tema.
Poglavlje I : Upoznavanje sa objektima 35
Klijent/server obrada
O snovna ideja sistema klijent/server jeste postojanje centralnog skladita inform acija -
neke vrste podataka, obino u bazi podataka - koje hoete da aljete, po zahtevu, grupi
ljudi ili raunara. U konceptu klijent/server kljuno je to to je skladite inform acija cen-
tralizovano tako da informacije m ogu da se m enjaju i da se te prom ene prenose svim ko-
risnicima informacija. Skladite inform acija, softver koji alje informacije i raunar
(raunari) gde se softver i inform acije nalaze, nazivaju se server. Softver koji se nalazi na
korisnikom raunaru, sarauje sa serverom, preuzim a informacije, obrauje ih i prika-
zuje na udaljenom raunaru, naziva se klijent.
Osnovni koncept klijent/server obrade, znai, nije previe sloen. Problemi se javljaju
jer im ate jedan server koji pokuava da opslui vie klijenata u isto vreme. Uglavnom se ko-
risti sistem za upravljanje bazam a podataka, tako da program er ,,uravnoteava raspored
podataka u tabelama da bi postigao optim alno korienje. Sistemi esto dozvoljavaju kli-
jentim a i da dodaju informacije na server. To znai da m orate obezbediti da novi podaci
jednog klijenta ne pregaze'" nove podatke drugog klijenta, ili da se ti podaci ne izgube u
procesu dodavanja u bazu. (Ovo se zove obrada transakcija - engl. transaction processitig).
Kada klijentski softver treba izmeniti, on m ora da se prevede, oisti od greaka i instalira na
klijentskim raunarim a, to je u stvarnosti znatno komplikovanije i skuplje nego to mi-
slite. Posebno je problem atino podrati vie tipova raunara i operativnih sistema. Ko-
nano, tu je i veoma bitno pitanje perform ansi: stotine klijenata mogu da postavljaju
zahteve vaem serveru u bilo kom trenutku, pa je i najmanje zakanjenje problematino.
Da bi se kanjenje svelo na najm anju m eru, program eri naporno rade da rasterete proce-
sne zadatke, prebacujui deo obrade na klijentski raunar, a ponekad i na druge raunare
na serverskoj strani, koristei takozvane posrednike (engl. middleware). (Posrednici se ta-
koe koriste da bi se olakalo odravanje.)
Realizacija tako jednostavnog postupka - slanja informacija - toliko je slojevita i slo-
ena da ceo problem eluje beznadeno zagonetno. I pored toga je veoma bitna: klijent/
server obrada nosi otprilike polovinu svih program skih aktivnosti. O na je zaduena za
sve, poev od uzimanja narudbina, transakcija s kreditnim karticama, pa do slanja ra-
znih vrsta podataka - berzanskih, naunih, dravnih; ta god vam padne na pam et. U
prolosti sm o se suoavali sa individualnim reenjima individualnih problema; svaki put
sm o smiljali novo reenje. Bilo je teko osmisliti ih, teko su se upotrebljavala i korisnik
ie m orao da ui nov interfejs za svako od tih reenja. Ceo klijent/server problem trebalo
bi sveobuhvatno da se rei.
stranica sa servera. eleii su punu klijent/server kompatibilnost kako bi klijent bio u mo-
gunosti da vraa podatke mogunost na server, na primer, da pretrauje baze na serveru,
dodaje nove informacije na server, ili da ostavi narudbinu (to je sve zahtevalo posebne
bezbednosne mere). Bili smo svedoci tih prom ena u razvoju Weba.
ita Weba je oznaio veliki korak napred - uveo je m ogunost da se delii inform acija
neizm enjeni prikazuju na bilo kom tipu raunara. Ti itai su ipak bili prilino prim itivni
i ubrzo su se zaglibili u zahtevima koji su im ispostavljani. Oni nisu bili previe interak-
tivni; zaguivali su server i sam Internet jer ste, svaki p u t kada je trebalo uraditi neto to
zahteva program iranje, m orali da vraate informacije serveru na obradu. Moglo je da
proe vie sekundi ili m inuta dok ne otkrijete da ste neto pogreno otkucali. Poto je i-
ta bio predvien samo za pregled, nije m ogao da izvri ni najjednostavnije zadatke ob-
rade. (S druge strane, bio je po tp un o bezbedan, jer na vaem raunaru nije mogao da
izvri nijedan program , dakle ni da m u potencijalno donese greku ili virus.)
Prim enjeno je vie pristupa reenju ovog problema. Za poetak, poboljani su grafiki
standardi da bi omoguili bolju animaciju i video prikaz u itaima. Drugi deo problema
mogao je biti reen samo ugraivanjem u ita mogunosti za pokretanje program a na kli-
jentskoj strani. To se naziva programiranje s klijentskestrane (engl. client-sideprogramming).
grafika.) Pored toga, bez sum nje ste stekli neposredno iskustvo s proverom ispravnosti
podataka na ulaznom obrascu. Pritisnete dugm e za slanje na stranici, server pokrene CGI
program koji otkrije greku, form atira HTML stranicu obavetavajui vas o greci, a za-
tim vam vrati tu stranicu. O nda vi m orate da se vratite na p reth o d n u stranicu i pokuate
ponovo. Ovo ne samo da je sporo ve je i zam orno.
Reenje je program iranje s klijentske strane. Veina stonih raunara na kojima rade i-
tai Weba sposobni su da urade ogrom an posao, a s prvobitnim statikim HTM L pristu-
p om sam o su stajali i besposleno ekali da server isporui sledeu stranicu. Program iranje
s klijentske strane znai da ita Weba radi sav posao koji moe da obavi, korisnik m nogo
bre dobija rezultat a oseaj zajednitva p ri radu s Web stranicom je potpuniji.
Rasprave o program iranju s klijentske strane malo se razlikuju od rasprava o progra-
m iranju uopte. Param etri su gotovo isti, ali je platform a drugaija: ita Weba je slian
ogranienom operativnom sistemu. Na kraju, opet m orate da program irate, i zato pro-
gram iranje s klijentske strane povlai vrtoglav niz problem a i reenja. U daljem tekstu da-
jem o pregled pitanja i pristupa pri program iranju klijentske strane.
Dodaci
Razvoj dodataka (engl. plug-ins) predstavlja jedan od najduih koraka napred u progra-
m iranju s klijentske strane. Program er dodaje novu funkcionalnost itau tako to kori-
snik u potrebnom trenutku preuzme deo koda koji se ugradi na odgovarajue m esto u
itau. Taj kod govori itau: ,,Od sada moe da obavlja i ovu novu aktivnost. (D odatak
treba da preuzm ete sam o jednom .) Preko dodataka su itaima pridodata brza i m ona
proirenja, ali pisanje dodataka nije jednostavan zadatak i nije neto to biste eleli da ra-
dite u okviru izgradnje odredene stranice. Vrednost odataka za program iranje s klijent-
ske strane jeste to to oni omoguavaju strunjaku da pravi nova proirenja i da ih dodaje
itau bez odobrenja proizvoaa itaa. Stoga, dodaci predstavljaju zadnja vrata koja
om oguavaju stvaranje novih jezika za program iranje s klijentske strane (iako nisu svi je-
zici realizovani kao dodaoi).
Skript-jezici
Dodaci su prouzrokovali razvoj skript-jezika za itae. Pomou skript-jezika ugradujete
izvorni kod program a za klijentsku stranu direktno u HTML stranicu, a dodatak koji tu-
mai taj jezik autom atski se aktivira pri prikazivanju HTML stranice. Skript-jezici se
obino prilino lako shvataju i poto se piu u delu HTML stranice, uitavaju se veoma
brzo, jednim pristupom serveru na kome se nalazi ta stranica. Nedostatak je to to je va
kod izloen i svako moe da ga vidi (i ukrade). U principu, ipak ne pravite neke sofistici-
rane stvari pom ou skript-jezika, pa ovaj nedostatak i nije neki problem .
Postoji jedan skript-jezik koji veina itaa Weba podrava i bez ikakvog dodatka - to
je JavaSoript (koji ima tek prolaznu slinost s Javom, i m oraete ga uiti zasebno). Tako je
nazvan sam o da bi prigrabio deo Javinog marketinkog uzleta. Naalost, veina itaa
Weba je svoju podrku za JavaScript realizovala na svoj jedinstveni nain, drugaije od
ostalih itaa, pa ak i od ostalih svojih verzija. Neto je popravila standardizacija Java-
Scripta u obliku ECMAScipta, ali je raznim itaima trebalo m nogo vrem ena da dou do
38 Misliti na Javi
tog nivoa (tom e je doprineo i M icrosoft, gurajui svoj VBScript koji pomalo lii na Java-
Script). Da bi program m ogao da se izvrava na svim itaim a,po pravilu ga m orate pisati
koristei najm anji zajedniki imenilac svih postojeih verzija JavaScripta. Programska
obrada greaka, kao i otkrivanje i otldanjanje greaka u toku pisanja program a, mogu se
opisati sam o kao muenje. Dokaz tili potekoa je injenica da je na JavaScriptu tek ne-
davno napisan zaista sloen program (to je Googleov GMail), to je zahtevalo veliki trud
i strunost.
Ovim se naglaava da su skript-jezici koji se koriste u nutar itaa Weba predvieni da
ree odreene vrste problem a, prvenstveno da se naprave bogatija i interaktivnija grafika
korisnika okruenja. Skript-jezik m oe da rei i do 80 procenata problem a koje sreemo
pri program iranju s klijentske strane. Vai problem i verovatno spadaju u tih 80 procena-
ta, a kako skript-jezici om oguuju laki i bri rad, trebalo bi da razmislite o njim a pre
nego to se upustite u m nogo zapetljanija reenja, kao to je program iranje na Javi.
Java
Ako skript-jezici mogu da razree 80 procenata problem a pri klijentskom program iranju,
ta je s preostalih 20 procenata zaista tekih stvari? Java je popularno reenje za tih 20%.
Pre svega, to je m oan program ski jezik, siguran, m euplatform ski i internacionalan.
Java se neprekidno iri: dodaju se nove m ogunosti jezika i biblioteke koje mogu elegant-
no da ree problem e teke i u tradicionalnim program skim jezicima, kao to su istovre-
meni rad, pristup bazama, m reno program iranje i distribuirana obrada. Java doputa
program iranje s klijentske strane preko apleta i pom ou lava Web Starta.
Aplet je mali program koji moe da se izvrava samo unutar itaa VVeba. Aplet se
autom atski preuzim a kao deo Web stranice (kao to se, na prim er, automatski preuzima
grafika). Kada se aplet aktivira, on izvrava program . Deo njegove pogodnosti je to to
omoguava da autom atski distribuirate klijentski softver sa servera tek u trenutku kada je
korisniku klijentski softver potreban, a ne ranije. Korisnik bespogovorno dobija najnovi-
ju verziju klijentskog softvera i to bez sloene ponovne instalacije. Zbog naina na koji je
Java projektovana, program er treba da napravi samo jedan jedini program, a taj program
autom atski radi na svim raunarim a koji imaju itae s podrkom za Javu. (Ovo, bez ika-
kve brige, obuhvata ogrom nu veinu raunara.) Poto je Java potpun programski jezik,
moete uraditi sav posao koji je m ogu na klijentskoj strani, pre i posle postavljanja za-
hteva serveru. Na prim er, nem a potrebe da aljete obrazac sa zahtevom preko Interneta
kako biste otkrili da li ste pogreili pri upisivanju datum a ili nekog drugog param etra; va
raunar moe brzo da iscrtava grafike na osnovu podataka, um esto da eka da ih server is-
crta i vrati sliku. Pored trenutnog poboljanja brzine i odziva, sm anjuju se ukupni mreni
saobraaj i optereenje servera i spreava usporavanje celog Interneta.
Druge mogunosti
Poteno reeno, Java apleti nisu opravdali velika poetna oekivanja. Kada se Java tek po-
javila, najvie se govorilo upravo o apletim a, jer je trebalo da oni najzad omogue ozbiljno
program iranje na klijentskoj strani, poveaju brzinu odziva i smanje protok podataka
potreban Internet aplikacijama. Predviale su se ogrom ne mogunosti.
Poglavlje 1: Upoznavanje sa objektima 39
Na Webu se zaista m ogu nai i veoma pam etni apleti, ali do sveopteg prelaska na aple-
te nije dolo. Verovatno je najvei problem bila veliina Javinog izvrnog okruenja (Java
Runtim e Environm ent, JRE) od 10 MB, koje je trebalo preuzeti s Weba i instalirati, to je
uplailo prosenog korisnika. Sudbinu im je m oda zapeatila injenica da je Microsoft
odluio da JRE ne isporuuje kao deo svog Internet Explorera. U svakom sluaju, Java
apleti se nisu proirili posvuda.
Bez obzira na to, u nekim situacijama Java aplete i Java Web Start aplikacije jo uvek
vredi imati. Ukoliko upravljate raunarim a korisnika, recimo unutar preduzea, bilo bi
p am etno da distribuciju i auriranje klijentskih aplikacija obavljate pom ou ovih tehno-
logija, jer ete tim e utedeti znatnu koliinu vrem ena, tru d a i novca, naroito ako m orate
esto da aurirate njihov softver.
U poglavlju Grafika korisnika okruenja upoznaem o Flex, novu Adobeovu tehno-
logiju koja obeava - u njom e se prave Flash apleti. Poto vie od 98 procenata svih itaa
Weba im a Flash Player (na W indowsu, Linuxu i M acu), m oem o sm atrati da je on usvo-
jen standard. Flash Player se instalira i aurira lako i brzo. Jezik ActionScript je napravljen
na osnovu ECMAScripta i stoga je prilino poznat, ali Flex omoguava program iranje bez
brige o specifinostima raznih itaa - zato je daleko privlaniji od JavaScripta. Pri pro-
gram iranju na klijentskoj strani, ovu m ogunost vredi razm otriti.
.NETi C#
Neko vrem e je glavni konkurent Java apleta bio Microsoftov ActiveX, iako samo na W in-
dovvs raunarim a. O tad je M icrosoft napravio prvog pravog konkurenta celoj Javi u liku
platform e .NET i program skog jezika C#. Platform a .NET je priblino isto to i Javina vir-
tuelna maina (Java Virtual Machine, JVM) plus Java biblioteke. JVM je softverska plat-
form a na kojoj se izvravaju java program i, a C# ima velike slinosti s Javom. Bez sum nje,
radi se o dosad najboljem Microsoftovom proizvodu na podruju program skih jezika i
program skih okruenja. Naravno, Microsoft je imao veliku prednost jer je mogao da ui
na tuim grekama, ali je bogami nauio. Prvi put od svog nastanka, Java je dobila pravu
konkurenciju. Zato su projektanti Jave u Sunu dobro pogledali C#, dobro razmislili o
tom e zato bi program eri hteli da preu na C#, i odgovorili: nainili su fundam entalna
poboljanja Jave - Javu SE5.
T renutno je najvea siabost .NET-a vano pitanje da li e Microsoft dozvoliti njegovo
potpm io prenoenje na ruge platforme. Microsoft tvrdi da se to moe napraviti bez pro-
blema, i ve postoji delimina realizacija .NET-a koja radi na Linuxu (projekat Mono,
www.gomono.com), ali dok se ne napravi potpuna realizacija iz koje M icrosoft nije nita
izbacio, .NET je rizino sm atrati reenjem za sve platforme.
Internet i intranet
Wcl> je najoptije reenje problem a klijent/server, pa je logino da istu tehnologiju
upotrebite i da biste reili podgrupu tog problem a, posebno klasini problem klijent/ser-
ver um itar preduzea. Pri tradicionalnom pristupu klijent/server, postoji problem zbog
raznih tipova raunara kao i problem zbog tekog instaliranja novog klijentskog softvera.
Oba problem a dobro su reena pom ou itaa Weba i program iranja s klijentske strane.
40 Misliti na Javi
Kada se tehnologija Weba koristi za inform acionu m reu ogranienu na odreeno pre-
duzee, to nazivamo intranet. Intranet obezbeuje m nogo veu sigurnost nego Internet
jer pristup serverima u preduzeu moete fiziki da kontroliete. Izgleda da korisnici,
kadajednom shvate osnovni princip rada itaa, m nogo lake izlaze na kraj s razliitim iz-
gledima stranica i apleta, pa bre ue nove sisteme.
Problem s bezbednou svrstava nas u jednu od grupa koje se obrazuju, ini se, po
autom atizm u, u svetu klijent/server program iranja. Ako se va program izvrava na In-
ternetu, ne znate na kojoj platform i e on raditi i elite da budete sasvim sigurni da ne i-
rite neispravan kod. Treba vam neto nezavisno od platform e i bezbeno, kao to su
skript-jezik ili Java.
Ako radite na intranetu, pred vas se postavljaju drugaija ogranienja. Nije neuobia-
jeno da svi raunari budu platform e Intel/W indows. Na intranetu ste sami odgovorni za
kvalitet svog program a i moete da otklanjate greke kako se koja otkriva. Pored toga,
moda ve imate dosta nasleenog koda koji ste koristili za tradicionalniji klijent/server
pristup, pri emu m orate fiziki da instalirate ldijentske program e svaki p u t kada radite
na poboljanju. Vreme protraeno na instaliranje poboljanja prua razlog vie da pree-
m o na itae gde su poboljanja nevidljiva i autom atska. (Ovaj problem reava i Java Web
Start.) Ako imate posla s takvim intranetom , najrazboritiji pristup je da krenete najkra-
im putem koji vam omoguava da koristite postojeu bazu koda, um esto da ponovo pi-
ete program e na novom jeziku.
Kada se suoite sa ovim zbunjujuim nizom reenia za program iranje s klijentske stra-
ne, najbolji plan napada je analiza isplativosti. Razm otrite ogranienja koja va problem
namee i najkrai put do reenja. Poto je program iranje s Jdijentske strane ipak progra-
miranje, uvek je dobro odabrati pristup koji omoguava najbri razvoj u odreenoj situa-
ciji. Ovo je hrabar stav koji vas priprem a za neizbene susrete s problem im a u razvoju
programa.
stranice prelaze na Javu zbog tehnologije servleta i iz njih izvedenih JSP strana, najvie
zato to se tim e iskljuuju problem i pri radu sa itaima razliitih m ogunosti. Progra-
miranje sa scrverske strane razm otreno je u knjizi Thitikingin Enterprise Java, koju moe-
te nai na adresi www.MindView.net.
Uprkos tom e to se o Javi pria sam o u vezi sa Internetom , ona je programski jezik opte
nam ene pom ou kogae moete reiti bilo koji tip problem a, kao i pom ou drugih jezika.
Tu Javina snaga nije samo u prenosivosti, ve i u lakoi program iranja, robusnosti, velikoj
standardnoj biblioteci i brojnim bibliotekama drugih proizvoaa koje se stalno razvijaju.
Saetak
Znate kako izgleda proceduralni program : definiciie podataka i pozivi funkcija. Da biste
pronali svrhu takvog program a, m orate malo da se pom uite i pregledate pozive funk-
cija i koncepte niskog nivoa kako biste stvorili m odel u glavi. Zbog toga nam treba po-
sredno predstavljanje kada projektujem o proceduralni program : sami za sebe, ti
program i m ogu da zbunjuju jer su naini izraavanja usm ereni vie ka raunaru nego ka
problem u koji reavamo.
Poto OOP dodaje m noge nove ideje onim a koje nalazite u proceduralnim jezicima,
moda mislite da e Java program biti m nogo komplikovaniji nego ekvivalentni C pro-
gram. Biete prijatno iznenaeni: dobro napisan Java program je uglavnom daleko jed-
nostavniji i m nogo razumljiviji od ekvivalentnog C program a. Imaete definicije objekata
koji predstavljaju ideje u vaem prostoru problem a (um esto pitanja raunarskog prikaza)
i poruke poslate tim objektima koje predstavljaju aktivnosti u tom prostoru. D obra stra-
na u objektno orijentisanom program iranju jeste ta to je uz dobro projektovan program
lako razumeti kod pri itanju. O bino ima i znatno m anje koda, jer ete m noge svoje pro-
bleme reiti ponovnim korienjem postojeeg koda iz biblioteka.
O O P i Java ne m oraju da budu za svakoga. Vano je da procenite svoje potrebe i odlu-
ite da li e ih lava optim alno zadovoljiti ili bi bilo bolje da radite s nekim drugim pro-
gramskim sistemom (ukljuujui onaj koji tren u tno koristite). Ako znate da e vae
potrebe biti usko specijalizovane u bliskoj budunosti i ako imate specifina ogranienja
koja Java m oda ne moe da zadovolji, onda ispitajte ostale raspoloive m ogunosti. Kon-
kretno, preporuujem da razm otrite Python; posetite www.Python.org. Ako ipak izabere-
te Javu, barem ete znati koje ste m ogunosti imali i zato ste ba nju izabrali.
Sve je objekat
,,Da govorimo drugaiji jezik, percipirali bismo tieto drugaiji svet.
Ludwig Witgenstein (1889-1951)
JAVA I C ++ SU H IB R ID N IJE Z IC I ALI SU PROJEKTANTI JAVE SMATRALI DA HIBRID IZA CIJA NIJE
toliko bitna kao u C++-U. U h ibridnom jeziku moe se koristiti vie program skih stilova;
C++ je hibridan da bi obezbedio povratnu kom patibilnost s jezikom C. Poto je C++
nadskup jezika C, on sadri i m noge nepoeljne nasleene osobine koje previe kompli-
kuju neke aspekte C++-a.
Jezik Java je napravljen za one koji ele da se bave samo objektno orijentisanim pro-
gram iranjem . Pre nego to se uopte upustite u program iranje, m orate poeti da raz-
miljate objektno-orijentisano (osim ako ve ne razmiljate tako). Ovaj poetni napor e
vam se isplatiti jer ete biti sposobni da program irate na jeziku koji se ui i koristi jedno-
stavnije od mnogih drugih O O P jezika. U ovom poglavlju razm atraem o osnovne delove
Java program a i nauiemo da je u Javi (gotovo) sve objekat.
O v d e m o e d o i d o n esu g lasica. Im a lju d i koji k au : O ito , to jc pokaziva", ali tak av iskaz ve sadri
p re tp o s ta v k e o realizaciji. Po svojoj s in ta k si, Java refe re n c e su m n o g o s ro d n ije C + + re fe re n c a m a nego
p o k a ziv a im a . U p rv o m iz d a n ju ove k n jig e o d a b ra o sa m n o v te rm in id e n tifik a to r (en g l. hnm U c) jcr
iz m e u re fe re n c i u C + + - u i re fe re n c i u Javi p o s to je b itn e razlike. Izlazio sa m iz C + + - a i n isa m eleo
d a z b u n ju je m p ro g ra m e re u C + + - u , za k oje sa m s m a tra o d a e b iti n a jb ro jn iji k o risn ic i Jave. Pre
n e g o to sam p rip re m io d ru g o iz d a n je, v id e o sa m d a je ee k o ri en te rm in re fe re n c a, p o to svako
ko p relazi sa C + + - a m o ra d a savlada m n o g c d ru g e p o jm o v e p o rc d te rm in o lo g ije re fe re n c i, jo jc d a n
p o ja m nee p rev ie s m e ta ti. M e d u tim , neki se n e slau ak ni sa te rm in o m re fe re n c a. U je d n o j knjizi
tv rd i se kak o je p o tp u n o p o g re n o rci d a Java p o d r a v a p ro s le d iv a n je p re k o rc fe re n c i11je r su id e n -
tifik ato ri o b je k a ta u Javi (p o to m a u to r u ) u s /iw / o b je k ti re fe re n c i. A p o to se svc (k a k o d aljc tv rd i)
u stva ri p ro s le d u je p o v re d n o s ti, vi n e o b a v lja te p ro s le d iv a n je p re k o rc fc rc n c i ve p ro s le u jc te o b -
je k te re fe rc n c i p o v re d n o s ti. M o e se d is k u to v a ti o p re c iz n o sti ta k o z a m re n ih o b ja n je n ja , ali sm a
tra m d a m o j p ris tu p p o je d n o sta v lju je s h v a ta n je k o n c e p ta , bcz ik akvih g u b ita k a (p a , te o re ti a ri jezika
m o g u d a tv rd e d a vas Iaem , ali ja u rei d a o b e z b e d u je m o d g o v a ra ju u a p s tra k c iju ).
Poglavjje 2: Sve je objekat 43
Daljinski upravlja moe da postoji sam za sebe, bez televizora. O dnosno, to to imate
referencu, ne znai da obavezno im ate i objekat povezan s njom . Ako elite da uvate re
ili reenicu, treba da napravite referencu na objekat ldase String:
String s;
Ali, ovim ste napravili satno referencu, ne i sam objekat. Ako pokuate u ovom trenut-
ku da poaljete poruku preko s, dobiete greku poto s u stvari nije povezano ni sa im
(nem a televizora). Zato je sigurnije da uvek inicijalizujete referencu kada je pravite:
String s = "asdf";
Ovde se koristi posebna osobina Jave: znakovni niz se m oe inicijalizovati tekstom pod
navodnicim a. Obino, za objekte m orate da koristite optiji tip inicijalizacije.
String s = n ew S t r i n g ("asdf");
Ovo ne samo da znai: Napravi mi nov objekat klase S trin g , ve daje i inform aciju o
tom e kako da se taj objekat napravi, tako to se navodi poetni znakovni niz.
Pored tipa String Java ima obilje drugih unapred definisanih tipova. M nogo je vanije
da moete napraviti svoje tipove. U stvari, to je osnovna aktivnost u program iranju na
Javi i o tome ete uiti u ovoj knjizi.
3. Dinamika memorija: To je oblast m em orije opte nam ene (takoe u radnoj me-
m oriji) gde obitavaju svi objekti. D obra strana dinamike m em orije jeste to to, za
razliku od steka, prevodilac ne m ora da zna koliko dugo dodeljeno skladite m ora
da ostane u dinamikoj m em oriji. Stoga im am o veliku fleksibilnost pri korienju
dinam ike memorije. Kad god vam zatreba neki objekat, napiite kod za njegovo
pravljenje koristei new, i skladite e se napraviti u dinamikoj memoriji. Narav-
no, m orate platiti ovu fleksibilnost: skladite u dinamikoj m em oriji due se pravi
nego skladite na steku (kad biste uopte mogli da napravite objekte na steku u Javi,
kao to moete u C + + -u).
4. Konstantno skladite: K onstantne vrednosti esto se um eu direktno u kod pro-
gram a to je bezbedno jer se one nikad ne m ogu prom eniti. Ponekad se konstante
izdvojeno grupiu kako bi opciono mogle da se stave u ROM m em oriju (m em orija
samo za itanje; engl. read-only memory), to se radi u raunarim a ugraenim u
druge ureaje.2
5. Skladita van radne memorije: Ako su podaci p otpuno izvan program a, oni mogu
da postoje i kada se program ne izvrava, izvan kontrole program a. Dva osnovna
prim era za ovo su objekti u tokovima podataka (engl. streamed objects), to su
objekti pretvoreni u tok bajtova, obino da bi se poslali na drugu m ainu, i trajni
objekti (engl. persistent objects), to su objekti stavljeni na disk da bi sauvali svoje
stanje ak i kada se program zavri. U ovim skladitima teko je pretvoriti objekte u
neto to moe da postoji na drugom m edijum u, a to moe da postane regularni
m em orijski objekat kada je potrebno. Java obezbeuje podrku za laku trajnost
(engl. lightvveight persistencc), a m ehanizm i kao to su JDBC i Hibernate obez-
beuju sofisticiraniju podrku za skladitenje i preuzim anje inform acija o objekti-
ma u bazama podataka.
boolean - - - Boolean
char 16 Unicode 0 Unicode 2'6-l Character
byte 8 -128 + 127 Byte
short 16 -2'5 +2I5-I Short
int 32 -23' +23'-l Integer
long 64 -263 +263-l Long
float 32 IEEE754 IEEE754 Float
double 64 IEEE754 IEEE754 Double
void - - - Void
Svi num eriki tipovi su oznaeni (sadre i pozitivne i negativne vrednosti), stoga ne
traite neoznaene tipove.
Veliina tipa boolean nije izriito definisana; zadato je samo da moe da im a vrednosti
true ili false.
Om otakc klase za proste tipove podataka omoguavaju da u dinamikoj m em oriji
napravite objekat koji predstavlja odreen prost tip. Na primer:
char c = 'x 1;
C h a r a c t e r ch = n e w C h a r a c t e r ( c ) ;
C h a r a c t e r ch = n e w C h a r a c t e r ( 'x ');
C h a r a c t e r ch = 'x ';
char c = ch;
Nizovi u Javi
Praktino svi program ski jezici podravaju neku vrstu nizova. Korienje nizova u C -u i
C + + - U rizino je jer su ti nizovi samo blokovi m em orije. Ako program pristupi nizu iz-
van njegovog m em orijskog bloka ili koristi m em oriju pre inicijalizacije (to su este gre-
ke u program iranju), doi e do nepredvidljivih situacija.
Jedan od osnovnih ciljeva Jave je sigurnost; u njoj se uopte ne pojavljuju m nogi pro-
blemi koji mue program ere u C-u i C + + -u. U Javi je niz garantovano inicijalizovan i ne
moe m u se pristupiti van njegovog opsega. Opseg se proverava po cenu male koliine
dodatnog utroka m em orije u svakom nizu, kao i uz proveru indeksa pri izvravanju, ali
se pretpostavlja da su sigurnost i poveana produktivnost vredni toga (a Java katkada
moe da optim izuje te operacije).
Kada pravite niz objekata, vi, u stvari, pravite niz referenci, i svaka od tih referenci
autom atski se inicijalizuje na posebnu vrednost. Za tu vrednost koristi se rezervisana re
null. Kada Java naie na null, ona prepoznaje da dotina referenca ne pokazuje na obje-
kat. Pre nego to je upotrebite, svakoj referenci m orate da dodclite objekat, i ako pokuate
da koristite referencu koja jo uvek ima vrednost null, problem e biti prijavljen pri izvr-
avanju. Na taj nain su tipine greke s nizovima predupreene 11 Javi.
Moete da napravite i niz prostih tipova. Ponovo, prevodilac garantuje ispravnu inici-
jalizaciju jer m em oriju za taj niz puni nulama.
Nizovi e biti detaljnije objanjeni u narednim poglavljima.
Oblast vaenja
Veina proceduralnih jezika poiva na oblasti vacnjn (engl. scope). O na odreuje vidlji-
vost i ivotni vek imena definisanih u n u tar te oblasti. U C-u, C + + -u i Javi oblast vaenja
je odreena vitiastim zagradam a { }. Na prim er:
Poglavjje 2: Sveje objekat 47
{
int X = 12;
/ / d o s t u p n a j e s am o p r o m e r l j i v a x
{
int q = 96;
// d o s t u p n e su i x i q
/ / d o s t u p n a j e sa mo x
/ / q j e " i zvan ob l a s t i vaenja"
}
Promenljiva definisana unutar oblasti vaenja dostupna je samo do kraja te oblasti.
Sav tekst nakon / / pa do kraja reda predstavlja komentar.
Uvlaenje pom ae da se program pisan u Javi lake ita. Poto je Java jezik slobodne
forme, dodatni razmaci, tabulatori i novi redovi ne utiu na rezultujui program.
U Javi ne tnoete da uradite sledee, iako je to dozvoljeno u C-u i C++-u:
{
int x = 12;
{
int x = 96; // n e p r o p i s n o
}
}
{
S t r i n g s = n ew S t r i n g ("neki znakov ni niz");
} // kraj oblasti vaenja
referenca s e nestati na kraju oblasti vaenja. M eutim, objekat klase String na koji je s
ukazivala jo uvek zauzima mem oriju. U ovom deliu koda neina naina da pristupite
objektu nakon oblasti vaenja, jer je jedina referenca na njega nedostupna izvan oblasti
vaenja. Dalje u knjizi videete kako reference na objekte mogu da se prosleuju i um no-
avaju celim tokom programa.
Poto se objekti napravljeni pom ou operatora new zadravaju dokle god su vam po-
trebni, ispostavlja se da mnotvo problem a u program iranju u C + + -u ne postoji u Javi. U
C + + -u se m orate pobrinuti ne sam o za to da objekti postoje olde god su vam potrebni,
nego ih m orate i unititi kada s njim a zavrite.
48 Misliti na Javi
Zbog toga se postavlja vano pitanje. Ako Java ostavlja objekte da lee unaokolo, ta ih
spreava da prepune m em oriju i zaustave program? Upravo bi se ta vrsta problem a poja-
vila u C ++-u. Na ovom mestu deluje malo magije. Java ima sakuplja smea (engl. garbage
collector); on vodi rauna o svim objektima koji su napravljeni operatorom new i otkriva
one na koje vie nema referenci. Zatim oslobaa m em oriju koju su zauzimali ti objekti, pa
ta m em orija moe da se koristi za nove objekte. To znai da nikada ne m orate sami da se
brinete o oslobaanju memorije. Samo napravite objekte, a kada vam vie nisu potrebni,
oni e sami otii. Ovo eliminie jednu klasu program skih problem a, takozvano curenje
memorije (engl. memory leak), pri kome program er zaboravi da oslobodi m em oriju.
Ovo uvodi nov tip, iako se telo klase sastoji samo od kom entara (zvezdica i kosa crta i
ono to je izm eu tih znakova, o em u e biti rei alje u ovom poglavlju), pa malo ta
moete s njom da uradite. M eutim, rnoete da napravite objekat ovog tipa koristei new:
NekoI m e T i p a a = new N e k o I m e T i p a ( ) ;
Ali klasi ne moete rei da mnogo toga uradi (tj. ne moete joj poslati neke vane po-
ruke) sve dok ne definiete neke njene metode.
Polja i metode
Kada definiete lclasu (a sve to radite u Javi jeste definisanje klasa, pravljenje objekata tih
klasa i slanje poruka tim objektim a), u nju moete staviti dve vrste elemenata: polja (koja
se ponekad nazivaju i podaci lanovi) i metode (koje se katkada nazivaju fimkcije lanice).
Polje je neki od prostih tipova ili objekat bilo kog tipa, s kojim moete da se poveete pu-
tem njegove reference. Reference na objekte m orate da indjalizujete (koristei new, kao
to ste videli ranije), da biste ih povezali sa stvarnim objektima.
Svaki objekat ima zasebno skladite za svoja polja; obino se polja ne dele izmeu obje-
kata iste klase. Evo prim era klase s nekim poljima:
cla s s S a m o P o d a c i {
int i ;
d o u b l e d;
b o o l e a n b;
I
Poglavlje 2 : Sve je objekat 49
Ova klasa ne radi nita, sem to uva neke podatke. Ali ovako moete da napravite objekat:
Poljima moete dodeliti vrednosti, ali prvo m orate da znate kako da se obratite lanu
nekog objekta. To se postie tako to se navede im e reference na taj objekat, zatim sledi
taka pa im e lana u nu tar objekta:
r e f e r e n c a N a O b j e k a t .polj e
Na prim er:
podaci .i = 4 7 ;
p o d a c i . d = 1.1;
p o d a c i . b = false;
Va objekat moe da sadri i druge objekte koji sadre podatke. Samo nastavite da ,,na-
dovezujete take.
Na prim er:
m o j A v i o n . l e v i R e z e r v o a r . k a p a c i t e t = 100;
Klasa SamoPodaci ne moe skoro nita da uradi osim da uva podatke, jer nem a me-
tode. Da biste shvatili metode, prvo m orate da nauite ta su argumenti i povratne vred-
nosti (ubrzo e biti opisani).
boole<an talse
char "\u0000" (nullj
byte |byte)0
short (short)O
mt 0
long 0L
float O.Of
double O.Od
Dobro obratite panju na to da Java jami dodelu podrazum evanih vrednosti samo
kada se promenljiva koristi kao lanica klase. To obezbeuje da prom enljive lanice pro-
stog tipa uvek budu inicijalizovane (to C ++ ne radi), ime se sm anjuje izvor greaka.
Ipak, ova poetna vrednost ne m ora da bude ispravna niti odgovarajua za program koji
piete. Najbolje je da uvek izriito inicijalizujete svoje promenljive.
50 Misliti na Javi
O va garan cija se ne o d n o si na lokalne pro m en ljiv e - o n e koje nisu polja klase. Stoga,
ako u n u ta r definicije m eto d e im ate:
in t x;
P ovratni tip opisuje tip vred n o sti koja se vraa kao rezu ltat m eto d e koju ste pozvali. Li-
sta a rg u m en ata zadaje tipove i im ena inform acija koje elite da p rosledite m etodi. Im e m e-
tode i lista a rg u m en ata (koji zajedno ine njen potpis) jed in stv en o id entifikuju m etodu.
M etode u Javi m o g u biti nap rav ljen e sam o kao deo klase. M etoda m oe da se poziva
sam o za neki o b je k a t, i taj objek at m o ra da b u d e sp o so b an da izvri poziv. Ako po k u ate
da pozovete p ro g re n u m e to d u objekta, d obiete p o ru k u o greci p rilik o m prevoenja.
M eto du objekta pozivate tako to navedete im e olijekta iza koga je taka, zatim im e m e-
tod e i n jenu listu a rg u m en ata, recim o ovako:
Na p rim er, p re tp o stav im o da im ate m eto d u f() koja nem a arg u m e n te i vraa v red n o st
tip a in t. Z atim , ako im ate o b jek at pod im en o m a koji im a m eto d u f(), m oete napisati
sledee:
in t x = a . f ( ) ;
sta tic m etode, o kojim a ete uskoro uiti, rnogu hiti pozvauezd klnsii, bez objekta.
Poglavlje 2: Sveje objekat 51
Lista argumenata
Lista arg u m en ata m etode o dreduje koje inform acije pro sled u jete m etodi. Kao to p re tp o -
stavljate, te inform acije - kao i sve d ru g o u Javi - im aju fo rm u objekata. Stoga u listi argu-
m en ata m o ra te da navedete tipove objekata koji se p ro sle u ju i im en a koja e se ko ristiti za
svaki od njih. Kao i u d ru g im situacijam a u Javi gde se ini da rad ite sa o b jektim a, vi, u
stvari, prosleujete reference.4 Tip reference m o ra da b u d e ispravan. A ko a rg u m e n t treba
da b u d e objekat klase String, o nda m o rate da prosledite objek at tip a String ili e prevodi-
lac prijaviti greku.
R az m o trim o m e to d u iji arg u m en t je objek at tip a String. Sledi definicija m eto d e koja
m o ra biti postavljena u n u ta r definicije ldase d a bi bila prevedena:
in t s k la d is te (S trin g s) {
return s .le n g th () * 2;
}
1 Uz uobiajeno izuzim anje ranijc pom en utih prostih tipova podataka boolean, char, byte, short, int,
iong, float i double. Io pravilu, vi prosletijete objekte, to znai da prosleujete reference na objekte.
52 Misliti na Javi
Vidljivost imena
K ontrola im en a je p ro b le m u svim p ro g ra m sk im jezicim a. Ako k o ristite im e u je d n o m
delu p ro g ra m a, a d ru g i p ro g ra m e r k o risti isto im e u d ru g o m delu, kako da razlikujete
je d n o im e o d d ru g o g i spreite d a se su d a re ? O vo je p o seb n o ozbiljan p ro b lem u C -u jer
p ro g ram esto sadri m o re im en a n e p o d e sn ih za rad . C + + klase (n a k o jim a su zasnovane
Java klase) funkcije u g n e u ju u n u ta r Idasa, pa zato i ne m o g u da se su dare sa im enim a
funkcija u g n e en im u n u ta r d ru g ih ldasa. M e u tim , u C + + -u se i dalje koriste globalni
p o d a ci i g lobalne funkcije p a je su d a ra n je jo uvek m ogue. D a bi se reio taj p ro blem , u
C + + je p o m o u d o d a tn ih rezervisan ih rei uveden itnenski prostor (engl. namespace).
Z ahvaljujui n ov o m p ristu p u , Java je sve to m ogla da izbegne. Za p ravljenje je d n o -
zn an ih im en a za biblioteke, p ro je k ta n ti Jave ele d a ko ristite im e vaeg In te rn e t d o m ena
u o b rn u to m p o retk u , p o to su ta im en a sig u rn o jedinstvena. Poto je im e m og d om en a
MindView.net, m oja u slu n a b ib lio tek a za o tld an jan je n ed o statak a dobila bi im e
net.m indview.utility.foibles. Iza o b rn u to g im en a d o m e n a , ostale take treba da predsta-
vljaju p o d d irek to riju m e.
U Javi 1.0 i Javi 1.1, oznake d o m e n a com, edu, org, net itd. po konvenciji su pisane ve-
likim slovim a, pa bi se b ib liotek a zvala: NET.mindview.utility.foibles. Tokom razvoja
Jave 2 o tk riv en o je da to izaziva pro b lem e, pa se sada celo im e paketa pie m alim slovim a.
O vaj m eh an izam znai da sve vae dato teke au to m atsk i ive u svojim im enskim pro-
sto rim a i da svaka klasa u n u ta r d ato tek e g aran to v an o im a jed in stv en iden tifikator - o
to m e se jezik b rin e u m esto vas.
import j a v a . u t i l, A r r a y L is t ;
kako b iste saoptili p rev o d io cu da elite d a k o ristite Javinu klasu ArrayList. M e u tim , p a-
ket util sadri vie kJasa i m o ete poeleti da ko ristite nekoliko n jih a d a ih p ri to m izriito
ne deklariete. To se lako p ostie o zn ak o m * za slo b o d an izbor:
import j a v a . u t i l
Rezervisana re static
Kada n ap ra v ite klasu, o b i n o opisu jete kako o bjekti te klase izgledaju i kako e se p o n a -
ati. O b jek a t zapravo ne d o b ijate sve d o k ga ne n ap rav ite o p e ra to ro m n e w - u toj taki se
o b je k tu d o d eljuje p ro s to r u m e m o riji (sldadite) i tek tad a m eto d e p o staju d o stu p n e .
Postoje dvc situacije u ko jim a ovaj p ristu p nije dovoljan. Jedna je ako elite da im ate
isto skladite za o d re d e n o polje, Liez o b zira na to koliko o bjekata te ldase n ap rav ite, ili ak
elite da skladite p ostoji iako nije nap ravljen nijedan objekat. D ru g a je ako vam treba
m e to d a koji nije p rid ru e n a n ijed n o m o d re e n o m o b jek tu te klase. O d n o sn o , tre b a vam
m eto d a koju m oete da pozovete iako n ijedan o bjek at nije napravljen.
O b a ova efekta m o ete postii p o m o u rezervisane rei static. Kada neto o znaite kao
static, to znai da o d re d e n o polje ili m e to d a nisu povezani ni s je d n im o b jek to m te Jdase.
Stoga m oete da pozovete m e to d u static ili da p ristu p ite polju static, iako nik ad a niste
n aprav ili objekat te klase. U sluaju uob iajen ih , n estatin ih polja i m eto d a, m o ra te da
n ap ra v ite objekat i da ga ko ristite za p ristu p po lju ili m e to d i.
U n ekim o b je k tn o o rijen tisa n im jezicim a koriste se te rm in i podaci klase 'i m etode klase,
to znai da podaci i m e to d e posto je sam o za klasu u celini, a ne i za o d re en e objekte kla-
se. P onekad se u litera tu ri o Javi tak o e koriste ti term in i.
l)a biste polje ili m eto d u proglasili za statin e, stavite rezervisanu re static p re defi-
nicije. Na p rim er, sledei oblik proizvodi i inicijalizuje statin o polje:
c la s s S ta tic T e s t {
s t a t i c i n t i = 4 7;
}
Cak i ako posle ovoga n ap rav ite dva objekta klase StaticTest, i dalje e posto jati sam o
je d a n p rim e ra k skladita za p ro m en ljiv u StaticTest.i. O ba objekta e deliti istu p ro m e n -
Ijivu i.
N aravno, poto sta tic m etode nc zalitcvaju da ijedan objekat bude napravljen pre nego to e se kori-
stiti, one ne m ogu iliivkliu) da pristupe nestatinim lanicam a ili m etodam a. Poto nestatini lanovi
i m etode m oraju biti povezani sa odgovarajuim objektom , iz statinih m etoda m oete pristupati ne-
statinim lanovim a sam o preko nekog im en ovanogobjekta.
54 Misliti na Javi
S ta tic T e s t s t l = new S t a t i c T e s t ( ) ;
S ta tic T e s t st2 = new S t a t ic T e s t O ;
U ovom tre n u tk u i stl.i i st2.i im aju istu v red n o st, 47, p o to se o d n o se na isti deo ine-
m orije.
Postoje dva nain a za p ristu p statin o j p ro m en ljiv o j. Kao to je po k azan o u p re th o d -
n o m p rim e ru , m o ete joj p ristu p a ti p rek o objekta, n a p rim e r st2.i. M oete joj p ristu p a ti
i d ire k tn o preko im en a klase, to ne m o ete d a u rad ite sa n e stati n o m lanicom .
StaticT e st.i+ + ;
class MozeSeUvecati (
s t a t ic void u ve c a j() { S ta tic T e s t.i+ + ; )
}
Poto je uvecaj() statina m eto d a, m o ete je pozvati d ire k tn o p rek o njene klase:
MozeSeUvecati. u ve caj( ) ;
Iako rezervisana re static, p rim e n je n a na polje, defin itiv n o m enja nain na koji se
p o d a tak stvara (po jed an za svaku klasu u o d n o su na po jedan nestatian za svaki obje-
kat), kada se p rim en i na m eto d u , p ro m e n e nisu tako velike. M etode se oznaavaju rezer
visan o m reju static kako bi se m ogle pozvati iako nije naprav ljen objekat. O vo je veom a
vano, kao to em o videti, za efinisanje m eto d e main() koja je p o etn a taka za pokre-
tan je svih aplikacija.
// Zdravo.java
import ja v a . u t i l
Prevodilac za Javu i Suiiova dokum tntacija stalno se m enjaju i najbolje ih je preuzim ati neposredno
od Suna. Ako je sam i preuzm etc, dobiete najnoviiu verziju.
56 Misliti na Javi
pu b lic c la s s ShowProperties {
public s t a t ic void m a in (S trin g [] args) {
Syste m .g etPro p erties() .1 is t(S y s te m .o u t);
System .out.pri n tl n(System .getProp erty("user.nam e")) ;
Sy ste m .o u t.p rin tln (
System .getProperty( " j a v a . 1i b ra ry .p a th ")) ;
)
} ///:-
Prvi red u m eto d i m a in () p rikazu je sva svojstva (engl. properties) sistem a na kojem
izvravate p ro g ram , dakle daje p o d atk e o o k ru en ju . M etoda list() alje te rezu ltate svom
a rg u m e n tu S y stem .o u t. V ideete u n astavku knjige da ih m oete poslati i na d ru g a m esta,
recim o u neku d ato tek u . M oete zatraiti i o d re e n o svojstvo - u ovom sluaju, korisni-
ko im e (engl. user nam e) i p u ta n ju (engl. path) do Javine biblioteke (engl. library). (M alo
kasnije o b jasniem o n eo b in e k o m en tare na p o etk u i na kraju.)
Prevoenje i izvravanje
Da biste preveli i po k ren u li ovaj p ro g ram , kao i sve d rug e u ovoj knjizi, prvo m o ra te da
im ate razvojno o k ruen je za Javu. Postoji vie nezavisnih razvojnih o k ru en ja, ali p retp o -
staviem o d a koristite b esp latn o razvojno ok ru en je JDK, k o m p an ije Sun M icrosystem s.
Ako koristite neki dru g i razvojni sistem ,' m o raete da pogledate d o k u m en ta ciju za taj si-
stem d a biste saznali kako da p rev o d ite i pokreete p ro g ram e.
Poveite se na In te rn et i p o gledajte W eb lokaciju http://iava.suii.coin. Tam o ete nai
in form acije i veze koje e vas voditi kroz proces p reu zim an ja i in staliran ja )D K -a za vau
p latfo rm u .
O bin o je to IBM -ov prevodilac jikes, koji je zn atn o bri od Sunovog javac (iako razlika nije velika
kada p o m o u Anta pravite grupe datoteka). Postoje i progranii otvorenog koda za pravljenje Java
prevodilaca, izvrnih okruenja i biblioteka.
Poglav[je 2: Sve je objekat 57
ja va c H ello D ate.java
ja v a HelloDate
/* Ovo j e komentar
* koji se n a s ta v lja
* u v i e redova
*/
Dokumentacioni komentari
V erovatno da je najvei p ro b lem p ri d o k u m e n to v a n ju koda bilo o d ravanje d o k u m e n ta -
cije. A ko su k o d i d o k u m en tacija razdvojeni, po staje n ezg o d n o m en jati d o k u m en tac iju
svaki p u t kada p ro m e n ite kod. Reenje izgleda jed n o stav n o : poveite k o d i d o k u m e n ta c i-
ju . N ajlake ete to u ra d iti kad sve stavite u istu d ato tek u . D a biste zaokruili p o stu p ak ,
p o tre b n a je p o seb n a sintaksa za d o k u m e n ta c io n e k o m en tare, kao i alat kojim ete te ko-
m e n ta re izdvojiti i preb aciti ih u k o ristan oblik. To je u rad ila Java.
Alat za izdvajanje k o m en tara naziva se Javadoc i deo je instalacije JDK-a. O n koristi neke
o d tehnologija Java prevodioca da p o trai posebne oznake k o m en tara u p ro g ram u . Izdvaja
oznaene inform acije i izvlai im e klase ili m etode koja ide uz taj kom entar. Na ovaj nain
m oete sa m in im aln o m koliinom rad a generisati p risto jn u doku m en taciju p rogram a.
R ezultat ovog p o stu p k a je H T M L d atotek a ko ju m oete da p regledate p o m o u itaa
W eba. Tako Javadoc om oguava d a na p ra v ite i odrav ate sam o je d n u izv o rn u d ato te k u i
a u to m atsk i generiete k o risn u d o k u m en taciju . Z ahvaljujui p ro g ra m u Javadoc im am o
je d n o stav an sta n d a rd za pravljenje o k u m en tacije, pa m o em o da o ekujem o ili ak za-
h tev am o d o k u m en ta c iju iz svih Java biblioteka.
Uza sve, m o ete n ap isati sopstvene Javadoc id en tifikato re (engl. handlers), doclete,
ukoliko k o m en tare koje je izdvojio Javadoc hoete p o seb n o da o b rad ite (recim o, da ih
ispiete u d rug aijem fo rm a tu ). O d ocletim a itajte u d o d a tk u na h ttp ://M in d V iew .n et/
Books/Betterjava.
Sledi uvod u Javadoc i pregled njegovih obeleja. P o tp u n opis nai ete u d o k u m e n ta -
ciji o JD K-u. Kada je raspakujete, p o tra ite p o d d ire k to riju m tooldocs" ili p ritisn ite istoi-
m en u hipervezu.
Sintaksa
Sve k o m and e p rog ram a Javadocnalaze se iskljuivo u n u ta r k o m entara /**. K om entar se za-
vrava sa */ kao i obino. Postoje dva osnovna naina za korienje ovog sistem a: ugraeni
H TM L ili korienje d o k u m en tacio n ih oznaka (engl. doc tags). Samostojee dokum entacio-
n eo zn a k e su ko m an d e koje p o in ju sa @ i koje se nalaze na poetku reda kom entara. (Zane-
m aruje se vodea zvezdica.) Nesam ostalnc dokum entacionc oznake m ogu biti napisane bilo
gde u n u ta r Javadoc k o m en tara i takode poinju sa @, ali se nalaze izm eu vitiastih zagrada.
Postoje tri tipa d o k u m e n ta c io n ih k o m en tara koji o d govaraju elem en tu k om e kom en-
ta r p reth o di: klasi, polju ili m etodi. K om en tar klase stoji o d m ah ispred d e fin i je klase;
k o m e n ta r polja se pojavljuje o d m a h ispred definicije polja, a k o m e n ta r m etode se javlja
n e p o sred n o ispred definicije m etode. O vo je jed n o stav an prim er:
Ugraeni HTML
Javadoc prep isu je H TM L oznake iz k o m en tara u H T M L d o k u m e n t koji generie. To
o m og u ava p o tp u n o korienje H TM L-a; m e u tim , o sn ov n i cilj je da se o m o g u i fo rm a-
tira n je koda, kao to je:
// : object/Documentation2.java
j
* <pre>
*System .out. p rin tln(n ew Date( ) ) ;
* </pre>
*/
///: '
p u b lic c lass Documentation2 {}
//: object/Documentation3.java
/**
* Moete u b aciti <em>ak</em> i li s t u :
* <ol>
* <li> Prva taka
* <1i> Druga taka
* <1i> Trea taka
* </ol>
*/
pu b lic c lass Documentation3 {}
Primeri oznaka
Evo p rim e ra n ekih Javadoc ozn ak a koje se m o g u stavljati u d o k u m e n ta c iju koda. Pre nego
to p o m o u Javadoca p o k u ate d a u ra d ite bilo ta ozbiljno, treb alo bi da p ro itate n jem u
posveen odeljak u d o k u m e n ta ciji JD K -a i tam o vid ite sve m ogue nain e u p o tre b e
Javadoca.
@see:
O va o zn ak a slui za u p u iv an je na d o k u m e n ta c iju u d ru g im klasam a. Javadoc e generi-
sati HTML sa o zn ak am a @see kao hip erv ezam a po vezanim s d ru g o m d o k u m en tacijo m .
O blici su:
@see imeklase
Psee potpuno-opisano-imeklase
@see potpuno-opisano-imeklase#ime-metode
{docRoot}
D aje relativ n u p u ta n ju d o koren sko g d irek to riju m a d o k u m en tacije. Koristi se za izriito
h iperpovezivanje sa stra n ic a m a u stablu do k u m en tacije.
{@inheritDoc}
Tekui d o k u m en tac io n i k o m e n ta r n asleuje d o k u m en tac iju najblie o sn o v n e klase ove
klase.
@version
N jen oblik je:
gde je informacija-o-verziji bilo koja b itn a inform acija koju treba ukljuiti. Kada sc in-
d ik a to r -version navede na k o m a n d n o j liniji p ro g ram a javadoc, inform acija o verziji e
biti p ro sle en a u gen erisan u H T M L d o k u m en taciju .
@author
N jen oblik je:
@since
O va oznaka o m og u ava da naznaite verziju klase koja je poela da k oristi o d re e n u m o -
gunost. V ideete da se pojavljuje u Java H T M L d o k u m en taciji da naznai koja je verzija
JD K -a koriena.
param
K oristi se za d o k u m e n to v a n je m e to d a u obliku:
@return
Koristi se za d o k u m e n to v a n je m eto d a, a pie se u obliku:
Pretu rn opis
@throws
O izuzecim a g o v o rim o u poglavlju O brada grcaka pom ou izuzctaka. U kratko, to su
objekti koji m og u biti ,,baeni iz m eto d e u sluaju greke. Iako sam o je d an objekat izu-
zetka m oe d a se pojavi kada pozovete m eto d u , o d re en a m eto d a m oe da proizvede vie
razliitih tipova izuzetaka a svi m o raju biti u n a p red naznaeni. Stoga oznaka za izuzetak
im a sledei oblik:
gde p o tp u n o -o p is a n o -im e k la s e nedvosm isleno daje iine klase izuzetka koja je negde de-
finisana, a o p is (koji m oe da se p ro teg n e na nekoliko redova) pokazuje zbog ega odre-
eni tip izuzetka m oe da se pojavi pri pozivu inetoe.
62 Misliti na Javi
deprecated
O vo se koristi da naznai m o g u n osti koje su zastarele. O znaka @deprecated pokazuje da
vie ne treba da koristite tu m ogunost, p o to e uskoro v erovatno biti u klonjena. Prevodi-
lac e vas upozoriti ako koristite m e to d u oznaenu sa @deprecated. U Javi SE5, @depreca-
ted je zam enjena anotacijom @Deprecated (anotacijam a je posveeno poglavlje Anotacije).
Primer dokumentacije
P onovo dajem o prvi p ro g ra m n a Javi, ovog p u ta s d o d a tn im d o k u m e n ta c io n im k o m en -
tarim a:
U prvom redu datoteke koristi se m oja tehnika: stavlja se //: kao posebne oznake za red
s kom entarom koji sadri ime izvorne datoteke. Taj red sadri inform aciju o p utanji do da-
toteke (object oznaava ovo poglavlje), iza koje sledi ime datoteke. Poslednji red takode se
zavrava kom entarom ( / / / : - ) koji oznaava kraj listinga izvornog koda i om oguava da se
taj kod autom atski aurira u tekstu ove knjige (nakon to ga prevodilac p ro v eri) i da se izvri.
O znaka /* Ispis: naznauje poetak izlaza koji e ovaj p ro g ram generisati. U ovom obli-
ku, (55% nratch) naznauje sistem u za testiranje da se izlaz prilin o razlikuje od jed n o g do
drugog izvravanja i da treba da oekuje korelaciju od sam o 55 pro cen ata sa ovde prikaza-
nim izlazom. O d onih p rim era u ovoj knjizi koji im aju neki izlaz, veina e sadrati ovaj
oblik izlaza, pa ete m oi da izvrite svaki pro g ram i da proverite da li m u je izlaz ispravan.
Poglavlje 2: Sve je objekat 63
Stil programiranja
P rem a stilu o p isano m u knjizi Codc C onventions fo r the Java Program m ingLatiguage8 prvo
slovo im en a klase treba da b u d e veliko. A ko se im e klase sastoji o d nekoliko rei, o n e se
piu zaje dn o (tj. ne koristite d o n je crte d a razdvojite im en a ), i prvo slovo svake u g rad en e
rei je veliko, na p rim er:
c lass SveBojeDuge { // . . .
Tako n ap isano im e klase lii n a grbe kam ile. Za skoro sve ostalo: m eto d e, p olja (p ro -
m enljive lanice) i im ena referenci n a objekte, usvojeni stil je isti kao i za klase, osim to
se p rv o slovo identifikatora pie m alo. N a p rim er:
c lass SveBojeDuge {
in t c e o B ro jK o jiP re d s ta v lja B o je ;
void promeniNijansuBoje ( in t novaNijansa) {
//
}
/ /
}
M islite na to kako k o risn ik tak o e m o ra da kuca sva ova ugaka im ena, stoga im ajte
m ilosti.
U Java kodu iz Sunovih b iblioteka k oristi se isti stil p isanja o tv o ren ih i zatv o ren ih vi-
tiastih zagrada p o p u t stila u p o treb ljen o g u ovoj knjizi.
Saetak
Cilj ovog poglavlja je da nau ite tek toliko Jave koliko je dov o ljn o da biste napisali je d n o -
stavan p ro g ram . Stekli ste i uvid u jezik i njegove o sn o v n e pojm ove. Do sada su ipak svi
p rim eri bili u znaku uradi ovo, zatim u rad i o n o , a p o to m neto tree. U n a re d n a dva p o-
glavlja upoznaete o sno v n e o p e rato re koji se u p o treb ljav aju u p ro g ra m ira n ju na Javi i
nauiete da upravljate tok o m p ro g ram a.
Vebe
U b ud ue e vebe biti raspodeljene po celom tek stu poglavlja, ali u ovom su sve vebe sta-
vljene na kraj, poto ste tek nauili da piete najjed n o stav n ije p ro g ram e.
Iza red n o g broja vebe nalazi se broj u zag rad am a, koji u op seg u od 1 do 10 pokazuje
njenu teinu.
Reenja o d a b ra n ih vebi nalaze se u elek tro n sk o m d o k u m e n tu The T hinking in Java
A nno tatcd Solution Guide, koji se m oe k u p iti na adresi w w w .M indV iew .net.
Veba 1: (2) N apiite klasu koja e sad rati neinicijalizovana p o lja tip a int i char, i ispiite
njihove v red n o sti kako biste se uverili da ih Java p o d ra z u m e v a n o inicijalizuje.
Veba 2: (1) N akon p rim e ra Zdravo.java u ov om poglavlju, n a p ra v ite p ro g ra m zdravo,
svete koji p rikazu je d a tu n a re d b u na ek ran u . P o treb n a vam je sam o je d n a m e to d a u klasi
(m a in koja se izvrava kada se p ro g ra m p o k re n e). Setite se da tre b a d a o stan e statina i da
ukljuite listu a rg u m en ata, iako je neete koristiti. Prevedite p ro g ra m k o m a n d o m javac i
p o k ren ite ga k o m a n d o m java. A ko k o ristite razvojno o k ru en je koje je d ru g aije od
JD K -a, n au ite kako d a prevedete i izvrite p ro g ra m e u to m o k ru e n ju .
Veba3: (1) P ro n a ite delove k o d a koji o b u h v ataju klasu NekoImeTipa i p re tv o rite ih u
p ro g ra m koji m oete d a p revedete i izvrite.
Veba 4: (1) P retvo rite delie k od a koji o b u h v ataju klasu SamoPodaci u p ro g ra m koji
m oete d a prevedete i izvrite.
Veba 5: (1) Izm enite p re th o d n o vebanje tako d a v red n o sti p o d a ta k a u klasi SamoPoda-
ci b u d u d o d eljen e i ispisane iz m eto d e main().
Veba 6: (2) N apiite p ro g ra m koji o b u h v ata i poziva m e to d u skladiste(), d efm isan u kao
deo k o da u ovom poglavlju.
Veba 7: (1) Pretvorite MozeSeUvecati delove k o d a u p ro g ra m koji radi.
Veba 8: (3) N apiite p ro g ra m koji po k azu je da postoji sam o je d a n p rim e ra k o d re en o g
statinog polja u klasi, bez o b zira na to koliko objekata te klase n apravite.
Veba 9: (2) N apiite p ro g ra m koji po k azu je da a u to m atsk o pakovanje fu n k cio n ie za sve
pro ste tipove i njihove o m otae.
V eba 10: (2) N apiite p ro g ra m koji ispisuje tri a rg u m e n ta p re u ze ta s k o m a n d n e linije.
Da biste to uradili, pozabavite se ind ek sim a u nizu objekta klase S trin g s k o m a d n e linije.
Veba 11: (1) Pretvorite p rim er SveB ojeD uge u pro g ram koji m oete da prevedete i izvrite.
Veba 12: (2) P ro n a ite ko za d ru g u verziju p ro g ram a Z d rav o .ja v a, koji je jednostavan
p rim e r d o k u m e n ta c io n ih k o m e n ta ra. P rop ustite tu d ato tek u k ro z Jav ad o c i pogledajte
rezultate p o m o u itaa W eba.
Veba 13: (1) P ro p u stite kroz Jav ad o c dato teke D o k u m en tacija 1.java, D o k u m en taci-
ja2.java i D okum entacija3 .jav a, i p ro v erite rezultate p o m o u itaa W eba.
V eba 14: (1) D od ajte H T M L listu d o k u m en taciji u p re th o d n o m vebanju.
Veba 15: (1) U zm ite p ro g ra tn iz vebe 2 i d o d ajte m u d o k u m e n ta c io n e k o m en tare. Iz-
dvojite te d o k u m e n ta c io n e k o m e n ta re u H TM L daiOteku koristei Jav ad o c i pregledajte
ih p o m o u itaa W eba.
V eba 16: (1) U poglavlju Inicijnlizacijn i ienje p ro n a ite p rim e r P re ld a p a n je .ja v a i do-
dajte m u d o k u m e n ta c io n e k o m en tare . Izdvojite te d o k u m e n ta c io n e k o m e n ta re u H TM L
d ato te k u koristei Jav ad o c i p regledajte ih p o m o u itaa W eba.
Operatori
N a n ajniem nivou, u Javi se s podacim a radi pom ou operatora.
Priori teti
P rioriteti o p erato ra definiu kako e izraz biti izrau n at kada se u n jem u javlja vi.e ope-
rato ra. Java im a specifina p ravila koja o d re u ju p o red ak izraunavanja. Najlake se
p am ti pravilo da se m n o en je i deljenje vre p re sab iranja i o d u zim an ja. P ro gram eri esto
zaborave ostala pravila o p rio rite tim a , p a stoga nije na o d m e t da koristite zagrade za iz-
riito navoenje p o retk a izraun av an ja. Na p rim er, p ogledajte n ared b e (1) i (2):
//: o p e r a t o r i/ P r io r it e t i.java
public c lass P r io r i t e t i {
public s t a t ic void main ( S t r i ng[] args) {
in t x = 1, y = 2, z = 3;
in t a = x + y - 2/2 + z; // (1)
in t b = x + (y - 2)/(2 + z ); // (2)
System .o u t.p rin t1 n ("a = " + a + " b = " + b ) ;
I
} /* Is p is :
a = 5 b = 1
* ///:-
Poglav[je 3: Operatori 67
Te n ared b e izgledaju gotovo jed n ak o , ali iz izlaza vidite d a zbog u p o treb e zagrada u (2)
im aju sasvim razliita znaenja.
O b ra tite pan ju na u p o tre b u o p e ra to ra + u n ared b i System.out.println(). U to m k o n -
tekstu , + znai nadovezivanje zn ak o v n ih nizova i, ako treb a, konverzija zn ak o v n ih ni-
zova. Kada p revodilac n ai e na String + ne-String, p ok u ae d a k o n v ertu je ne-String u
String. Kao to vid ite iz izlaza, a i b je u sp en o konv erto vao iz tip a int u String.
Dodela vrednosti
V red n ost se dodeljuje o p e ra to ro m = . O n znai u zm i v red n o st s d esn e stra n e koja se esto
naziva dvrcdnost (engl. rvalue), i kopiraj ie n a levu stra n u , koja se esto naziva Ivrednost
(engl. lvalue). D vrednost je bilo koja k o n sta n ta, p ro m en ljiv a ili izraz koji m oe d a se iz-
raun a, ali Ivrednost m o ra da b u d e p o seb n a im en o v an a pro m en ljiv a. (O d n o sn o , m o ra
p o sto jati fiziki p ro sto r za sm etan je te v red n o sti.) N a p rim er, m o ete d odeliti k o n sta n t-
n u v red n o st prom enljivoj
a = 4;
c lass Rezervoar {
in t nivo;
}
Klasa Rezervoar je je d n o sta v n a i njena dva p rim e rk a (rl i r2) n ap rav ljen a su u m eto d i
m ain(). Polju nivo u svakom p rim e rk u klase Rezervoar d od eljen e su razliite v rednosti,
zatim je v red n o st r2 d o d eljen a p rim e rk u rl i p o to m je r l p ro m en jen . U m n o g im p ro -
g ram sk im jezicim a oekivali b iste da su r l i r2 nezavisni sve vrem e, ali, p o to ste d odelji-
vali reference, kada se izm eni o b jek at rl, m enja se i objekat r2, zato to i r l i r2 sare istu
referencu koja pokazuje na isti objekat. (P rv o b itn a referenca koja se nalazila u rl i koja je
pokazivala na objekat koji je uvao v red n o st 9, izm en jen a je p rilik o m odele i efektivno
izgubljena; n jen objekat e p o istiti sakuplja sm ea).
O vaj fenom en esto se naziva pojavap scu d o n im a (engl. aliasing), i on je u o snovi nain
na koji Java rad i sa o b jek tim a. Ali ta ako neete da se u ovom sluaju pojavi pseu d o n im ?
M oete da precizirate d o d elu i d a napiete:
r l.n iv o = r2 .n ivo ;
cla s s Slovo {
char c;
Poglavlje 3: Operatori 69
y .c = ' z ' ;
Matematiki operatori
O sn ov ni m atem atik i o p e ra to ri su isti kao i u veini p ro g ram sk ih jezika: sabiranje (+ ),
o d u z im an je (-), deljenje (/), m n o en je (*) i m o d u lo (% ), koji daje o statak p ri celobroj-
n o m deljen ju. Pri celo b ro jn o m deljenju odseca se realni deo, a ne zaok ru u je rezuitat.
Java tako d e koristi skraeni C /C + + zapis za isto v rem en o ob avljanje o p eracije i doele.
To se naznaava na sledei nain: iza o p erato ra sledi znak jedn ako sti, i d o sled n o se m oe
p rim e n iti na sve o p era to re u jeziku (kada to im a sm isla). Na p rim e r: da biste d o dali 4 p ro -
m enljivoj x i rezultat dodelili x, piite: x + = 4.
O vaj p rim e r p okazuje korienje m atem atik ih op erato ra:
p r in t("u /= v : + u );
) /* Is p is :
j : 59
k : 56
j + k : 115
j - k : 3
k / j : 0
k * j : 3304
k % j : 56
j %= k : 3
Poglavlje 3: Operatori 71
v : 0.5309454
w : 0.0534122
v + w : 0.5843576
v - w : 0.47753322
v * w : 0.028358952
v / w : 9.940527
u += v : 10.471473
u -= v : 9.940527
u *= v : 5.2778773
u /= v : 9.940527
* ///:-
x = -a ;
x = a * -b;
x = a * (-b );
Broj 4 / se sm atrao arobnim brojem " na koledu koji sani pohaao, pa m i se to urezalo u seanje.
72 Misliti na Javi
Jedno o d objanjenja za p o rek lo im en a C + + , koje znai jed an k o rak dalje o d C -a, lei
u o p e ra to ru uveanja. U vrem e n a sta n k a Jave, Bill Joy (jedan o d a u to ra Jave) rekao je da
je Java = C + + (C p lus p lu s m in u s m in u s), nagovetavajui kako je Java jezik C + + iz
kojeg su izbaeni n e p o tre b n i teki delovi, pa je zbog toga m n o g o jednostavnija. to b u -
dete vie napred ovali kroz ovu k njigu, videete da su m n o g i delovi jednostavniji, ali im a
d ru g ih stvari zbog kojih Java ipak nije m n o g o jed n o stav n ija o d C + + -a .
Operatori poreenja
R ezultat o p e ra to ra p o re en ja je logika v re d n o st (boolean). O n i o cen ju ju relaciju izm e-
d u v re d n o sti dva o p era n d a. Izraz sa o p e ra to rim a p o re e n ja daje v re d n o st true ako je re-
lacija tan a i false ako je relacija n eta n a. O p e ra to ri p o re en ja su m an je o d (< ), vee od
(> ), m an je ili jed n ak o (< = ), vee ili jed n ak o (> = ), jed n a k o (= = ) i razliito (!=). Jednakost
i razliitost se m ogu p rim e n iti n a sve proste tip o v e p o d atak a , ali se ostala p o re en ja ne
m o g u p rim e n iti na tip boolean. O b jekti tip a boolean m o g u im ati sam o v red n o sti true ili
false, p a ne bi im alo sm isla tra iti koji o d njih je vei, a koji m anji.
R ezultat e sada biti kao to i oekujete. Ah, ali to ipak nije ba tako jed n o stav n o . Ako
sam i n ap rav ite klasu, na p rim er:
c lass Vrednost {
i nt i ;
}
public class MetodaEquals2 {
p ublic s t a t ic void main (S t r in g [] args) {
Vrednost v l = new V red n o st();
Vrednost v2 = new VrednostO ;
v l . i = v2 .i = 100;
System .out.pri n t l n ( v l . equ als(v 2 )) ;
}
} /* Is p is :
fa l se
* ///:-
Logiki operatori
Logiki o p e ra to ri konju n k cija (&&), d isjunkcija (II) i negacija (!) daju v re d n o sti true ili
false tipa boolean. U ovom p rim e ru k oriste se o p e ra to ri p o re e n ja i logiki o p erato ri:
// Tip in t u Ja v i ne moe da se
// k o ris ti kao lo g i k i tip
//! p r i n t ( " i && j je " + ( i && j ) ) ;
//! p r i n t ( " i I I j je " + ( i | ( j ) ) ;
//! p r i n t ( " ! i je " + ! i ) ;
p r in t("(i < 10) && (j < 10) je "
+ ( (i < 10) && (j < 10)) ) ;
p r in t (" (i < 10) j | (j < 10) je "
+ ( (i <10) || ( j < 10)) ) ;
}
} /* Is p is :
i = 58
j = 55
i > j je true
i < j je fa ls e
i >= j je true
i <= j je fa ls e
i == j je fa ls e
i != j je true
(i < 10) && (j < 10) je fa ls e
(i < 10) || (j < 10) je fa ls e
* ///:-
O p erato re konjunkcije, disjunkcije i negacije m oete p rim e n iti sam o na v red n o sti tip a
b o o le an . Za logike uslove ne m oete da koristite ostale (nelogike) tipove, kao u jezici-
m a C i C + + . O vakve neuspele pokuaje m oete v ideti u k o m e n ta rim a sa o zn ak o m //!
76 Misliti na Javi
Nepotpuno izraunavanje
K ada rad ite s logikim o p e ra to rim a , naii ete na fen o m en p o d nazivom n e p o tp u n o iz-
rau n av an je. To znai da e izraz b iti izrau n av an sam o do tren u tk a kada tan o st ili ne-
ta n o st celog izraza m oe n ed v o sm islen o da se odredi. Z ato p reostali delovi logikog
izraza u opte nee b iti izrau n ati. Evo p rim era koji p o kazuje n ep o tp u n o izraunavanje:
Svaki test vri p o re en je sa a rg u m e n to m i vraa v re d n o sti true ili false. T akoe ispi-
suje i p o ru k u da je bio pozvan. Testovi se pozivaju preko sledeeg izraza:
P riro d n o je da pom islite kako e sva tri testa biti izvrena, ali izlaz pokazuje drugaije:
Prvi test daje rezultat tr u e pa se izraunavanje izraza nastavlja. M eutim , drug i test daje re-
zu ltat false. Poto to znai da e i rezultat celog izraza sigurno biti false, zato nastavljati iz-
raunavanje izraza? To m oe da potraje. Ba zbog toga se koristi n e p o tp u n o izraunavanje:
ako ne treba do kraja izraunavati sve delove logikog izraza, p ro g ram e m oda raditi bre.
Literali
Kada u p ro g ra m u doslov n o n avodite v re no sti, prevodilac o b in o tan o zna kojim tip o m
da ih p redstavi. P o nek ad se m oe javiti n ed ou m ica. U to m sluaju m o rate da n avo dite
p rev o d io ca d o d a tn im in fo rm ac ijam a u oblik u znakova p rid ru e n ih v red n o sti literala.
Sledei p rim e r po k azu je te znakove:
c : 1111111111111111
b: 1111111
s : 111111111111111
* /// -
Slovo iza literala zadaje njegov tip. Veliko ili m alo L oznaava tip long (m e u tim , m alo
1 zb un juje zato to lii n a jed in icu ). Veliko ili m alo F oznaava tip float. Veliko ili m alo D
oznaava tip double.
Sve celo b ro jn e tipove p o d atak a m ogue je zadavati u h ek sad ecim aln o m obliku (sa
o sn o vom 16), n azn aav an jem v o d eim 0x ili 0X n ak o n ega slede sim boli 0 -9 i a -f, bilo
m alim ili velikim slovim a. A ko p o k u ate da inicijalizujete p ro m en ljiv u v red n o u veom
od one koju m oe d a uva (bez o b zira na n u m erik i oblik v red n o sti), prevodilac e pri-
javiti greku. U g o rn jem p rim e ru o b ra tite p an ju na m aksim alne m ogue heksadecim al-
ne v red n o sti za tipove char, byte i short. Ako ih p rekoraite, prevodilac e ih auto m atsk i
p retv o riti u int i jav iti kako treb a izvriti suavanje eksplicitnom konverzijom za d a tu d o-
delu. (E ksplicitne konverzije su d efin isan e u nastavku poglavlja.) Tada ete znati da ste
prekoraili dozvo ljen u v red n o st.
O ktalni ob lik (sa o sn o v o m 8) nazn aav a se v odeom n u lo m u zapisu broja, koju slede
cifre 0 -7 .
U C -u, C + + -u i Javi ne postoji prikaz b in arn ih brojeva kao literala. M eutim , pri rad u s
heksadecim alnim i o k taln im zapisom rezultate je podesno prikazati u b in a rn o m obliku. To
se lako postie m eto d am a static toBinaryString() iz klasa Integer i Long. Im ajte u vidu da
se m anji tipovi autom atski k o nvertuju u int kada se proslede u Integer.toBinaryString().
Veba 8: (2) Pokaite da hek sad ecim aln i i o k taln i zapis rade s brojevim a tipa long. Za pri-
kazivanje rezultata u p o treb ite Long.toBinaryString().
Eksponencijalni zapis
Za ekspon en cijaln i zapis realnog b ro ja k oristi se notacija koju sam o duvek sm atrao
o b esh ra b ru ju o m .
U nauci i inen jerstv u e o znaava o sno vu p riro d n o g logaritm a, koja otprilike iznosi
2,718. (Preciznija v re d n o st tip a d o u b le je d o stu p n a u Javi kao M ath.E .) O n a se k o risti u
ek sp o n en cijaln im izrazim a kao to su 1,39 x e'43, to znai 1,39 x 2,71843. T vorci FOR-
T R A N -a odluili su d a e e znaiti deset na step en , to je u dn o, je r se FO RTRAN u p o -
trebljava u nauci i inenjerstvu, i svako je m ogao pom isliti d a e tvorci o b ra titi p a n ju na
takvu d vo sm islen ost.2 Bilo kako bilo, ovaj obiaj je nastavljen u C -u , C + + -u i sada u Javi.
Stoga, ako ste se navikli na e kao na o sn ov u p riro d n o g logaritm a, o b ra tite p a n ju kad a u
Javi v id ite izraz kao to je 1,39 e-43f; o n o znaava 1,39 x 10~43.
P ratei znak n e m o ra te da k o ristite kada prevodilac m oe sam da o d red i odgovarajui
tip. Kada napiete:
long n3 = 200;
nem a dvosm islenosti, pa je L iza bro ja 200 iziino. M e utim , kada napiete:
John K irkham jc napisao: R aunarim a sam poeo da se bavim 1962. koristei FORTRAN II na m ai-
ni IBM 1620. U to vrem e, tokom ezdesetih i poetkom sedam desetih, FORTRAN je u p o tp u n o sti
pisan velikim slovim a. To potic verovatno od toga to su stari ureaji za u no s koristili 5-bitni Bau-
d o to v kod koji nije p o d r/av ao m ala slova. Slovo E je u eksponencijalnoj notaciji uvek pisano kao ve-
liko i nikada nije bilo m eano sa osnovom p riro d n o g logaritm a, e, koja se uvek pie m alim slovom .
H je oznaavalo eksponent, obino 10, za korieni brojni sistem. U to vrem e i oktalni form at je bio
iroko rasp ro stranjen m edu p rogram erim a. Da sam naiao na oktalni broj u eksponencijalnoj nota-
ciji, sm a trao bih da je osnova 8. Seam se da sam p rvi p ut video eksponencijalni zapis napisan s
m alim e u kasnim sedam desetim i sm atrao sam ga zbunjujuim . Froblem se pojavio kada su m ala
slova p ro d rla u FORTRAN, ne na saniom poetku. Mi sm o, u stvari, imali funkcije koje sm o koristili
ako nam je zaista bila potrebna osnova p riro d n o g logaritm a, ali su sve bile pisane velikim slovim a.
80 Misliti na Javi
daje n u lu sam o ako su oba ulazna bita jednaka nuli. Iskljuiva disjunkcija nad bitovim a ili
XOR ( A) daje jedinicu kao v red n o st izlaznog bita, ako je jed an ili d ru g i ulazni bit je d n a k je -
dinici, ali ne i oba. Negacija nad bitovim a (~ , koja se takoe naziva i operatorprvogkom ple-
m enta) jeste u n a rn i o p erato r; im a sam o jed an arg u m en t. (Svi ostali o p erato ri n ad bitovim a
su b in a rn i o p erato ri - im aju dva o p eran d a.) Negacija n ad b ito v im a daje negaciju ulaznog
bita - jed inicu ako je ulazni b it je d n ak nuli i n u lu ako je ulazni b it jed n ak jedinici.
Za o p erato re n ad b ito v im a i logike o p e rato re k o riste se isti sim boli, p a e v am biti
lake da se setite znaenja ako se d o setite sledeeg: p o to su bito v i ,,m ali, za o p erato re nad
b ito v im a koristi se sam o p o jed an znak.
O p e ra to ri n a d b ito v im a m o g u da se k o m b in u ju sa z n ak o m = i tim e u jed in e operaciju
sa dodeljivanjem : dozvoljeni su &=, 1= i A=. (Poto je ~ u n a rn i o p erato r, o n ne m oe da
se k o m b in u je sa zn ak o m =.)
T ip boolean se tre tira kao je d n o b itn a v red n o st, pa je situacija neto d rugaija. N ad
njim m oete da p rim e n ite k o n ju n k ciju , d isju n k ciju i iskljuivu d isju n k ciju n ad bitovim a,
ali ne i negaciju nad b ito v im a (verovatno da bi se izbeglo m eanje s logikom negacijom ).
Za tip boolean o p e rato ri n ad b ito v im a im aju isti efekat kao i logiki o p e ra to ri, osim to
se n e javlja n e p o tp u n o izraunavanje. O p e ra to r iskljuive disju n k cije n ad b ito v im a nem a
ekvivalentan logiki op erato r. Z ato ovaj o p e ra to r predstavlja jed in i nain da n a dve vred-
nosti tipa boolean p rim e n ite o p eraciju XOR. Na pro m en ljiv e tip a b o o le a n ne m oete
p rim en jiv ati o p erato re p o m e ran ja koje em o u p rav o opisati.
Veba 10: (3) N apiite p ro g ram s dve b in a rn e k o n stan te koje im aju n aizm en in e jedinice
i nule, s tim to je prvoj na n ajm an je zn aajn o m m estu nula, a d ru g o j jed in ica. (U putstvo:
to e vam biti najlake s hek sad ecim aln im k o n sta n tam a). Z ad ajte ta dva b ro ja kao arg u -
m en te svih o p e ra to ra n ad bito v im a na sve m o g u e naine, a rezu ltate prikaite m eto d o m
Integer.toBinaryString().
Operatori pomeranja
O p erato ri p o m e ran ja (engl. shift) takoe rade s bitovim a. O ni m o g u da se k oriste isklju-
ivo s p ro stim , celobrojnim tip o v im a. O p e ra to r p o m era n ja ulevo (< < ) kao rezultat daje
o p e ra n d s leve stra n e o p e rato ra, p o m e ren ulevo za broj bitova naveden n.ikon o p erato ra
(nii bitovi p o p u n jav aju se n u lan ia). O p e ra to r o zn aen o g p o m e ran ja u d esn o (> > ) kao
rezultat daje o p e ra n d s Ieve stra n e o p e ra to ra , p o m eren u d esn o za bro j bitova naveden na-
kon o p erato ra . O zn aen o p o m eran je ud esn o > > k oristi produavanje uz oiivanje znaka
(engl. sign extension)\ ako je v red n o st p ozitivna, vii bitovi se p o p u n jav aju nu lo m ; ako je
v red n o st negativna, vii bitovi se p o p u n jav aju jedinicom . U Javu je takoe d o d a to i neo-
znaen o p o m e ran je u d esn o > koje k oristi produavanje nz dodavanje nula (engl. zero
extension): bez o bzira na znak, vii bitovi se p o p u n jav aju n u lo m . Ovaj o p e ra to r ne postoji
u C -u ili C++-U.
Ako p o m e ra te v red n osti tip a char, byte ili short, on e e biti p ro iren e na int pre nego
to se izvri p o m eran je i rezu ltat e biti tip a int. Koristi se sam o p et niih b itova vrednosti
s desne stra n e o p erato ra. O vo vas spreava da izvrite p o m eran je za vie m esta nego to
ima bitova u ru ita r p ro m en ljiv e tip a int. Ako o periete n ad v red n o u tipa long, dobiete
Poglavlje 3: Operatori 81
rezu ltat tipa Iong. Bie k orieno sam o est niih b ito v a v re d n o sti s desne stra n e o p era-
to ra, pa ne m oete da izvrite p o m e ra n je za vie m esta nego to im a b itova u n u ta r p ro -
m enljive tip a long.
P om eranje m oe da se k o m b in u je sa z n ak o m jed n ak o sti ( = ili = ili > = ) .
L vrednost se zam enjuje v red n o u lv red no st p o m e re n o m za d v re d n o st m esta. Kada se
n eozn aen o p o m eran je u d esn o k o m b in u je sa d o d e lo m , po sto ji p ro blem . A ko ovu o p era-
ciju p rim e n ite na vredn o sti tip a b y te ili short, neete d o b iti p rav iln e rezultate. U m esto
toga, on e se p ro iru ju na int, p o m e ra ju ud esn o, ali se sk rau ju p riiik o m d odele, pa u tim
sluajevim a kao rezultat d obijate 1. To pok azuje n a red n i p rim er:
//: operatori/NeoznacenoPomeranjeUdesno.java
// Test za neoznaeno pomeranje udesno.
import s t a t ic n e t.m in d v ie w .u til. P r in t . * ;
long 1 = s lu c a ja n . nextlong( ) ;
long m = s lu c a ja n . nex tLo n g();
p rin tB in a ry L o n g ("- lL ", -1L);
prin tB in aryLo n g (" +1L , +1L);
long 11 = 9223372036854775807L;
pri ntBi naryLong( " n a jv e i", 11);
long 11n = -9223372036854775808L;
p rin tB i naryLong("najmanj i " , 11 n ) ;
pri ntBi naryLong ( " 1 " , 1 );
p rin tB in aryLo n g ("~ 1 " , -1);
p rin tBin aryLong( " - 1 " , -1);
prin tB in aryLon g ("m ", m);
p rin tB in a ryLo n g ("l & m", 1 & m);
p rin tB in a ryLo n g ("l | m", 1 | m);
p rin tB in aryLo n g ("l " m", 1 ^ m);
p r intBinaryLong("1 5 ", 1 5 );
Poglavlje 3: Operatori 83
* // /= -
84 Misliti na Javi
return i * 100;
el se
return i * 10;
}
p ub lic s t a t ic void m a in (S trin g [] args) {
p r in t ( t e r n a r n i( 9 ) ) ;
p r in t ( t e r n a r n i(1 0 ));
p r in t ( s t a n d a r d n iIf E ls e ( 9 ) ) ;
p r in t ( s t a n d a r d n iIf E ls e ( lO ) ) ;
}
} /* Is p is :
900
100
900
100
* ///:-
V idite d a je k o d m eto d e ternarni() saetiji od o noga to biste m o rali pisati d a te rn a r-
nog o p e ra to ra nem a, kao u m eto d i standardniIfElse(). M e u tim , standardniIfElse() se
lake ita i bre pie. Stoga d o b ro razm islite p re nego to u p o treb ite te rn a rn i o p e ra to r -
po pravilu, to je u m esn o kada pro m en ljiv o j dodelju jete je d n u od dve v rednosti.
while (x = y) {
/ /
}
Kao to vidite, eksplicitnu konverziju je m ogue izvriti na nu m erik o j vred n o sti, kao
i na p rom enljivoj. Im ajte u vidu da je ozvoljena i izlina eksplicitna konverzija. Na p ri-
m er, prevodilac, kad god treb a, a u to m atsk i prevodi v red n o st tip a int u tip long; ipak, su-
vina konverzija se dozvoljava, je r tim e m oete d a ie naglasite ili da kod u inite jasnijim .
U d ru g im situacijam a, eksplicitna konverzija m oe b iti n e o p h o d n a da bi kod uop te m o -
gao biti preveden.
U C -u i C++-U , a u to m atsk a konverzija m oe izazvati m alo glavobolie. U Javi je a u to -
m atska konverzija b ezb ed n a osim kada vrite takozvanu snavajuu konverziju (tj. kada
prelazite sa tipa p o d atak a koji m oe da uva vie inform acija na onaj koji uva m anje), pri
em u rizikujete da izgubite inform acije. U to m siuaju prevoilac vas prisiljava da vrite
eksplicitn u konverziju, obavetavajui vas na taj nain da ,,to m oe biti op asn o - a ako
ipak to elite, m oraete izriito da traite konverziju. Proiirujuu konverzijn ne treba iz-
riito zahtevati jer novi tip m oe da uva z n a tn o vie in fo rm acija nego stari, pa se infor-
m acije nikad ne gube.
Java dozvoljava da izvrite e k sp li tn u konverziju iz bilo kog pro sto g tipa u bilo koji
dru gi prost tip, izuzev tipa boolean koji u o p te ne m oete k o nvertovati. Klase takoe ne
dozvoljavaju eksplicitnu konverziju. Da biste konvertovali jed n u klasu u d ru g u , za to
m o ra da postoji posebna m etoda. (Kasnije u knjizi videete i da se m oe vriti eksplicitna
konverzija objekata u o k v iru porodice tipova; Hrast m oe biti eksplicitno k o nvertovan u
Drvo i o b rn u to , ali ne i u stran i tip kao to je Stena.)
88 Misliti na Javi
Odsecanje i zaokruivanje
K ada obavljate suavajuu konverziju, m o ra te p aziti na odsecan je i zaokru iv an je. P rim e-
ra rad i, ako realan bro j tip a float izriito p retv o rite u ceo bro j tip a int, ta u ra d i Java? Na
p rim er, broj 29.7 p retv arate u int - hoete li d o b iti 30 ili 29? O d g o v o r n a to p ita n je nave-
d e n je u sledeem p rim e ru :
Dakle, odgovor je da se p rilik o m eksplicitne konverzije tipa float ili double u ceo broj
(tip int), decim ale uvek odsecaju. U koliko h oete da rezultat b u d e z ao k ru en , u p o tre b ite
m e to d u round() iz b iblioteke java.lang.Math:
Poto round() p rip ad a biblioteci java.Iang, nije p o tre b n a p o seb n a n ared b a iinport za
n jen o uvoenje i korienje.
Unapreenje tipova
Ako vrite bilo koju m atem atik u operaciju i operaciju nad b itov im a s p ro stim tipo vim a
p o datak a, koji su m anji o d int (tj., char, byte ili short), videete d a e te v red n o sti b iti u n a-
p re en e u tip int pre nego to se operacije izvre, a rezultat e tak o e biti tipa int. Stoga,
ako tu v red n o st elite da p onovo dodelite m an jem tip u , rn orate da koristite eksplicitnu
konverziju. (A poto vrite d o d elu m an jem tip u , m o gu se izgubiti inform acije.) U prin ci-
p u , najvei tip p o datak a u izrazu o d re u je veliinu rezu ltata tog izraza; ako p o m n o ite flo-
at i double, rezultat e b iti tipa double; ako saberete int i long, rezultat e biti tip a long.
// A ritm e ti k i o p e ra to ri:
// X = X * y;
// X = x / y ;
// X = x % y;
// X = x + y;
// X = x - y ;
// x++
// X--
// X = +y;
// X = -y;
// Poreenje i
// f(x > y ) ;
// f (X >= y ) ;
// f(x < y ) ;
// f(x <= y ) ;
f(x == y ) ;
f(x != y ) ;
f(!y );
x = x && y;
x = x || y;
// Operatori nad bitovim a:
//! x = ~y;
x = x & y;
x = x | y;
x = x ~ y;
//! x = x 1;
//! x = x 1;
/ / ! x = x > 1;
// Sloena dodela:
// x += y;
// x -= y;
// x *= y;
// x /= y;
// x %= y;
// x = 1;
// x = 1;
// X >= 1
x &= y;
x A= y;
x |= y ;
// E k s p lic itn a kon verzija:
//! char c = (ch ar)x ;
//! byte b = (b yte)x ;
//! short s = (s h o rt)x ;
//! in t i = ( in t ) x ;
//! long 1 = (lon g)x ;
//! flo a t f = (f lo a t ) x ;
//! double d = (double)x;
1
void charTest(char x, char y) {
Poglavlje 3: Operatori 91
// A ritm e ti k i o p e ra to ri:
x = (c h a r)(x * y );
x = (c h a r)(x / y );
x = (c h a r)(x % y );
x = (c h a r)(x + y );
x = (c h a r)(x - y );
x++;
x--;
x = (char)+ y;
x = (ch ar)- y;
// Poreenje i lo g i k i:
f(x > y ) ;
f(x >= y ) ;
f(x < y ) ;
f(x <= y ) ;
f(x == y ) ;
f(x ! = y ) ;
//! f ( ! x ) ;
//! f(x && y ) ;
//! f(x || y ) ;
// Operatori nad bitovima:
x= (ch ar)~ y;
x = (c h a r)(x & y ) ;
x = (c h a r)(x | y ) ;
x = (c h a r)(x ~ y ) ;
x = (c h a r)(x 1);
x = (c h a r)(x 1);
x = (char) (x > 1);
// Sloena dodela:
x += y;
x -= y;
x *= y;
x /= y;
x %= y ;
X = 1;
X = 1 ;
X > = 1;
x &= y;
x "= y ;
x |= y;
// E k s p lic itn a konverzija:
//! boolean bl = (boolean)x;
byte b = (b yte )x ;
short s = (s h o rt)x ;
in t i = ( in t ) x ;
long 1 = (lon g )x ;
flo a t f = ( f lo a t ) x ;
double d = (double)x;
)
void byteTest(byte x, byte y) {
92 Misliti na Javi
// A ritm e ti k i o p e ra to ri:
X = (s h o rt)(x * y ) ;
x = ( s h o r t ) (x / y ) ;
x = (s h o rt)(x % y ) ;
x = (s h o rt)(x + y ) ;
x = (s h o rt)(x - y ) ;
x++;
x--;
x = (sh ort)+ y;
x = (s h o rt)- y ;
// Poreenje i lo g i k i:
f(x > y ) ;
f(x >= y ) ;
f (x < y ) ;
f(x <= y ) ;
f(x == y ) ;
f (x ! = y ) ;
//! f(!x );
//! f(x && y ) ;
//! f(x || y ) ;
// Operatori nad bitovim a:
x = (sh o rt)~ y ;
x = (s h o rt)(x & y ) ;
x = (sh o rt) (x | y ) ;
x = (s h o rt)(x ~ y ) ;
x = (s h o rt)(x 1 );
x = (s h o rt)(x 1 );
x = (sh o rt) (x > 1 );
// Sloena dodela:
x += y ;
x -= y;
x *= y;
x /= y;
x %= y;
x = 1;
X = 1;
X > = 1;
x &= y;
x "= y ;
x 1= y ;
// E k s p lic itn a ko n verz ija:
//! boolean bl = (boolean)x;
char c = (ch a r)x ;
byte b = (b yte )x ;
in t i = ( in t ) x ;
long 1 = (lo n g )x ;
flo a t f = ( f 1o a t )x ;
double d = (double)x;
)
void in t T e s t(in t x, in t y) {
94 Misliti na Javi
Saetak
Ako im ate iskustva s bilo kojim jezik o m ija je sintaksa slina C -ovoj, videli ste kako su Ja-
vini o p e rato ri toliko slini o n im a iz vam a zn a n ih jezika da ih gotovo ni ne treb a uiti.
U koliko vam je poglavlje bilo tesko, p ogledajte m u ltim ed ijsk u prezentaciju T hinking in C,
koja je d o stu p n a na adresi www.M iin1Vicw.iici.
Reenja odabranih vebi data su u elektronskom dokumentu Thinking in lava Annotatcd Solution
Guide, koji se moe kupiti na lokaciji tvww.MindView.rwt.
Kontrolisanje izvravanja
Kao i svesno bie, i program tnora da upravlja svojim okruenjem i da bira ta e da radi.
U lavi birate pom ou naredaba za kontrolisanje toka programa.
JAVA KORISTI SVE NAREDBE JEZIKA C ZA KONTROLU IZVRAVANJA, STOGA E VAM, AKO STE
p ro g ram ira li na C -u ili C ++-U , vei deo ovoga to sledi biti p o zn at. M n ogi p ro ced u raln i
p ro g ram sk i jezici im aju neku v rstu n ared b e za k o n tro lu i m e u jezicim a esto posto je
slinosti. M e u rezervisane rei za k o n tro lu izvravanja u Javi sp ad aju if-else, while, do-
while, for, return, break i n are d b u izbora switch. Java, m e u tim , ne p o d rava p rilin o
o p a sn u n a re d b u goto (koja i dalje m oe b iti najefikasniji nain za reavanje o d re e n e vr-
ste p ro b lem a ). I dalje m oete da n ap rav ite skok koji je nalik na goto, ali je m n o g o vie
o g ran ien o d tip in e nared b e goto.
Logike vrednosti
Sve uslovne n ared b e koriste tan o st i n etan o st uslovnih izraza da bi odredile to k izvra-
vanja. P rim er uslovnog izraza je a = = b. Tu se k o risti o p e ra to r p o re en ja = = d a se utvrdi
da li je v red n o st a jed n ak a v red n osti b. Ovaj izraz vraa true ili false. I bilo koji o p e ra to r
p o re en ja iz p re th o d n o g poglavlja m oe se ko ristiti za fo rm iran je uslovnog izraza. O b ra-
tite p an ju na to da Java ne dozvoljava da kao logiki tip (boolean) koristite broj, iako je
to dozvoljeno u C -u i C ++-U (gde je tan o sve razliito o d nule, a n eta n o je nu ia). Ako
elite da k o ristite nelogiki tip u logikom testu, na p rim e r if(a), prvo ga m o rate pretvo-
riti u v re d n o st tipa boolean p o m o u usiovnog izraza, na p rim e r if(a != 0).
Naredba if-else
N aredba if-else je najosnovniji nain na koji se k o ntrolie to k p ro g ram a. D eo else nije
obavezan, pa stoga if m oete da koristite u dva oblika:
i f (1ogi k i- i zraz)
naredba
i f (1ogi k i- i zraz)
naredba
el se
naredba
Logiki izraz m o ra da vraa rezultat tipa boolean. Naredba je jed n o stav n a nared b a
koja se zavrava z nakom taka i zarez, ili sloena n ared b a, o d n o sn o g ru p a naredaba u n u -
ta r vitiastih zagrada. Svaki p u t kada se koristi term in naredba, p o d razu m ev a se da ona
m oe biti jednostavna ili sloena.
100 Misliti na Javi
Kao p rim e r za if-else, sledi m eto d a test() koja saoptava da li je p retp o stav ljen a vred-
n ost vea, m an ja ili je d n ak a ciljnoj v red n o sti:
//: c o n tr o l/ If E ls e .ja v a
import s t a t ic n e t.m in d view .u ti1 .P r in t
p ub lic c lass If E ls e {
s t a t ic in t re z u lta t = 0;
s t a t ic void t e s t ( in t vrednost, in t c i l j ) {
if(v re d n o s t > c i l j )
re z u lta t = +1;
e lse if(v re d n o s t < c i l j )
re z u lta t = -1;
el se
re z u lta t = 0; // Po k lo p ile su se
}
p ublic s t a t ic void m a in (S trin g [] args) {
te s t(1 0 , 5 );
p ri n t ( r e z u l t a t ) ;
t e s t(5 , 10);
p rin t(re z u lta t);
t e s t(5 , 5 );
pri n t ( r e z u l t a t ) ;
}
} /* Is p is :
1
-1
0
* ///= -
Negde na sredini koda m eto d e test() v idite kom bin aciju else if, to nije nova rezervi-
sana re, nego jed an else iza kojega je nova n ared b a if.
Iako je Java jezik slo b o d n o g o blika, kao C i C + + , uvlaenje tela n ared b e za k o n tro lu
izvravanja je korisn o kako bi italac m ogao Iake da o dredi gde o n o poinje i gde se za-
vrava.
Petlje
Petlje se k o n tro liu rezervisanim reim a w h ile, d o -w h ile i for, koje se pon ek ad nazivaju i
iteracione narcdbe. Naredba se ponav lja sve d o k logiki-izraz za k o n tro lu ne dobije vred-
n o st false. O blik petlje w h ile je sledei:
Sledi je d n o stav an p rim e r koji generie sluajne brojeve sve d o k o d red en i uslov ne
b u d e ispunjen.
M eto da uslov() koristi sta tin u m eto d u random() iz b iblioteke Math, koja generie
v re d n o st tip a double izm e u 0 i 1 (u k lju u ju i 0, ali ne i 1). Prom enljivoj rezultat vred-
no st daje o p e ra to r p o re en ja <, iji je rezu ltat tip a boolean. U koliko o d ta m p ate vred-
n o st tip a boolean, au to m atsk i ete d o b iti odgo v araju i znakovni niz tru e ili false. Uslovni
izraz za while glasi: Ponavljaj n ared b e u telu petlje sve d o k m e to d a uslov() vraa true.
Petlja do-while
O blik petlje do-w hile je:
do
naredba
w h ile ( lo g i k i- iz r a z ) ;
ledina razlika izm eu while i do-while jeste ta da se n ared b a u petlji do-while uvek iz-
vri b arem je d n o m , ak i ako izraz im a v red n o st false i prvi p u t. Ako je uslovni izraz ne-
taan pre ulaska u petlju vvhile, n ared b a se nee izvriti n ijed n o m . U praksi, do-while se
rede javlja od vvhile.
Petlja for
Petlja for je verovatno najei oblik ponavljanja (ciklusa). O na vri inicijalizaciju pre pr-
vog izvravanja ciklusa. Z atim isp itu je uslov ( logiki-izraz) i ako je o n isp u n jen , izvrava
narcdbu, a p o to m na kraju svakog ciklusa izvrava korak i p o n o v o ispituje logiki-izraz.
O b lik petlje for je:
fo r ( i n i c i j a l iz a c ij a ; 1o g i k i- iz ra z ; korak)
naredba
102 Misliti na Javi
Bilo koji o d izraza inicijalizacija, logiki-izraz ili korak m oe b iti prazan . Logiki izraz
se prov erava p re svakog izvravanja n aredbe. im izraz d obije v red n o st false, petlja se
p rek ida i izvravanje se nastavlja p rv o m n a red b o m n ak o n petlje for. Na kraju svakog ci-
klusa (posle svakog izvravanja n a red b e), izvrava se korak.
Petlje for se o b in o k oriste za nabrajanje:
* '/ / / :-
Operator zarez
R anije u ovom poglavlju naveo sam da se operator zarez (n e razdelnik zarez koji slui d a
odvoji definicije, kao i arg u m e n te m eto d e) k oristi sam o u k o n tro ln im izrazim a petlje for.
Kako p rilik o m inicijalizacije, tako i p ri izvravanju koraka k o n tro ln o g izraza, m oete na-
vesti vie n a red ab a razdvojenih zarezim a i o n e e biti izvrene sekvencijalno. P o m o u
o p e ra to ra zarez m oete definisati vie prom enljiv ih u n u ta r n ared b e for, ali o n e m o ra ju
b iti istog tipa:
// : c o n tro l/ O peratorZarez.java
p u b lic c la s s OperatorZarez {
public s t a t ic void m a in (S trin g [] args) {
f o r ( i n t i = 1, j = i + 10; i < 5;
i++, j = i * 2 ) {
S y s te m .o u t.p rin tln ("i = " + i + " j = " + j ) ;
)
)
} /* Is p is :
i= 1 j= 11
i= 2 j= 4
i= 3 j= 6
i= 4 j= 8
* ///:-
Foreach sintaksa
Java SE5 uvodi novu i saetiju sintaksu naredbe for koja se u p o trebljava za nizove i kontej-
nere (o kojim a ete vie saznati u poglavljim a N izovi i Detaljno razm atranje kontejnera).
N ju esto nazivaju foreach sintaksa, jer u njoj ne m o rate sam i da pravite celobrojnu p ro-
m enljivu za bro jan je prolaza kroz sekvencu stavki - foreach au to m atsk i pravi sve stavke
u m esto vas.
104 Misliti na Javi
Na p rim er, p retp o stav im o da im ate n iz b ro jev a tip a float i d a ho ete da izaberete svaki
elem ent to g niza:
fo r (f lo a t x : f ) {
Kao to ete videti u poglavlju iivanje objekata, foreach sintaksa ra d i sa svakim ob-
je k to m za koji se zn a p o re d a k n jegovih lan o v a (koji p rip a d a klasi Iterable).
M noge for n ared b e o b u h v ataju p ro lazak k ro z sekvencu celo b ro jn ih v re d n o sti, recim o
ovako:
U ovo m sluaju foreach sintaksa n e b i rad ila, sem ukoliko u n a p re d n e n a p ra v ite n iz int
brojeva. D a bih to pojen o stav io , u b ib lio tek u net.mindview.util.Range stavio sam m e-
to d u range() koja au to m atsk i g enerie o d g o v araju i niz. N a m era m i je bila d a se range()
ko risti kao static uvoz:
Foreach sintaksa tedi neto v rem en a prilik o m pisan ja koda, ali je vanije to to je takav
k od m nogo itljiviji - kazuje ta hoete (d o b iti svaki elem en t n iza), a ne kako to postiete
(Pravim ovaj indeks d a b ih m ogao izabrati svaki elem en t niza )- U ovoj knjizi e se
foreach sintaksa upotrebljavati gde god je to m ogue.
Rezervisana re return
Za bezuslovno skakattje slui nekoliko rezervisanih rei: return, break i continue, a p o sto -
ji i nain skakanja n a n a re d b u sa o zn ak o m (engl. label), slino n ared b i goto u d ru g im je-
zicim a.
R ezervisana re return im a dve n am ene: o n a o d re u je v re d n o s t k o ju e m eto d a v ratiti
(ako uop te vraa v red n o st, tj. ako p o v ratn a v red n o st nije tip a void) i p ro u zro k u je tre n u -
tan izlazak iz m etode. P re th o d n u m e to d u test() m o em o p o n o v o n ap isati tako d a iskori-
stim o tu pogo d n o st:
Poslenji d eo prik azu je b e sk o n an u p etlju while, koja b i se, teorijski, izvravala n ep re-
kidno. M e u tim , u n u ta r p etlje se nalazi n are d b a break p o m o u koje se izlazi iz petlje. Po-
red toga, p rim etie te d a n a re d b a continue v raa izvravanje na v rh petlje i d a ne izvrava
o sta ta k tela petlje n a k o n sebe. (Stoga se ispisivanje u dru go j petlji javlja sam o k ad a je
v re d n o st i deljiva sa 10.) N a izlazu se ispisuje 0 je r je v red n o st izraza 0 % 9 jed n ak a 0.
D rugi oblik besk o n an e p etlje je for(;;). P revodilac tu m a i while(true) i for(;;) n a isti
nain, p a je izb o r iskljuivo p ita n je p ro g ram e rsk o g ukusa.
Veba 7; (1) P repravite vebu 1 tak o d a p ro g ra m zavrava ra d p o m o u rezervisane rei
break, k ad a v re d n o st d o e d o 99. Pokuajte d a u m esto toga k oristite return.
uveni goto
R ezervisana re goto p o sto ji u p ro g ram sk im jezicim a o d sam og poetka. Z aista, goto je
nastao kao posledica k o n tro le p ro g ra m a u m ain sk o m jeziku: ,A ko je isp u n jen uslov A,
skoi tam o , u su p ro tn o m , skoi o v am o . K ad p ro itate asem blerski ko d koji na k raju ge-
nerie p rak tin o bilo koji p revodilac, p rim etie te d a se k o n tro la p ro g ram a sastoji o d vie
skokova. (P revodilac Jave p rav i sop stveni asem blerski k o d , ali njega izvrava v irtueln a
m aina Jave (JV M ), a n e hard verski procesor.)
N aredba g o to je skok n a niv o u izvornog koda i to ju je iznelo na lo glas. Ako e p ro -
g ram stalno skakati s je d n e take n a d ru g u , zar ne po stoji nain da se ko d reorganizuje
tako da to k k o n tro le n e b u d e toliko p u n skokova? N aredba g o to je pala u p rav u nem ilost
n ako n objavljivanja uv en o g lanka E dsgera D ijkstre G oto se sm atra tetnim " i od tada
su n ap ad i na nju postali p o p u la ra n sp o rt.
Kao to je takvoj situaciji svojstveno, srednji p u t je najbolji. Problem nije u korienju
n ared b e g o to, ve u n jen o m preesto m ko rien ju - u retkim situ acijam a g o to je najbolji
nain za s tru k tu rira n je to k a izvravanja.
Iako je re g o to rezervisana u Javi, o n a se u jeziku ne koristi; Java nem a n ared b u goto.
Ipak, o na im a neto to lii na skok, pov ezan o sa rezervisanim reim a b re a k i c o n tin u e .
To nije skok, ve vie nain da se izae iz petlje. O n se esto povezuje s n a red b o m g o to
zato to koristi isti m eh an izam : o zn ak u (engl. label).
O znaka je id en tifik ato r iza koga sledi dvotaka, na p rim er:
oznakal:
oznakal:
sp o ljn a - p e tlja {
u n u tra n ja - p etlja {
/ /
Poglavlje 4: Kontrolisanje izvravanja 109
break; // (1)
/ /
continue; // (2)
/ /
continue oznakal; // (3)
/ /
break oznakal; // (4)
}
}
f o r ( i n t k = 0; k < 5; k++) {
i f ( k == 3) {
p r in t("n a s ta v i u n u tra n ju ");
continue u nutrasnja;
}
}
}
}
// Ovde ne moete da pozovete
// oznaene naredbe break i continue
}
}/ * Is p is :
i =0
n astavi unutranju
i = 1
nastavi unutranju
i =2
nastavi
i =3
preki ni
i =4
nastavi unutranju
i = 5
nastavi unutranju
i = 6
nastavi unutranju
i = 7
nastavi spoljanju
i =8
p rekini spoljanju
* ///:-
spoljasnja:
while(true) {
p r i n t ( " S p o lj a n j a p e t l j a w h ile " ) ;
w h ile (tr u e ) {
i++;
print("i = 11 + i);
if(i 1) {
printC'nastavi");
continue;
)
i f (1 == 3) {
print("nastavi spolja n ju ");
continue spoljasnja;
}
if(i == 5) {
pri nt("preki n i " ) ;
break;
}
if(i == 7) {
p rin t("p re k in i s p o lja n ju ");
break s p o lja s n ja ;
}
}
}
}
} / * I s p is :
Spoljanja p e t l j a while
i = 1
nastavi
i = 2
i = 3
nastavi spo lja nju
Spoljanja p e t l j a while
i = 4
i = 5
preki ni
Spoljanja p e t l j a while
i = 6
i = 7
p re k in i spoljanju
* ///:-
V ano je da zap am tite kako se o zn ak a u Javi jed in o k o risti kad im ate u g n e en e petlje
i elite da n ap rav ite break ili continue u vie nivoa u gneivanja.
U svom lan k u G o to se sm atra tetn im , D ijkstra je p o se b n o im ao zam e rk i na u p o tre -
b u oznaka, a ne sam e nared b e goto. P rim etio je da broj b u b ica raste s b ro jem oznaka u
p ro g ram u i da oznake i goto oteavaju analizu p ro g ram a. O b ra tite p an ju n a to d a oznake
u Javi ne pate o d to g p ro b lem a, p o to je m esto n a k o m e m o g u da stoje o g ran ien o i ne
m o g u da se koriste za o p ti p ren o s k ontrole. Treba p rim e titi i d a je ovo sluaj kada neka
osobin a jezikai postaje korisnija kada se ogranie njene m o g u n o sti.
Naredba switch
N ared ba sw itc h se n ek ad naziva i naredba izbora. N ared b a sw itc h b ira iz m e u nekoliko
delova koda u zavisnosti o d v re d n o sti d ato g izraza. N jen o p ti ob lik je:
switch (izraz) {
case vrednostl : naredba; break;
case vrednost2 : naredba; break;
case vrednost3 : naredba; break;
case vrednost4 : naredba; break;
case vrednost5 : naredba; break;
/ /
default: naredba;
}
Izraz m o ra im ati c elo b ro jn u ili logiku v red n o st. N ared b a switch p o red i rezultat izra-
za i svake vrednosti. Ako p ro n a e ekv ivalen tnu v red n o st, o d g o v araju a naredba (jed n a ili
vie njih, vitiaste zagrade nisu p o tre b n e) bie izvrena. A ko ne p ro n a e ekvivalentnu
v red n o st, bie izvrena naredba oznaena kao default.
P rim etiete u p reth o d n o j definiciji da se svaki blok case zavrava sa break, im e se to k
izvravanja p rem eta na kraj tela nared b e switch. O vo je uob iajen nain fo rm iran ja na-
redbe switch, ali je break o pcioni. Ako nedostaje, izvravae se sledee case n aredbe sve
d o k se ne naie na break. Iako o b in o ne elite da se to deava, isk u sn o m p ro g ram e ru ovaj
p ristu p m oe biti koristan . O b ratite panju na to da p o sled n ja nared b a, posle default,
nem a break jer se izvravanje nastavlja ba tam o gde bi se io n ak o odvijalo nakon break.
M oete, bez ikakvih posledica, da stavite break na kraj bloka default ako sm atra te da je to
vano zbog stila.
N aredba switch o m oguuje istu realizaciju izbora izm eu vie razliitih puteva izvra-
vanja, ali je za nju p o treb an izraz koji im a v rednost tipova kao to su int ili char. Sa n ared-
b o m switch ne m o etek ao izrazza izbor koristiti, na p rim er,z n ak o v n i niz ili broj u fo rm atu
po k retnog zareza. Za tipove koji nisu celobrojni ili logiki m o ra te da koristite niz naredaba
if. Na kraju sledeeg poglavlja, videete da to ogranienje olakava enum, nova rezervisana
re koja se u Javi koristi od verzije SE5, jer enum lepo radi sa n a re d b o m switch.
Poglavlje 4 : Kontrolisanje izvravanja 1 13
'/ / / = -
m eto d a Random.nextInt() daje sluajan ceo bro j izm e u 0 i 25, koji se d o d aje n u m e ri -
koj (ASCII) vred n o sti slova 'a'. To znai d a se 'a' a u to m atsk i p retv ara u tip int da b i se iz-
vrilo sabiranje.
D a bi se pro m en ljiv a c tip a int tam p ala k ao znak, m o ra b iti vraen a u tip char ekspli-
c itn o m konverzijom ; inae b i se ispisivali brojevi.
Veba 8: (2) N apiite n a red b u switch k oja ispisuje p o ru k u za svaki o d sluajeva (case), a
switch stavite u n u ta r petlje for koja isprobava svaki sluaj. Stavite n are d b u break n akon
svakog sluaja i testirajte p ro g ram , a zatim izbacite nared b e break i v idite ta se deava.
Veba9: (2) Fibonaijev n iz c ine b rojevi 1 , 1 ,2, 3, 5, 8 ,1 3 , 21, 34 itd., gde je svaki bro j (o d
treeg nadalje) je d n ak zb iru p re th o d n a dva. N apiite m eto d u koja p rim a ceo bro j k ao ar-
g u m e n t i prikazuje toliko F ibonaijevih brojeva poev o d prvog, n pr. ako p o k ren ete java
Fibonacci 5 (gde je Fibonacci im e klase) izlaz e biti: 1, 1, 2, 3, 5.
Veba 10: (5) Vampirski broj im a p a ran broj cifara i dobija se m n o e n je m p ara brojeva
koji im aju p o pola o rig in aln ih cifara proizvoda. Cifre se uzim aju iz p o lazn o g broja p ro i-
zvoljnim redosledom . N isu dozvoljeni parovi zavrnih nula. P rim eri:
1260 = 21 * 60
1827 = 21 * 87
2187 = 27 * 81
N apiite p ro g ra m koji pronalazi sve etvorocifrene v am pirske brojeve. (P redloio D an
F orhan.)
Saetak
O vim poglavljem se zavrava prouavanje osnovnih osobina koje se javljaju u veini pro-
gram skih jezika: raunanje, p rio ritet operatora, eksplicitna konverzija tipova, uslovi i petlje.
Sada ste sprem ni za korake koji e vas pribliiti svetu objektno orijentisanog pro g ram iran ja.
N aredno poglavlje e ob rad iti vane tem e: inicijalizaciju i ienje objekata te veom a b itn o
sakrivanje realizacije.
R eenja n ek ih vebi d ata su u e le k tro n sk o m d o k u m e n tu Thc Thinking in Java Annotalecl Solution
Guide, a m o g u se k u p iti na lo k a ji www.MindVicw.com.
Inicijalizacija i ienje
S napretkom raunarske revolucije, ,,nesigurno program iranje je postalo jeda n od glavnih
razloga za visoku cenu programiranja.
class Kamen {
Kamen() { / / Ovo j e konstruktor
System.out.print("Kamen");
}
} /* Ispis:
Kamen Kamen Kamen Kamen Kamen Kamen Kamen Kamen Kamen Kamen
* ///:-
new Kamen();
zauzim a se m em o rija i poziva k o n stru k to r. G ara n tu je se da e objek at b iti p rav iln o inici-
jalizovan p re nego to b u d e u p o treb ljen .
O b ra tite p an ju n a to d a se stil p isan ja p o k o m e se prv o slovo im en a svih m eto d a pie
m alim slovom ne o d n o si n a k o n stru k to re , je r im e k o n stru k to ra m o ra da se tano pok lapa
sa im en o m klase.
K o n stru k to r koji ne p rim a a rg u m e n te naziva se po d ra zu m eva n i konstruktor. U veem
d elu literature o Javi koju je izdao Sun, n jih nazivaju k o n stru k to ri bez arg u m en ata" (engl.
no-arg constructors). T erm in p o d razu m ev an i k o n stru k to r upotrebljava se dugi niz godi-
n a, p a u ga i ja koristiti. Ali kao i svaka m eto d a , k o n stru k to r m oe da im a arg u m e n te koji
om o g uav aju d a o d red ite kako e o b jek at biti naprav ljen . P reth o d n i p rim e r lako m oe da
se prep rav i tako da k o n stru k to r im a jed an arg u m en t:
class Kamen2 {
Kamen2(int i ) {
System.out.print(''Kamen " + i + " ) ;
}
}
Ako je Drvo(int) jed in i k o n stru k to r, prevodilac nee dozvoliti da n ap rav ite objekat
Drvo ni na koji d ru g i nain.
Poglavlje 5: Inicijalizacija i ienje 117
K on struk tori elim iniu veliku g ru p u p ro b lem a i ine p ro g ram e razum ljivijim . U pret-
h o d n o m p rim e ru ne postoji eksplicitan poziv nekoj m eto d i inicijalizacija() koja je k o n -
ceptu alno odvojena o d pravljenja objekta. U Javi, pravljenje objekta i njegova inicijalizacija
objed injen i su kon cepti - je d n o bez d ru g o g ne ide.
K o n stru k to r je n eo b i n a vrsta m eto d e je r n e m a p o v ra tn u v red n o st. O vo je p o tp u n o
razliito o d p o v ra tn e v re d n o sti tip a void, kad a m eto d a ne vraa n ita, ali i dalje im ate m o -
g u n o st d a je n ap ra v ite tako da v raa neto. K o n stru k to ri n em aju p o v ra tn u v re d n o st i
d ru g a m o g u n o st ne p o sto ji (izraz n e w v raa referencu n o v onapravljenog objekta, ali
sam k o n stru k to r ne vraa n ita). Ako bi p o sto jala p o v ra tn a v red n o st i ako b iste m o g li da
je b irate , prevo d ilac bi nekako m o ra o da zna ta d a rad i s to m p o v ra tn o m v red n o u .
Veba 1: (1) N apravite klasu koja sadri n e in i ja liz o v a n u String referencu. Pokaite da
Java tu referencu inicijalizuje v red n o u null.
Veba 2: (2) N aprav ite klasu s je d n im String p o ljem koje se inicijalizuje n a m estu defi-
nisanja i d ru g im koje inicijalizuje k o n stru k to r. Po em u se razlik u ju ta dva pristu p a?
Preklapanje metoda
Jedno od vanih p itan ja u svakom p ro g ram sk o m jeziku jeste u p o tre b a im ena. Pravei
objekat, vi zaajete im e oblasti u m em o riji. M etoda je im e neke akcije. Svim o b jek tim a i
m eto d am a obraate se prek o im ena. D o b ro o d a b ra n a im en a ine sistem koji je lake razu -
m eti i m enjati. To veo m a lii na p isanje p ro ze - cilj je da b u d e te u vezi sa itaocim a.
P rob lem nastaje kada nijanse ljudskog jezika p rim en ju jete n a p ro g ram sk i jezik. esto
ista re im a vie razliitih znaenja - o n a je preklopljena (engl. overloaded). To je korisno,
naro ito ako se radi o je d n o stav n im razlikam a. Vi ete rei operi koulju, operi kola i
operi psa. Bilo bi b u d alasto ako biste m o rali da g ovorite operiV eM ainom k oulju,
operiC rev o m kola i operiK upanjem psa sam o da bi slualac m ogao da n ap rav i razliku
izm eu tih akcija. Veina Ijudskih jezika je re d u n d a n tn a , pa i dalje m oete da od red ite
znaenje ak i ako ispu stite nekoliko rei. Jedinstveni id en titik a to ri n am n isu p o tre b n i
- znaenje m o e m o shvatiti iz konteksta.
U veini p ro g ram sk ih jezika (p o seb n o C -u ) svaka m eto d a (koje se u tim jezicim a obi-
no nazivaju funkcije) m o ra im ati jed in stv en identifikator. Tako ne m oete da im ate jed n u
funkciju p o d im en o m p rin t() koja bi ispisivala cele brojeve i d ru g u istog im en a za ispisi-
vanje brojeva u fo rm a tu p o k retn o g zareza - svaka funkcija m o ra da im a jed in stv en o im e.
U Javi (i C + + -u ) p o sto ji jo je d a n inilac koji n am ee prek lap an je im ena m etoda: kon-
struk to r. Poto je im e k o n stru k to ra u n a p re d o d re e n o im e n o m klase, k o n stru k to r m oe
im ati sa m o to je d n o im e. Ali ta ako elite da objek at p rav ite na vie naina? N a p rim er,
p re tp o sta v im o da p rav ite klasu koja m oe da se inicijalizuje na sta n d a rd a n nain ili ita-
njem info rm ac ija iz dato tek e. P otreb n a su vam dva k o n stru k to ra , jed an bez arg u m en ata
(p o ra zu m ev a n i k o n stru k to r) i d ru g i, iji je arg u m e n t tipa String u kom e je im e datoteke
iz koje treb a inicijalizovati objekat. O b a su k o n stru k to ri, pa m o raju im ati isto im e - im e
te klase. Stoga je prcklapanje m etoda sutinski zn aajn o u Javi, je r o m o g u uje da se isto
im e m eto d e koristi s dru g aijim tip o v im a arg u m e n ata . Iako je prek lap an je m eto d a neop-
h o d n o za k o n stru k to re , to je opta p o g o d n o st d o stu p n a za bilo koju m etodu.
118 Misliti na Javi
class Drvo {
i n t v is in a ;
Drvo() {
print("S a en je m la dic e ");
v is in a = 0;
}
Drvo je visoko 3 m
preklopljena metoda: Drvo je visoko 3 m
Pravimo novo Drvo koje je visoko 4 m
Drvo je visoko 4 m
preklopljena metoda: Drvo je visoko 4 m
Saenje mladice
* ///:-
O bjekat klase Drvo m o e d a b u d e nap rav ljen ili kao m laica, b ez arg um enata, ili kao
biljka odgajena u rasad n ik u s d a to m visin om . D a bi se to o m oguilo, postoje dva k o n -
stru k to ra ; je d an bez arg u m e n a ta i d ru g i, iji je a rg u m e n t postojea visina.
M oe vam zatreb ati d a pozovete m e to d u info() n a vie naina. N a p rim er, ako elite da
ispiete jo n e k u d o d a tn u p o ru k u , o n d a n a re d ite a rg u m e n t tip a String, a ako ne elite ni-
ta vie d a kaete, o n d a v am n e tre b a a rg u m e n a t. Bilo bi n eo b i n o da date dva razliita
im ena neem u to oigled n o im a isti kon cep t. N a sreu, p rek lap an je m eto d a om oguava
da isto im e koristite za obe stvari.
//: inicijalizacija/PreklapanjeProstihTipova.java
// Proirivanje prostih tipova i preklapanje.
import static net.mind vi ew .u ti l.Print.*;
void f 6 ( f l o a t x) { p r i n t n b ( " f 6 ( f l o a t ) ) ; }
void f6(double x) { p r i n t n b ( " f 6 ( d o u b le ) " ) ; }
void f 7 (double x) { p r i n t n b ( " f 7 ( d o u b le ) " ) ; }
void testKonstantom() {
printnb ("5: " ) ;
f 1 ( 5 ) ; f 2 ( 5 ) ; f 3 ( 5 ) ; f 4 ( 5 ) ; f 5 ( 5 ) ; f 6 ( 5 ) ; f 7 (5 ); p r i n t ( ) ;
}
void testChar() {
char x = ' x ' ;
Poglavlje 5: Inicijalizacija i ienje 121
printnb("char: ");
fl(x);f2(x);f3 (x);f4(x);f5 (x);f6(x);f7 (x); p r i n t ( ) ;
}
void testByte() {
byte x = 0;
printnb("byte: ");
f l ( x ) ;f2 (x);f3(x);f4(x);f5(x);f6(x);f7 (x); p r i n t ( ) ;
}
void testShort() {
short x = 0;
printnb("short: ");
fl (x);f2(x);f3 (x);f4(x);f5 (x);f6(x);f7 (x); pri n t ();
}
void t e s t l n t O {
int x = 0;
printnbC'int: ");
f l ( x ) ; f 2 ( x ) ; f 3 ( x ) ; f 4 ( x ) ; f 5 ( x ) ; f 6( x ) ; f 7( x ) ; p r i n t ( ) ;
}
void testLong() {
long x = 0;
p r in t n b ( " io n g : " ) ;
fl(x);f2 (x);f3(x);f4(x);f5 (x);f6(x);f7 (x); p r i n t ( ) ;
}
void t e s t F l o a t( ) {
f l o a t x = 0;
p rin tn b ("flo a t: ");
f l ( x ) ; f 2 ( x ) ; f 3 ( x ) ; f 4 ( x ) ; f 5 ( x ) ; f 6 ( x ) ; f 7( x ) ; p r i n t ( ) ;
}
void testDouble() {
double x = 0;
printn b ("d o u b le : " ) ;
f l ( x ) ; f 2 ( x ) ; f 3 ( x ) ; f 4 ( x ) ; f 5( x ) ; f 6 ( x ) ; f 7( x ) ; p r i n t ( ) ;
}
pu blic s t a t i c void m a in(S trin g [] args) {
PreklapanjeProstihTipova p =
new PreklapanjeProstihTip ova();
p.testKonstantom ();
p .te s t C h a r O ;
p.te stB yte ();
p.te s tS h o rtO ;
p .te s tln t();
p .t e s t L o n g ( ) ;
p .te s tF lo a tO ;
p.testDoubleO ;
}
} / * Is p is :
5: f l ( i n t ) f 2( i n t ) f 3( i nt ) f 4 ( i n t ) f5(lo ng ) f 6 ( f 1oat) f7(double)
char: f l ( c h a r ) f 2 ( i nt ) f 3 ( i n t ) f 4 ( i n t ) f5(lo n g ) f 6 ( f l o a t ) f 7 (double)
byte: f 1(byte) f2(byte ) f 3( s h o r t ) f 4 ( i n t ) f 5 ( 1ong) f 6 ( f l o a t ) f7(double)
sho rt: f l ( s h o r t ) f2 (s h o rt) f 3 ( s h o r t ) f 4 ( i n t ) f 5 (lo n g ) f 6 ( f l o a t ) f7(double)
122 Misliti na Javi
P rim etiete d a se k o n sta n ta 5 tre tira kao v red n o st tip a int, pa se, ako postoji, poziva
prek lopljen a m eto d a iji je a rg u m e n t tip a int. U svim d ru g im sluajevim a tip p o d a tk a se
p ro iru je ako je m an ji o d tip a a rg u m en ta u m eto d i. K od tip a char javlja se neto drugaiji
efekat - ako se n e n a e ta n o odgo v araju i p a rn ja k tip a char, o n se p ro iru je n a int.
ta se deava ako je a rg u m e n t vei o d a rg u m e n ta koji se oekuje u p reklopljenoj m e-
todi? O dgo v o r daje izm en jen i p re th o d n i p rim er:
void testDouble() {
double x = 0;
print("argum ent t ip a d o u b le ;");
fl(x );f2 ((flo a t)x );f3 ((lo n g )x );f4 ((in t)x );
f5 ((s h o rt)x );f6 ((b y te )x );f7 ((c h a r)x );
}
pu b lic s t a t i c void m a in (S trin g [] args) {
Degradacija p = new Degradacija ( ) ;
p.tes tD o ubleO ;
}
} / * I s p is :
argument t ip a double:
fl( d o u b le )
f2 (flo a t)
f 3(1ong)
f4 (in t)
f5 ( s h o r t )
f 6 ( byte)
f7(c ha r)
* ///:-
U o vom sluaju m etode u zim aju suene v red n o sti p ro sto g tipa. A ko je va a rg u m e n t
iri, m o ra te ga eksplicitno k o nv erto vati u p o treb an tip. U koliko to ne u rad ite, prevodilac
e prijaviti greku.
void f () { }
i n t f ( ) { return 1; }
f0;
kako izvrno o k ru en je m oe da o d red i koju m eto d u f() treb a da pozove? I kako bi neko
ko ita p ro g ram to m ogao da zna? Z bog ove vrste p ro b lem a, tip p o v ra tn e v red n o sti ne
m oe da se koristi za razlikovanje m etoda.
124 Misliti na Javi
Podrazumevani konstruktori
Kao to je ranije p o m e n u to , p o d ra z u m e v a n i k o n stru k to r (tj. n o -a rg k o n stru k to r) n em a
arg u m en te i k oristi se za p rav ljen je p o d ra z u m e v a n ih o b jekata. A ko n ap rav ite klasu koja
nem a k o n stru k to re, p rev o d ilac e u m esto vas a u to m a tsk i n a p ra v iti p o d ra z u m ev a n i k o n -
struk to r. Na p rim er:
class Ptica {}
Izraz
pravi nov objekat i poziva p o d raz u m ev an i k o n stru k to r, iako o n ranije nije izriito nave-
den. Bez njega ne bi p ostojala n ijed n a m eto d a koju b ism o m ogli da p o zovem o kako bism o
napravili objekat. M e u tim , ako definiete m ak ar jed a n k o n stru k to r te klase (sa arg u m en -
tim a ili bez n jih), prevodilac nee um esto vas n ap rav iti p o d razu m ev an i k o n stru k to r:
class Ptica2 {
Ptica2 ( i n t i ) { }
Ptica2 (double d) { }
}
p u blic class NemaSinteze {
pu blic s t a t i c void m a in (S tr in g [] args) {
/ / ! Ptica2 p = new P t ic a 2 ( ) ; / / Nema podrazumevanog konstruktora
Ptica2 p2 = new P t i c a 2 ( l ) ;
Ptica2 p3 = new P tic a 2 ( 1 . 0 );
}
1 III--
Ako sada napiete:
new P t ic a 2 ( ) ;
Rezervisana re this
A ko im ate dva objekta istog tipa, koji se zovu a i b, m o d a se p itate kako m oete da p o-
zovete m e to d u oljusti() za o b a objekta:
B a n a n a . o lju s t i( a , l ) ;
B a n a n a . o lju s t i( b , 2 ) ;
O vo su saino in tern i oblici i ako ih napiete, p revodilac ih ne prih v ata, ali vam daje ide-
ju o to m e ta se deava.
P retp ostavim o da se nalazite u n u ta r m eto d e i da elite da koristite referencu na tekui
objekat. Poto je tu referencu prevodilac skriveno prosledio, za nju ne postoji identifikator.
Za tu n a m en u , m e u tim , postoji rezervisana re: this. R ezervisana re this - koja m oe da
se koristi sam o u n u ta r ne-static m eto d e - vraa referencu na objekat za koji je m etoda po-
zvana. Tu referencu m oete da koristite kao i svaku d ru g u referencu na objekat. Vodite
126 Misliti na Javi
//: i n i c i j a l i z a c i j a / K a j s i ja . j a v a
pu blic class K a js ija {
void o t r e b i ( ) { / * . . . * / }
void k o s tic a () { o t r e b i ( ) ; / * . . . * / }
} ///:-
U n u tar m eto d e kostica() tnogli biste d a n ap iete this.otrebi(), ali to nije p o tre b n o .1
Prevodilac to au to m atsk i radi u m e sto vas. R ezervisana re this k o risti se sam o kada treb a
da izriito k o ristite referencu n a tek u i objekat. Na p rim e r, o n a se esto k o risti uz n a red b e
return kada treba da v ratite referencu n a tekui objekat:
public class L is ta {
i n t i = 0;
Lista p r e l i s t a j O {
i++;
return t h i s ;
}
void i s p i s ( ) {
S y s te m . o u t. p r in t ln (" i = " + i ) ;
}
pu blic s t a t i c void m a in (S trin g [] args) {
L ista x = new L i s t a ( ) ;
x . p r e l i s t a j ( ) . p r e l i s t a j ( ) . p r e l i s t a j ( ) . i spi s ( ) ;
}
} / * Is p is :
i = 3
* ///:-
Poto m etoda p re lista j() vraa referencu n a tekui o b jek at preko rezervisane rei th is,
lako se m oe izvriti vie o p eracija n ad istim o b jek to m .
th is se koristi i za prosleivanje tekueg objekta d ru g o j m etodi:
class Osoba {
pu blic void pojedi(Jabuka jabuka) {
Ima Ijudi koji kao opsednuti piu this ispred svakog poziva m eto d e i svake reference polja, obra-
zlaui da je takav ko d jasniji i eksplicitniji. Ne inite to. Z na se zbog ega koristim o jezike visokog
nivoa: oni m nogo toga rade um esto nas. Ako budete pisali this kada nije n eo p b o d n o , zbuniete i
naljutiti sve koji e itati va program , poto u svem ostalom kodu koji su proitali this nije bio po-
sejan posvuda. Ljudi oekuju da se this upotrebljava sam o o n d a kada je n eo p h o d an . Pridravajui se
doslednog i jednostavnog stila program iranje tedite vrem e i novac.
Poglavlje 5: Inicijalizacija i ienje 127
Jabuka o lju s te na = j a b u k a . o l j u s t i S e ( ) ;
S y s t e m . o u t . p r i n t ln ( " M lja c " ) ;
}
}
class lj u s t a c {
s t a t i c Jabuka 1ju s ti(J a b u k a jabuka) {
/ / . . . ukloni Ijusku
re tu rn jabuka; / / Oljustena
}
}
class Jabuka {
Jabuka o l j u s t i S e ( ) { return 1j u s t a c . l j u s t i ( t h i s ) ; }
}
Jabuka zove Ijustac.ljusti(), sp o ljn u m e to d u koja obavlja o p eraciju koja, iz nekog raz-
loga, m o ra biti spo ljna za objekat Jabuka (m o d a se sp o ljn a m eto d a m oe p rim e n iti na
vie razliitih klasa, a vi ne elite da p o navljate n jen ko d ). D a bi se p rosledila spoljnoj m e-
todi, o n a m o ra da u p o treb i this.
Veba 8: (1) N apravite Idasu s dve m eto d e. U n u ta r prve m eto d e, d v ap u t pozovite d ru g u :
prvi p u t bez this, a d ru g i p u t p o m o u this - tek da biste videli kako radi; tc ne bi treb alo
da rad ite u praksi.
To je m ogue sam o kada toj statinoj m etodi prosledite referencu na objekat (i statina m etoda m oe
praviti sopstvene objekte). Tada preko te reference (koja je u to m sluaju igra ulogu refe ren ce th is)
m oete da pozivate nestatine m etode i da pristupate nestatinim poljim a. Ipak, kada elite neto
tako da radite, napravite sam o obinu nestatinn m etodu.
130 Misliti na Javi
p rim er, p retp o stav im o da se to k o m stv aran ja va objekat iscrta n a ekranu. Ako eksplicit-
n o ne ob riete njegovu sliku sa ek ran a, m o d a o n a n ikad nee biti u klonjena. U koliko
m e to d u fin alize() p ro g ra m ira te za n ek u v rs tu b risan ja, a o b jek at do sp e p o d dejstvo saku-
pljaa sm ea i fin alize() b u d e p o zv an a (a niko ne ja m i d a e se to desiti), u prvoj fazi i-
enja slika e b iti u k lo n jen a sa ek ran a. U s u p ro tn o m , ako sakuplja sm ea ne rei da
poisti va objekat, slika o staje na ekranu.
M oe se d o g o d iti d a p ro s to r koji zau zim a va objekat n ik ad ne b u d e o slo b o en , jer
vaem p ro g ra m u n ik a d a nee p o n e stati m em o rije. A ko se p ro g ra m zavri, a sakuplja
sm ea nije im ao p rilik u d a o slo b o d i p ro s to r koji je bilo koji va objekat zauzim ao, celo-
k u p an p ro sto r e b iti odjednom v raen o p e ra tiv n o m sistem u na izlasku iz p ro g ram a. Tako
se izbegava d o d a tn a u p o tre b a rau n a rsk ih resursa - ako ienje nije p o tre b n o p a se p o -
boljavaju p erfo rm an se p ro g ram a.
Jo sh u a B loch ide jo dalje u odeljku pod naslovom Izbegavajte korienje zavrnih m etoda": Fina-
lizatori su nepredvidljivi, esto o p a s n i, i po pravilu nepotrebni." Efiknsno programiranje na lavi, s. 18
(M ikro knjiga, 2004).
Poglavlje 5: Inicijalizacija i ienje 131
Stanje okonanja
U glavnom ne m oete da se oslonite na to da e finalize() biti pozvana, ve m o ra te da na-
p rav ite zasebne funkcije za ienje i da ih eksplicitno pozovete. Z ato se ini da je finali-
ze() je d in o korisna za o slo b a an je m em o rije rezervisane n a neu ob iajen nain, koju
veina p ro g ra m e ra nikada nee koristiti. Postoji, m e u tim , je d n a vrlo k o risna p rim e n a
m eto d e finalizef) koja se ne oslanja na to da e ona biti svaki p u t pozvana. To je provera
p o sto jan ja stanja okonanja' (engl. ten n in a tio n condition) nekog objekta.
O d tre n u tk a kada vas objekat vie ne zan im a - kada je sp rem an da b u d e poien - taj
o bjekat treba da b u d e u stan ju u kom e njegova m em o rija m oe b ezb ed no da b u de oslo-
b o en a. Na p rim er, ako objekat predstavlja o tv o ren u d a to tek u , pro g ra m e r treb a da zatvo-
ri tu d a to tek u pre nego to sakuplja sm ea poisti taj objekat. A ko bilo koji deo objekta
nije p ra v iln o poien, im aete greku u p ro g ram u koju je vrlo teko o tk riti. M etoda fi-
n a lize() je znaajna zato to m oe da se iskoristi za otk riv an je tak vih sluajeva i ako se ne
poziva uvek. Ako neka finalizacija o tk rije greku, otkrili ste p ro b lem , to vas, uostalom ,
jedino i brin e.
' Izraz koji je skovao Bill V enners (w w w.artima.com) tokom naeg sem inara.
132 Misliti na Javi
/ / : in ic ij a li z a c ija / S t a n je O k o n c a n ja . ja v a
/ / O tkrivanje objekta k o ji n i j e ispravno poien
/ / pomou metode f i n a l i z e ( ) .
class Knjiga {
boolean pozajmljena = f a ls e ;
Knjiga(boolean p2) {
pozajmljena = p2;
}
void v r a t i ( ) {
pozajmljena = f a ls e ;
}
protected void f i n a l i z e ( ) {
i f (pozajml jena)
System .out.println (''Greka: k njig a n i j e vraena");
/ / Normalno b is te u r a d i l i i sledee:
/ / s u p e r . f i n a l i z e O ; / / Poziv v e r z i j e osnovne klase
}
}
Sve pozajm ljene knjige u stan ju o k o n an ja treb alo bi da b u d u v raen e pre nego to ili
pok u pi sakuplja sm ea, ali se do g o d i da su m eto d i m a in () p ro g ra m e r grekom ne vrati
jednu o d knjiga. Bez m eto d e fin alize() koja proverava stanje o k o n an ja, to bi predstavlja-
lo greku koju je p o ten cijaln o teko o tkriti.
O b ra tite p an ju na to da je za zahtevanje ienja korien p oziv S ystem .gc(). ak i da
nije, vrlo je verovatno da bi zalutala K n jiga je d n o m bila o tk riv en a u p o n o v ljen im izvra-
v an jim a p ro g ram a (p o d p retp o stav k o m da p ro g ra m zau zim a d o v o ljn o m em o rije kako bi
bio p o k re n u t sakuplja sm ea).
Po prav ilu , treb alo bi da p retp o stav ite kako i verzija fin alize() u osnovnoj klasi irna
vanog posla i da je pozovete p o m o u rezervisane rei su p e r, kao to vidite u K njiga.fi-
nalize(). U ovom sluaju, taj red je pretvoren u k o m e n ta r zato to zahteva o b ra d u izuze-
taka, a m i ih jo n ism o razm o trili.
Poglavlje 5: Inicijalizacija i ienje 1 33
Veba 10: (2) N apravite klasu s m e to d o m finalize() koja ispisuje n eku p o ru k u . U m etod i
main() n apravite objekat te klase. O b jasn ite p o n aa n je svog p ro g ra m a.
Veba 11: (4) Prepravite p re th o d n u vebu tak o d a se vaa m e to d a finalize() uvek poziva.
Veba 12: (4) N aprav ite klasu Rezervoar koja se m o e p u n iti i p raz n iti, i koja im a takvo
stanje okonanja da m o ra b iti p ra z n a p rilik o m ienja objekta. N apiite m e to d u finali-
ze() koja proverava ispun jen je tog uslova o k o n an ja . U m eto d i main() ispitajte scenarije
koji se m o g u o d ig rati p rilik o m u p o tre b e klase Rezervoar.
kada se zavri p o stu p ak oznaavanja. T okom ienja o slo b aa se m em o rija koju su zau-
zim ali m rtv i objekti. M e u tim , n ita se ne k o p ira, p a ako sakuplja odlui d a sabije frag-
m e n tira n i d in am iki m em orijski prostor, o n to rad i tako to p o m e ra objekte.
Tehnika stani-i-kop iraj poiva na ideji da ovaj tip saku pljan ja sm ea ne rad i u p o zad i-
ni, ve se p ro g ram zaustavlja d o k se obavlja sak u p ljan je sm ea. U literatu ri koj u je objavio
Sun p ro n ai ete vie referenci na sakuplja sm ea kao p o zad in sk i proces niskog p rio ri-
teta, ali se ispostavilo da u ran ijim verzijam a S unove JVM saku pljanje sm ea nije realizo-
vano n a taj nain. U m esto toga, S unov sakuplja sm ea je zaustavljao p ro g ra m k ad a
p o n estan e m em o rije. I teh n ik a o zn ai-ip o isti zahteva zaustavljanje p ro g ram a.
Kao to je ranije p o m e n u to , o p isan a v irtu eln a m ain a zau zim a m e m o riju u velikim
b lokovim a. A ko napravite veliki objekat, o n d o b ija so pstveni blok. S trik tn a teh n ik a stani-
i-kopiraj zahteva kop iran je svih ivih objek ata sa izvorinog d in am ik o g m em orijsk og
p ro sto ra u novi p re nego to se stari oslobodi, za ta je n e o p h o d n o p u n o m em orije. Sa-
kuplja sm ea to k o m sakupljanja o bino m oe d a k o p ira objekte u m rtve blokove. Svaki
blo k im a brojaproizvodnje koji vodi evidenciju d a li je b lo k iv. O b i n o se sabijanje vri
sam o n ad b lokovim a koji su n apravljeni posle posled n jeg sak up ljan ja sm ea; svim osta-
lim blok ov im a b roja p roizvodnje se uveava ako su o d n e k u d referencirani. N a ovaj n a-
in se b rin e o uobiajenim sluajevim a p riv re m e n ih o b jekata k ratk o g ivotnog veka.
P erio din o se radi p o tp u n o ienje - veliki o bjekti se i dalje ne k o p iraju (ve im se sam o
uvea broja proizvodnje), a blokovi koji sadre m ale o b jek te k o p iraju se i slau. JVM
p rati efikasnost sakupljaa sm ea i ako se za njegovo korienje n e o p h o d n o troi vrem e
jer su svi objekti dugog ivotnog veka, preb acuje ga u reim o zn ai-i-p oisti. Slino tom e,
JVM vodi rau n a o u spenosti tehnike o zn ai-i-po isti, i ako d in am i k i m em o rijsk i p ro -
sto r p o stan e fragm en tiran , prebacuje se nazad u reim stan i-i-k o p iraj. P reth o d n a m eto d a
prebacivanja predstavlja p o m e n u ti prilagodljivi deo, tj. p o sto ji teh n ik a prilagodljiva sta-
ni-i-k o p iraj oznai-i-poisti.
Postoji vie d o d atn ih m o g u n o sti za ub rzav an je v irtu e ln e m aine. Posebno vana m o -
gunost o n o si se na rad p ro g ram a za uitavanje (engl. loader) i o n og a to se naziva p re-
vodilac b a-k ad a-treb a (engl. Just-In-Time, JIT). JIT p revodilac delim in o ili p o tp u n o
pretvara p ro g ram u lokalni m ainski kod, tako da JVM ne m o ra da ga in terp re tira, pa je
izvravanje m n o g o bre. Kada klasa m o ra da se u ita (o b ino , prvi p u t kada elite da na-
pravite objekat te klase), pronalazi se d atoteka .class i b ajtk od te klase se uitava u m em o -
riju. U to m tre n u tk u jedan p ristu p m oe biti da p rim e n im o JIT p rev o enje na sav k od , ali
to im a dve m ane. Prvo, neto vie traje (to, kada se n ak u p i kroz ivotni vek p ro g ram a , ne
m oe da b u d e zanem arljivo). D rugo, poveava se izvrni p ro g ram (bajtk od je z n a tn o
k o m p ak tniji od raspakovanog JIT koda), pa m o g u d a se izm en e m em o rijsk e stranice, to
defin itiv n o u sporava program . A lternativni p ristu p je lenja p ro cen a (engl. lazyevaluation),
to znai da se II I prevoenje ne radi sve d o k nije n e o p h o d n o . T im e se postie da kod koji
se nikad a ne izvri, m oda nikada ne b ud e JIT p reveden. T ehnologije Java H o tS p o t u n o-
vijim razvojnim o k ru en jim a (JDK) p o stu p aju slino, jer o p tim iz u ju svaki deo koda sva-
ki p u t kada se on izvrava - to se kod vie izvrava, p o staje sve bri.
136 Misliti na Javi
Inicijalizacija lanica
fava se ba tru d i d a g a ra n tu je k ako e sve p ro m en ljiv e biti p ra v iln o in i jalizo v an e p re ko-
rienja. Kad su p ro m en ljiv e definisane lo kaln o u m eto d i, ovo g a ra n tu je prevodilac (jer
inae prijavljuje grek u ). Z nai, ako napiete:
void f() {
int i ;
i++; // Greka -- i nije inicijalizovana
/ / : i n i c i j a l i z a c i j a / I n i c i j a l n e V r e d n o s t i . java
/ / Prikazuje podrazumevane i n i c i j a l n e vred no sti.
import s t a t i c n e t . m in d v i e w . u t il. P r i n t . * ;
p u b lic class I n ic ija ln e V r e d n o s t i {
boolean t ;
char c;
byte b;
short s ;
i nt i ;
1ong 1;
flo a t f ;
double d;
I n i cija ln e V re d n o sti reference ;
void i s p i s l n i c i j a l n e V r e d n o s t i () {
p r i n t ( " T i p podatka I n i c i j a l n a vrednost");
p r i n t ( boolean " + t);
print("char [" + c + "] " ) ;
prin t("b y te " + b);
print("short " + s)
print("int " + i)
pri nt("1ong " + 1)
p rin t("flo a t + f)
print("double " + d);
printC'reference " + reference);
iv.ispislnicijalneVrednosti();
/* U ovom sluaju takoe moete napisati:
new InicijalneVrednosti().ispislnicijalneVrednosti();
*/
}
} / * I s p is :
Tip podatka I n i c i j a l n a vrednost
boolean fa ls e
char [ 1
byte 0
short 0
in t 0
long 0
flo a t 0.0
double 0.0
reference null
* I I I,-
Zadavanje inicijalizacije
ta se deava ako elite da p rom enljivoj d odelite p o e tn u vrednost? D irek tan n ain d a to
urad ite jeste da joj d o d elite v red n o st na m estu gde tu p rom enljivu definiete u klasi. (To
nije m o gue u C + + -u , iako poetn ici u jeziku C + + to uvek pokuavaju.) U sledeem p ri-
m eru definicije polja u klasi In ic ija ln e V r e d n o s t i p ro m en jen e su da bi obezbedile p o et-
ne v red n osti:
/ / : i n i c i j a l i z a c i j a / I n ic ija ln e V r e d n o s t i 2 . ja v a
/ / E k s p lic itn o zadavanje i n i c i j a l n i h v r e d n o s ti.
pu b lic c la s s Mera {
Dubina d = new Dubina ( ) ;
/ /
1 ///:-
Ako prom enljivoj d n iste dali p o e tn u v red n o st, a ipak p ok u ate da je koristite. d o-
biete greku p ri izvravanju koja se u Javi naziva izuzetak (engl. exception), to je o b ra-
eno u poglavlju O brada greaka potnou izuzetaka.
M oete ak d a pozovete m e to d u d a b iste obezb edili v re d n o st za inicijalizaciju:
/ / : i n i c i j a l iz a c ij a / I n i c i j a l iz a c ijaMetodom2.java
p u blic c la s s In icijalizacijaM eto d o m 2 {
in t i = f ();
in t j = g ( i ) ;
in t f ( ) { re tu rn 11; }
irit g (in t n) { re tu rn n * 10; }
} III--
Ali ovo ne m oete d a urad ite:
Inic/jalizacija konstruktorima
K o n stru k to r m oe d a se k oristi za inicijalizaciju. To daje veu fleksibilnost u p ro g ra m ira -
n ju , je r m o ete da pozivate m e to d e i izvravate akcije to k o m rad a p ro g ra m a kako biste
od red ili p o etn e v red n o sti. Jenu stvar treb a im ati na u m u : tim e ne spreavate a u to m a t-
sku inicijalizaciju koja se odigrava p re nego to se u e u k o n stru k to r. Stoga, ako biste, na
p rim er, napisali:
Redosled inicijalizacije
Redosled inicijalizacije u n u ta r klase o d re en je red o sled o m kojim su p rom enljive defini-
sane. D efinicije pro m en ljiv ih m ogu biti razbacane u n u ta r i izm e u definicija m eto d a, ali
se p rom enljive inicijalizuju pre poziva bilo koje m eto d e - ak i k o n stru k to ra . Na p rim er:
class Kuca {
Prozor pl = new P r o z o r ( l) ; / / Pre konstruktora
Kuca() {
/ / Ukazuje da smo unutar konstruktora
p r i n t ( 'KucaO" ) ;
p3 = new Prozor(33); / / Ponovo i n i c i j a l i z u j e p3
}
Prozor p2 = new Prozor(2); / / Nakon konstruktora
void f () { p r i n t ( " f ( ) " ) ; }
Prozor p3 = new Prozor(3); / / Na kraju
140 Misliti na Javi
class C in ija {
C i n i j a ( i n t marker) {
p r i n t ( " C i n i j a ( " + marker + " ) " ) ;
}
void f l ( i n t marker) {
p r i n t ( " f l ( " + marker + " ) " ) ;
}
}
Poglavlje 5: Inicijalizacija i ienje 141
class Sto {
s t a t i c C i n ij a c i n i j a l = new C i n i j a ( l ) ;
S to() {
p rin t("S to () ) ;
c in ija 2 .f(l);
}
void f 2 ( i n t marker) {
p r i n t ( " f 2 ( " + marker + " ) " ) ;
}
s t a t i c C i n ij a c in i j a 2 = new C i n i j a (2 );
class Kredenac {
C i n ij a c in i j a 3 = new C i n i j a ( 3 ) ;
s t a t i c C i n ij a c i n i j a 4 = new C i n i j a ( 4 ) ;
Kredenac() {
p r i n t (" K r e d e n a c ( )" );
c in ija 4 .fl(2 );
}
void f 3 ( i n t marker) {
p r i n t ( " f 3 ( " + marker + " ) " ) ;
}
s t a t i c C in ija ci n i j a 5 = new C i n i j a ( 5 ) ;
}
pu b lic class S t a t i c k a l n i c i j a l i z a c i j a {
pu b lic s t a t i c void m a in (S trin g [] args) {
p r i n t ( " P r a v l je n je novog objekta klase Kredenac() u metodi main");
new KredenacO;
p r i n t ( " P ra vlje n je novog objekta klase Kredenac() u metodi main " ) ;
new Kredenac( ) ;
s t o . f 2 ( 1) ;
k r e d e n a c . f3 ( l) ;
}
s t a t i c Sto sto = new S to () ;
s t a t i c Kredenac kredenac = new Kredenac();
} / * I s p is :
C in ija (l)
Cini j a (2)
Sto()
fl(l)
Ci ni j a(4)
C in ija ( 5 )
Cini ja (3)
Kredenac()
f 1 (2)
P r a v lje n je novog objekta klase Kredenac() u metodi main
C in ija ( 3 )
KredenacO
142 Misliti na Javi
fl(2 )
P ra v lje n je novog objekta klase Kredenac() u metodi main
C in ija ( 3 )
KredenacO
f 1 (2)
f 2 (1)
f 3 (1)
* ///:-
Klasa Cinija om oguava da p ra tite pravljenje objekata, a klase Sto i Kredenac na vie
m esta u n u ta r definicija im aju statin e lanove klase Cinija. O b ra tite p a n ju na to da Kre-
denac pre statinih definicija p rav i nestatian objekat Cinija cinija3.
Iz rezu ltata p re th o d n o g p ro g ra m a v idite d a se inicijalizacija statin ih elem en ata javlja
sam o ako je n e o p h o d n a. A ko n e n a p rav ite objekat klase Sto i ako se n ik ad a ne o b ratite
m e to d a m a Sto.cinijal ili Sto.cinija2, statin i objekti Cinija cinijal i cinija2 nik ad a nee
b iti n apravljeni. O n i se inicijalizuju sam o kada se p rav i prvi o bjek at klase Sto (ili kada se
p rv i p u t p ristu p a statin o m p o d a tk u ). N akon toga, vie se ne obavlja p o n o v n a inicijali-
zacija statin ih objekata.
Prvo se inicijalizuju statin i elem en ti, ako to ve nije u in jen o , a zatim nestatin i. D o-
kaz za to vidite u rezu ltatu p re th o d n o g p ro g ram a . D a b i se izvrila statin a m e to d a m ain(
), m o ra b iti uitan a klasa Staticlnitialization, a zatim se inicijalizuju n jen a statin a polja
sto i kredenac, to p ro u zro k u je uitavanje tih klasa; p o to o b e te klase sadre statin e o b -
jekte Cinija, zatim se uitava Cinija. Tako se sve klase ovog p ro g ra m a uitavaju p re poet-
ka izvravanja m etode main( ). To najee nije sluaj, p o to u tip i n o m p ro g ram u sve
nee b iti povezano statin im e lem en tim a kao u ovom p rim eru .
Da b ism o napravili saetak procesa pravljenja objekta, p o sm a tra jm o klasu p o d im e-
n o m Pas:
1. Iako se u njoj rezervisana re sta tic ne upotrebljava eksplicitno, k o n stru k to r jeste
statin a m eto d a. Stoga, p ri p rv o m pravljenju objekta tip a Pas ili kada se prvi p u t
p ristu p a statikoj m eto d i ili statik o m polju klase Pas, Javin in te rp re te r m o ra da
p ro n a e d ato tek u Pas.class, to ini pretraivanjem p u ta n je klasa (engl. classpath).
2 . Pri uitavanju P as.class (pri em u se pravi objekat klase C lass, o em u e kasnije
biti rei) pokree se inicijalizacija svih statin ih elem enata. Z nai, o n i se inicijalizu-
ju sam o jed an p u t, kada se odgovarajui objekat klase C lass uitava p o prvi put.
3. Kada napravite objekat o p eracijo m n ew Pas(), proces kon stru k cije objekta nalae
da se prvo zauzm e do v o ljn o skladinog p ro sto ra u d in am i k o m m em o rijsk o m
p ro sto ru .
4 . Taj p ro sto r se p o p u n i n u lam a, im e se au to m atsk i zadaje p o d ra zu m e v a n a v red n o st
svih pro m en ljiv ih pro sto g tipa u to m o bjektu Pas (n u la za brojeve i njen ekvivalent
za b o o le a n i c h a r), a sve reference d obijaju vre n o st nu ll.
5. Izvravaju se sve inicijalizacije koje se javljaju na m estu definicije polja.
6. Izvravaju se k o n stru k to ri. Kao to ete videti u poglavlju Ponovno korienjc klasa,
to m oe da b u d e veliki posao, n aro ito p ri nasledivanju.
Poglavlje 5: Inidjalizacija i ienje 143
O vo podsea na m eto d u , ali je to sam o rezervisana re sta tic posle koje sledi b lo k koda.
Ovaj k o d se, kao i d ru g e inicijalizacije sta ti n ih elem enata, izvrava sam o je d n o m , kada
prvi p u t p rav ite objekat te klase ili kada p rv i p u t p ristu p a te stati n o m lan u klase (ak i
ako n ik ad a n e n ap rav ite o b jek at te klase). N a p rim e r:
class S o l jic e {
s t a t i c S o ljic a s o l j i c a l ;
s t a t i c S o ljic a s o ljic a 2 ;
s ta tic {
s o l j i c a l = new S o l j i c a ( l ) ;
s o l jic a 2 = new S o l jic a ( 2 ) ;
}
S o l jic e ( ) {
p rin t("S o lj i c e ( ) " ) ;
} / * I s p is :
Unutar metode main()
S o ljic a (l)
S o ljic a ( 2 )
f (99)
* ///:-
Statini elem en ti klase S oljice in icijalizu ju se bilo da se sta ti n o m o b jek tu s o ljic a l p ri-
stu p a u red u o zn a en o m sa (1), b ilo d a je red (1) k o m en ta risan a iz redova o zn aen ih sa
(2) uk lo n jen k o m en tar. A ko su i (1) i (2) k o m en tarisan i, statin i elem en ti nee b iti inici-
jalizovani, kao to v id ite iz rezu ltata p ro g ra m a . Takoe nije b itn o da li je k o m e n ta r uklo-
njen isp red sam o je d n o g red a ili o b a re d a o zn aen a sa (2); statin i elem en ati e se
inicijalizovati sam o je d n o m .
V eba 13: (1) P roverite n are d b e iz p re th o d n o g pasusa.
V eba 14: (1) N ap rav ite klasu s je d n im sta tin im p o ljem tip a S trin g koje se inicijalizuje
n a m e stu definisanja i d ru g im p o lje m koje in i ja liz u je statian blok. D oajte statin u
m e to d u koja ispisuje o b a p o lja i p o k azu je d a se o b a inicijalizuju p re u p o treb e.
// : inicijalizacija/Solje.java
/ / Javina " I n i c i j a l i z a c i j a i n s t a n c i. "
i mp o r t s t a t i c n e t . m i n d v i e w . u t i 1 . P r i n t . * ;
class Solja {
S o l j a ( i n t marker) {
p r i n t ( " S o l j a ( " + marker + " ) " ) ;
}
void f ( i n t marker) {
p r i n t ( " f ( " + marker + " ) " ) ;
}
}
{
s o l j a l = new S o l j a (1);
so lja 2 = new Solj a(2 );
p r i n t ( " s o l j a l i solja 2 i n i c i j a l i z o v a n i " ) ;
}
izgleda gotovo istovetno kao o d red b a za inicijalizaciju statin ih elem enata, sam o to ne-
dostaje rezervisana re static. O va sin tak sa je n e o p h o d n a da bi se obezbedila p o d rk a za
inicijalizaciju anortim nih unutranjih klasa (poglavlje U nutranje klase), ali o m o g u u je i
da jam ite kako e se o d re en e op eracije izvriti bez o bzira na to koji e eksplicitni kon-
s tru k to r biti pozvan. Iz rezultata p ro g ram a v id ite da se o d re d b a inicijalizacije instanci
izvrava p re svih k o n stru k to ra.
Veba 15: (1) N aprav ite klasu s je d n im p o ljem tip a String koje se inicijalizuje p o m o u
inicijalizacije instanci.
Inicijalizacija nizova
Niz je sekvenca objek ata ili elem en ata pro sto g tip a koji su jed n o g istog tip a i upak o v an i
zajed no p o d jed n im im e n o m za identifikaciju. N izovi se definiu i koriste p o m o u ope-
ratora indeksiranja [ ]. R eferencu niza definiete tako to iza im ena tip a stavite prazn e
uglaste zagrade:
i n t [ ] a l;
146 Misliti na Javi
Ako uglaste zagrade stavite posle id en tifik ato ra, znaenje e b iti p o tp u n o isto.
in t a l [ ] ;
int [] al = { 1, 2, 3, 4, 5 };
in t [] a2;
a2 = a l;
/ / : in i c i j a l i z a c i j a / N i z o v i P r o s t i h T i p o v a . j a v a
import s t a t i c n e t .m in dvi e w . u t i 1 . P r in t
/ / : in i c i j a l i z a c i j a / N i z o v i I N e w . j a v a
/ / P ra v lje n je nizova operatorom new.
import j a v a . u t i 1 . * ;
import s t a t i c n e t . m in d v i e w . u t il. P r i n t . * ;
Poto se veliina niza bira p seu d o slu ajn o (m e to d o m R a n d o m .n e x tIn t(), iji je re zu k
tat sluajan broj izm e u nule i n jen o g arg u m e n ta ), jasn o je da se niz zaista pravi za v rem e
izvravanja. Pored toga, iz rezultata ovog p ro g ram a v id ite da elem en ti nizova p ro stih ti-
pova au to m atsk i d o b ijaju p o d raz u m ev an e v red n o sti. (Za n u m erik e i p rom enljive tipa
ch a r to je nula, a za b o o le a n to je false.)
M etod a A rra y s.to S trin g (), koja p rip ad a sta n d a rd n o j Javinoj biblioteci ja v a .u til, daje
verziju je d n o d im e n z io n a ln o g niza koja se m oe ispisati.
i n t [] a = new i n t [ s l u c a j a n . n e x t l n t ( 2 0 ) ] ;
/ / : in ic ij a l i z a c i j a / N i z O b j e k a t a . j a v a
/ / P ra v lje n je niza i j i elementi nisu prostog t i p a .
import j a v a . u t i l . * ;
import s t a t i c n e t . m in d v i e w . u t il. P r i n t . * ;
Integ er [] a = new I n t e g e r [ s lu c a ja n . n e x t l n t ( 2 0 ) ] ;
Ako to k o m izvravanja zab o rav ite da n ap rav ite objekat, javie se izuzetak kada po k u -
ate da u p o tre b ite p ra z n u lokaciju u nizu.
Niz o b jekata tak o e m o ete da inicijalizujete koristei listu izm eu vitiastih zagrada.
Za to p o sto je dva oblika:
p u b lic class I n i c i j a l i z a c i j a N i z a {
p u b lic s t a t i c void m a in ( S tr in g [] args) {
Integerf ] a = {
new I n t e g e r ( l ) ,
Poglavlje 5: Inicijalizaaja i ienje 149
new I n t e g e r ( 2 ) ,
3, / / Autopakovanje
);
In te g e r[ ] b = new Integer [ ] {
new I n t e g e r ( l ) ,
new In te g e r( 2 ) ,
3, / / Autopakovanje
);
S y s t e m . o u t. p r in t ln ( A rr a y s . to S tr in g ( a ) ) ;
System.out. p r i n t ln ( A r r a y s . t o S t r i ng(b)) ;
};
} / * I s p is :
[1. 2, 3]
[1, 2, 3]
* ///:-
U ob a sluaja, zavrni zarez u listi inicijalizatora nije obavezan. (Z ato je lake o d ra-
vanje dugakih lista.) Poslednji zarez u listi inicijalizatora je o p cio n i. (O va m o g u n o st je
n am en jen a lakem o d ravan ju d ugakih lista.)
lako je p rv i oblik k oristan , njegova o g ran ien ja su vea, je r se m oe u p o treb ljav ati
sam o na m estu definicije niza. D rugi i trei oblik m oete u p o tre b iti b ilo gde, ak i u n u ta r
poziva neke m etode. Na p rim er, m ogli biste n ap rav iti niz o bjekata tip a String koje ete
proslediti m etod i main() neke d ru g e m etode, da biste n a taj n ain zadali a ltern ativ n e ar-
g u m en te k o m a n d n e Iinije toj m eto d i main():
/ / : i n i c i j a l i z a c i j a / D i n a m i c k i N i z . java
/ / I n i c i j a l i z a c i j a nizova.
Veba 17: (2) N aprav ite klasu s k o n stru k to ro m koji p rim a arg u m en t tip a String. T okom
p ravljenja ispiite taj a rg u m en t. N apravite niz referenci objek ata te klase, ali n e m o jte p ra -
viti objekte koje ete d o d eliti to m n izu. K ada p o k ren ete p ro g ram , p ro v erite d a li se ispi-
suju inicijalizacione p o ru k e iz poziva k o n stru k to ra .
Veba 18: (2) D o p u n ite p re th o d n u vebu p ravljenjem o bjekata koje ete d o d eliti n iz u re-
ferenci.
class A { }
M oete v ideti da p r in t( ) u zim a niz elem enata tip a O b jec t, a zatim foreach sintaksom
prolazi kroz niz i ispisuje sve njegove objekte. Klase sta n d a rd n e Javine biblioteke daju ra-
zum ljiv ispis, ali o bjekti ovde n ap rav ljen ih klasa tam p aju im e klase, znak @i heksadeci-
m aln e cifre. D akle, p o d ra z u m e v a n o p o n aan je (ako za svoju klasu ne definiete m eto d u
to S trin g ( ), to e b iti o p isan o u nastavku knjige) jeste da se ispisuje im e klase i adresa
olijekta.
Poglavlje 5: Inicjjalizacija i ienje 151
O vako su se pre pojave Jave SE5 pisali Java p ro g ram i d a bi se d ob ile p rom enljive liste
p ara m e ta ra . M ed u tim , u Javi SE5 pojavila se du go zahtevana m o g u n o st da se p ro m en lji-
ve liste p a ra m e ta ra definiu p o m o u o p era to ra tri take, kao to vidite u sledeoj m e to d i
ispisiNiz():
/ / : in ic ij a li z a c i ja / O p c io n i P r a t e iA r g u m e n t i. java
I ovo pokazuje da prom enljiv.e p a ra m e tre m oete u p o treb ljav ati i sa zadatim tip o m
koji nije Object. U p re th o d n o m p rim e ru , svi p ro m en ljiv i p a ra m e tri m o ra ju biti String
objekti. U p ro m en ljiv im p a ra m e trim a m o g u se ko ristiti svi tip ov i, i prosti. U sledeem
p rim e ru po k azu jem o d a lista p ro m en ljiv ih p a ra m e ta ra p ostaje niz i da je veliina to g niza
nula ukoliko ta lista n e m a sadraja:
s t a t i c void f( L o n g . . . argumenti) {
S y s t e m . o u t . p r i n t ln ( " t r e i" ) ;
}
public s t a t i c void m a in (S trin g [] argumenti) {
f C a ' , ' b ' , 1c ' ) ;
f (i);
f(2 . i) ;
f (0 );
f (0 L );
/ / ! f ( ) ; / / Nee se prevesti - - vieznano
}
} / * Is p is :
prvi a b c
drugi 1
drugi 2 1
drugi 0
trei
* ///:-
//: inicijalizacija/PreklapanjePromenljivihParametara3.java
Po pravilu, listu p ro m en ljiv ih arg u m e n a ta treb alo bi d a u p o treb ljav ate sam o u jed n o j
od p rek lo p ljen ih m eto d a. Ili, u o p te n e u p o trebljavajte.
Veba 19: (2) N apiite m e to d u koja p rim a String niz p ro m en ljiv ih a rg u m en ata. U verite
se da toj m e to d i m oete proslediti listu elem en ata tip a String razdvojenih zarezim a ili
String[].
Veba 20: ( 1) N apiite m e to d u main() koja u m esto u o b iajen e sintakse u p o treb ljav a p ro -
menljive a rg u m en te. Ispiite sve elem en te rezu ltu ju eg niza args. Ispitajte tu m e to d u p o -
m ou razliitog b ro ja arg u m e n ata s k o m a n d n e linije.
Nabrojani tipovi
Naizgled m ali d o d a tak u favi SE5 jeste rezervisana re e n u m koja m n o g o olakava ivot
kada tre b a da g ru piete i u p otreb ite skup nabrojanih tipova (engl. enum erated types). N e-
kada biste napravili skup k o n sta n tn ih c elo b ro jn ih v red n o sti, ali one ,,ne znaju da ine
skup, pa se rizinije i tee upo trebljavaju. Inae, n a b ro jan i tip o v i su toliko esto p o tre b n i
da su oduvek postojali u C -u , C + + -u i u vie d ru g ih jezika. Pre Jave SE5, p ro g ra m e ri na
Javi m orali su m n o g o d a znaju i da paze kako bi valjano proizveli e n u m efekat. Sada i Java
ima e n u m , a o n je ak i m oniji o d o noga to im aju C /C + + . Evo je d n o stav n o g p rim era :
/ / : i n i c i j a l iza ci j a / L j u t o . java
pu b lic enum Ljuto {
NE, BLAGO, SREDNJE, MNOGO, PALI
} ///:-
156 Misliti na Javi
K ada n ap rav ite enum, p revodilac m u au to m atsk i dod aje korisne m o g u n o sti. N a p ri-
m er, prav i m e to d u toStringO k o jo m m o ete lako da prik aete im e enum instance.
(U pravo tako je p re th o d n a n ared b a print dala rezultat. Prevodilac pravi i m e to d u ordi-
nal() koja daje red n i bro j d eklarisanja o d red en e enum k o n stan te u n jenoj klasi, i statin u
m e to d u values() koja daje niz v red n o sti enum k o n stan ti p o re a n ih p o red o sled u kojim
su bile deldarisane:
lako enum izgleda kao nov tip p o d atak a, ta rezervisana re sam o o d re u je p o n aan je
p revodioca to k o m generisanja klase za enum, pa m oete u m n o g o m e da ga tre tira te kao i
svaku d ru g u klasu. U stvari, n a b ro jan i tipovi i jesu klase sa sopstvenim m eto d am a.
Posebno je zg odno kako se n ab ro jan i tipovi m o g u u p o trebljavati u n u ta r n ared b e
svvitch:
p u b lic void o p i i (} {
System .out.print("O va plje ska vic a j e " ) ;
switch(stepen) {
case NE: System .ou t.println ("po tp un o nezainje na." ) ;
break;
case BLAGO;
case SREDNJE: S y s t e m . o u t . p r i n t l n ( " l j u t k a s t a . " ) ;
break;
case MNOGO:
case PALI:
d e fa u lt: S y s te m .o u t.p rin tln ("p re lju ta .");
}
}
p u b lic s t a t i c void m a in (S trin g [] args) {
P1jeskavic a
bez = new P1jeskavica(Ljuto.N E),
bib e r = new P1jeska(Zainjenost.SREDNJE),
fefero n = new P1jeska(Zainjenost.MNOGO);
bez.opii ( ) ;
b ib e r . o p i i ( ) ;
f e f e r o n . o p i i ( ) ;
}
} / * I s p is :
Ova p lje s k a v ic a j e potpuno nezainjena.
Ova p lje s k a v ic a j e lj u t k a s t a .
Ova p lje s k a v ic a j e p r e l j u t a .
* ///:-
Saetak
P rilino razra en m e h a n iz am ini jalizacije, kakav je k o n stru k to r, treb alo bi da ukae na
o g ro m n u vanost koja je u o v o m jeziku d ata inicijalizaciji. Jedno od p rv ih zapaanja o
p ro d u k tiv n o sti u C -u , koje je S tro u stru p izneo d o k je p ro jek to v ao jezik C + + , bilo je da
nep rav iln a in icijaliza ja p ro m en ljiv ih p ro u zro k u je znaajan deo pro b lem a p ri p ro g ra-
m iran ju . O v u v rstu greaka je teko p ro n ai, a slini p ro b lem i javljaju se i p ri nepravil-
n o m ienju. Poto k o n stru k to ri o m o g u u ju da garantujete prav iln u inicijalizaciju
(prevodilac nee d o zv o liti d a o b jek at b u d e n ap rav ljen bez valjanog poziva k o n stru k to ra ),
d obijate p o tp u n u k o n tro lu i sig urno st.
U C + + -u u n itav an je je v eom a b itn o , je r objekti n apravljen i o p e ra to ro m n ew m o raju
eksplicitno da b u d u u n iten i. Sakuplja sm ea u Javi au to m atsk i oslobaa m em o riju ,
tak o da u veini sluajeva o d g o varaju e m eto d e za ienje nisu p o treb n e. (Ali kada jesu,
m o rate sam i sve d a u ra d ite .) Kada v am ne treb a p o n a a n je nalik na d estru k to re, Javin sa-
kuplja sm ea u m n o g o m e p o jed n o stav lju je p ro g ram ira n je i dodaje preko p o tre b n u si-
g u rn o st u u p rav ljan ju m e m o rijo m . N eki sakupljai sm ea m o g u ak da iste i drug e
resurse, kao to su id en tifik ato ri d ato tek a i grafikih objekata. M e u tim , sakuplja sm ea
dod aje reijske trokove to k o m izvravanja p ro g ram a, iju je cenu teko pro cen iti zbog
tra d i o n a ln e sp o ro sti Javinih in te rp re ta to ra. Iako su se p erfo rm an se Jave z n atn o po-
boljaie to k o m v rem en a, taj jezik se, zbog svoje spo ro sti, i dalje ne p rim en ju je u nekim si-
tuacijam a.
O k o n stru k to rim a p osto ji jo stvari koje nisu ra zm o tren e u ovom poglavlju. Poto ga-
rancija ko n stru k cije vai i kada p rav ite nove klase kom pozicijom ili nasleivanjem , p o treb-
n a je d o d a tn a sin tak sa da bi se to podralo. O kom poziciji, nasleivanju i to m e kako te
operacije u tiu n a k o n stru k to re , nauiete u n ared n im poglavljim a.
R eenja o d a b ra n ih vebi d a ta su u e le k tro n sk o m d o k u m e n tu The Thinking in Java Am iotated Solu-
tion Guide, k oji se m o e k u p iti na lo kaciji www.M indView.com.
Kontrola pristupa
K ontrola p ristu p a (ili sakrivan je realizacije) zn ai m oi p o p ra v iti ono to p r v i p u t nije bilo
dobro u ra en o .
SVI DOBRI PISCI - UKLJU U JU I T U I O N E KOJI PlSU SOFTVER - ZN A JU DA NITA NIJE D O BRO
n ap isan o d o k se vie p u ta n e p rerad i. A ko d eo svog k o d a na neko v rem e ostavite u fioku
i zatim ga p o n o v o p ro itate, m o d a ete o tk riti m n o g o bolji n a in d a ga u rad ite. To je je-
dan o d glavnih razloga za p o n o v n u p o d e lu na p ro ste faktore, dakle za p re ra d u fu n k cio n al-
nog k o d a da bi se uin io itljiviji i razum ljiviji, a sam im tim e se i lake o d rav ati.1
M e u tim , posto je i p ro b lem i zbog n asto jan ja d a se p ostojei k o d m en ja i poboljava.
esto korisnici (p ro g ra m eri klijen ti) rau n aju na to da e o d re e n i aspekat koda ostati
neizm enjen. D akle, vi h o ete d a ga m en jate, a o n i d a o n o stan e neizm en jen . Z ato je jed an
od o sn o v n ih ciljeva o b jek tn o o rijen tisan o g dizajna razdvojiti o n o to se m en ja o d stvari
koje o sta ju iste.
O vo je p o se b n o vano za biblioteke. K orisnici biblioteke m o ra ju b iti sig u rn i kako se
m ogu o slo n iti na deo koji k o riste i kako nee m o rati p o n o v o d a p iu p ro g ra m e k ad a se
poiavi nova verzija biblioteke. S d ru g e stran e, tvorac biblioteke m o ra im ati slo b o d u da
pravi izm en e i u n a p re e n ja a da p ri to m b u d e siguran kako te izm ene nee uticati na kod
klijentskog p rog ram a.
Sve to m o e da se ostvari p rek o konvencija. Na p rim er, p ro g ra m e r biblioteke m o ra da
se sloi kako nee izbacivati postojee m eto d e kada m enja klasu u b iblioteci, je r b i tim e
n aru io k o d p ro g ram era klijenta. O b rn u ta situacija je z n atn o sloenija. A ko je re o polju,
kako tv orac biblioteke m oe da zna kojim su p oljim a p ristu p ali p ro g ra m e ri klijenti? Isto
vai i za m eto d e koje su sam o deo realizacije klase i nisu n am en jen e da ih d ire k tn o u p o -
trebljavaju p ro g ram e ri klijenti. ta ako tvorac biblioteke eli d a p o tp u n o izbaci staru re-
alizaciju i napie novu? M enjanje bilo koje od gore p o m e n u tih lanica m oglo bi d a n arui
ko p ro g ra m e ra klijenta. Stoga su tvorcu biblioteke vezane ruke i ne m oe nita d a m enja.
Da bi se reio ovaj p ro b lem , u Javi postoje specifikatori p ristu p a koji tv o rcu biblioteke
o m o g uava ju da naznai ta je p ro g ra m e rim a klijentim a d o stu p n o , a ta nije. N ivoi d o -
zvoljenog p ristu p a od p o tp u n o g p ristu p a" d o najm anjeg p ristu p a jesu p u b lic , p ro te c -
ted, p ak etn i p ristu p ( 7 a koji ne p ostoii rezervisana re) i p riv a te . N a o sn o v u p re th o d n o g
m oete p o m isliti da kao p ro jek tan t b iblioteke treb a sve da uvate to ,,privatnije m ogue
i da izloite sam o m etode koje elite da p ro g ram eri klijenti koriste. To je sasvim tano,
iako je esto su p ro tn o intuiciji stru n ja k a koji p ro g ram ira ju na d ru g im jezicim a (poseb-
no na C -u ) i koji su navikli da svem u p ristu p aju bez ogranienja. D o kraja ovog poglavlja
trebalo bi d a se uverite u znaaj k o n tro le p ristu p a u Javi.
' V ideti liefactoring: Improving tlie Design o f Existing Code, koji su napisali M artin Fow!er i dr. (Addi-
son-W esley, 1999). Povrem eno se neko pobuni protiv po n o v n ep o d ele na proste faktore, sa argum en-
tom da je kod koji radi savreno d o b ar i da preraivati ga znai gubiti vrem e. Takav argum ent nije
vaijan zato to lavovski deo vrem ena i novca koji se uloi u projekat ne o tp ad a na prvo pisanje koda,
nego na njegovo odravanje. U initi kod razum ljivijim , znai utedeti m nogo novca.
16 0 Misliti na Javi
/ / : pristup/PunoIme.java
Sada ArrayList m oete da k o ristite bez im en a paketa. M e u tim , nije d o stu p n a nijedna
d ru g a klasa iz p aketa java.util. Da biste uvezli sve klase biblioteke, u p o tre b ite * kao to je
u rad e n o u ostalim p rim e rim a u ovoj knjizi:
import j a v a . u t i l . * ;
Do sada se vei d eo p rim e ra u ovoj knjizi nalazio u je d n o j d ato teci i bio je n ap isan za
lokalnu u p o tre b u , te se nije b avio im e n im a pak eta. U tim p rim e rim a klase su ip ak bile u
paketu, tzv. n eim en o v an o m ili podrazumevanom paketu. To se svakako m oe rad iti, i u
nastavku knjige takav p ristu p bie korien gde g o d je m ogue, je d n o stav n o sti radi. Ali
ako nam eravate da prav ite b iblioteke ili p ro g ram e koje e v o d iti ra u n a i o d ru g im p ro -
gram im a na istom ra u n a ru , m o ra te da v o d ite ra u n a o sp reav an ju su k o b a im en a klasa.
Kada p rav ite dato tek u sa izv o rn im k o d o m za Javu, ta d ato te k a se esto naziva i jedinica
za prevoenje (engl. compilation unit, translation unit ). Im e svake jed in ice za p revoenje
m ora da se zavrava sa .java, a u n u ta r nje m oe da p o sto ji je d n a jav n a (public) klasa istog
im ena kao i d atoteka (uk lju u ju i i velika i m ala slova, ali bez nastavka .java). U svakoj je-
dinici za prevo en je m oe d a se nalazi sam o jedna jav n a klasa, in ae se prev o d ilac b u n i.
Ostale klase iz te jed in ice za prev o en je, ako ih u o p te im a, skrivene su o d sp o ljn o g sveta
izvan tog paketa, jer o n e nisu javne i p red stav ljaju kiase za ,,p o d rk u glavnoj javnoj klasi.
Organizacija koda
Pri prev o en ju dato tek e .java, d o b ijate p o je d n u izlaznu d a to te k u za svaku klasu iz d ato -
teke .java. Svaka o d tih izlaznih d ato tek a im a isto im e kao o d g o v araju a klasa u d atoteci
.java, ali s nastavkom .class. Stoga iz m alog b ro ja d a to tek a .java m oete da dobijete p ri-
lian broj datotek a .class. Ako ste p ro g ram ira li n a jeziku koji se p rev o d i u izvrni oblik,
verovatno ste navikli da prevodilac p rav i m e u o b lik (o b in o d ato te k u .obj) koji zatim s
drugim d ato tek am a istog oblika p ak u jete p o m o u povezivaa (engl. linker) d a biste na-
pravili izvrnu d atoteku ili to inite p o m o u b ib lio tek ara (engl. librarian) da biste n a p ra -
vili biblioteku. Java ne radi n a taj nain . P ro g ram koji rad i je sk u p d ato te k a .class koje
m ogu da b u d u spakovane i k o m p rim o v an e u JAR arh iv u (p o m o u Javinog arh iv ara jar.)
Posao Javinog in te rp re ta to ra je da p ro n a e, u ita i in te rp re tira 2 te d atoteke.
Biblioteka je skup takvih d ato tek a sa klasam a. Svaka izvorna d ato tek a o b in o im a jed-
nu klasu koja je javna i proizvoljan broj n ejavnih klasa, pa za svaku izv o rn u d ato tek u p o-
stoji je d n a javna (p u b lic) k o m p o n en ta . Ako elite d a n azn aite da sve te k o m p o n e n te
(koje se nalaze u o d vojenim d ato te k am a .java i .class) id u zajedno, k o risti se rezervisana
re package.
Ako ko ristite n ared b u package, o n a mora da b u d e u p rv o m re d u koji nije k o m e n ta r u
datoteci. Kada napiete:
package p r is tu p ;
/ / : pristup/OdreenaMojaKlasa.java
/ / : pristup/OdreenaMojaKlasa.java
import p ris tu p .m o jp a k e t.* ;
G ru p isan je d ato teka jed n o g pak eta u zaseban d ire k to riju m reava i jo dva p ro b lem a:
pravljenje jedinstv enih im en a paketa i pro n alaen je ldasa koje m o g u biti zak o p an e negde
u d u b in i stru k tu re direkto riju m a. To se p ostie tako to se p u ta n ja do d ato tek a .class ub a-
cuje u im e paketa. Po konvenciji, p rv i deo im e n a pak eta je im e In te rn e t d o m e n a tvorca
ldase, u o b rn u to m redosledu. Poto su im en a In te rn e t d o m e n a g aran to v an o jed in stv ena,
ako p rim en ju je te ovu konvenciju, im e vaeg pak eta e sig u rn o b iti jed in stv en o i nee doi
do suk o b a im en a (tj. d o k neko d ru g i ne p reu zm e va d o m e n i n e po n e da pie k o d na Javi
sa istim p u ta n ja m a koje ste i vi koristili). N aravno, ako n e m a te svoj d o m e n , sm islite m alo
v ero v atn u k om b in aciju (kao to je vae im e i prezim e) d a b iste n ap rav ili je d in stv en o im e
paketa. A ko ste odluili da objavljujete k o d p isan n a Javi, isp lati se ulo iti relativ n o m ali
n a p o r u pribavljanje linog do m en a.
D ru g i d eo ove tehnike je d a preslikate im e p ak eta n a im e d ire k to riju m a n a v aem ra-
u n a ru . Kada izvrni sistem treb a da u ita d a to te k u .class, m oe da p ro n a e d ire k to riju m
u k o m e se o n a nalazi.
Javin in te rp re ta to r radi sledee: prv o p ro n alazi sistem sku p ro m en ljiv u CLASSPATH3
(koja se postavlja u o p erativ n o m sistem u, to p o n ek a d u ra d i in stalacioni p ro g ram koji na
ra u n a ru instalira Javu ili na Javi zasnovanu alatk u ). CLASSPATH sadri je d a n ili vie di-
rek to riju m a koji se koriste kao korenski za traen je d ato tek a .class. In te rp re ta to r u im en u
paketa zam enjuje svaku taku kosom crto m da bi generisao p u ta n ju od korena definisanog
p rom enljivom CLASSPATH (tako paket foo.bar.baz postaje foo\bar\ baz ili foo/bar/baz
ili m o da neto drugo, u zavisnosti od vaeg o p erativ n o g sistem a). To se zatim spaja s ra-
znim d irek to riju m im a iz p u tan je CLASSPATH. N a tim m estim a in te rp re ta to r trai d ato -
teku .class ije im e odgovara klasi koju p okuavate d a napravite. (O n tak o e p retrau je i
neke stan d a rd n e d irektoriju m e u zavisnosti o d m esta n a k o m e se in te rp re ta to r nalazi.)
D a biste ovo shvatili, razm o trite im e m og d o m e n a - MindView.net. Kada o b rn e m o
redosled i svc ispiem o m alim slovim a, net.m indview ustanovljava se jed in stv en o global-
no im e za m oje klase. (N astavci com , edu, org itd. ranije su u Javinim pak etim a pisani ve-
likim slovim a, ali ie to p ro m e n je n o u Javi 2, tako da se celo im e pie m alim slovim a.) Ako
od luim da n ap rav im biblioteku p o d im en o m simple, u n eu p o d elu u g lobalno im e i d o -
biti im e paketa:
package net.mindview.simple;
/ / : ne t/m indview/simple/Vector.java
/ / P ra v lje n je paketa
package net.mindview.simple;
//: net/mindview/simple/List.java
// Pravljerje paketa.
package net.mindview.simple;
C:\DOC\JavaT\net\mindview\simple
Kada p ro m en ljiv u CLASSfATH p o d esite kako treba, n ared n u d ato tek u m oete da sta-
vite u bilo koji d irek to riju m :
/ / : p r is tu p / L ib T e s t .ja v a
/ / K o r i s t i b i b li o t e k u .
import ne t.m in dview .sim ple .*;
Poto i java.util.* tak o e sadri klasu Vector, to m oe d a izazove sukob im ena. M eu-
tim , dokle g od ne napiete k o d koji izaziva d vosm islenost, sve e b iti u red u to je do b ro ,
inae biste m o rali m n o g o da piete d a biste izbegli sukob koji se nik ad a nee d ogoditi.
Sukob nastaje ako sada p o k u ate da n a p rav ite objekat klase Vector:
Vector v = new V e c to r () ;
Na koju se klasu Vector ovo odnosi? Prevodilac to ne m oe da zna, kao ni italac. Stoga
se prevodilac ali i zahteva da b u d ete izriiti. Ako, na p rim er, elite sta n d a rd n i Javin Vec-
tor, m o ra te da napiete:
/ / : n e t /m in d v i e w / u t il / P r i n t . ja v a
/ / Metode is p is iv a n j a koje se mogu u p o t r e b lja v a t i bez odreenja
/ / paketa i putanje, kada ih u Javu SE5 uvezemo kao s t a t i k e :
package n e t . m in d v ie w . u t il;
import j a v a . i o . * ;
p u b lic class P r in t {
/ / I s p i i i prei u nov red:
p u b lic s t a t i c void p r i n t (Object obj) {
S y s t e m . o u t . p r i n t ln ( o b j ) ;
}
/ / Samo prei u nov red:
pu b lic s t a t i c void p r i n t () {
S y s t e m . o u t . p r i n t ln ( ) ;
}
/ / I s p i i bez prelaska u nov red:
pu b lic s t a t i c void p rin tn b (Object ob j) {
S y s t e m . o u t. p r i n t ( o b j) ;
}
/ / Nova metoda p r i n t f ( ) Jave SE5 (kao u C-u):
p u b lic s t a t i c PrintStream
p r i n t f ( S t r i n g format, O b je c t . . . argumenti) {
return S y s t e m . o u t. p r in t f(f o r m a t, argumenti);
}
)///-
/ / : p r is tu p / P r in t T e s t . ja v a
/ / K o r i s t i s t a t i k e metode za is p i s i v a n j e , koje pripadaju kla si
/ / P r in t . ja v a .
import n e t.m in d v ie w .u ti1. P r i n t . * ;
p rin t ( lO O L ) ;
p r i n t ( 3 . 14159);
}
) / * I s p is :
Dostupna od sada pa na dalje !
100
100
3.14159
* ///:-
O d sad a m oete u svoju bib lio tek u d o d ati svaku k o risn u novu alatku kada god naiete
na nju. B iblioteci n e t.m in d v ie w .u til do d av aem o k o m p o n e n te kroz celu knjigu.
1 68 Misliti na Javi
Paketni pristup
U svim p rim e rim a d o ovog poglavlja specifikator p ristu p a u o p te nije bio naveden. Za
p odrazu m ev an i p ristu p ne p o sto ji rezervisana re, ali se o n o b i n o naziva p a k e tn i (katka-
da i ,,prijateljski ). To znai da sve ostale klase iz tekueg p ak eta im aju p ristu p to m lanu,
ali sve klase van tog paketa taj lan v ide kao p riv a tn i (i n e m o g u da m u p ristu p e ). Poto
jedinica za prevoenje - d ato tek a - m o e d a p rip a d a sam o je d n o m p ak etu , sve klase u n u -
tar nje a u to m atsk i su d o stu p n e jed n a d ru g o j, zato to im aju p ak etn i p ristu p .
Paketni p ristu p om o g uav a da g ru piete sro d n e klase u je d a n pak et ta k o d a m o g u lako
m e u so b n o da k o m u n iciraju . Kada klase grup iete u pak et, im e p a k e tn im lano vim a
dozvoljavate m e u so b n i p ristu p , vi po stajete vlasnik" k o d a u to m p aketu. Im a logike u
tom e d a sam o k o d u vaem vlasnitvu treb a d a im a p ak e tn i p ristu p o stalo m k o d u u vaem
vlasnitvu. M oe se rei da p ak etn i p ristu p o p ravdava g ru p isa n je klasa u pakete. U m n o -
gim jezicim a, definicije m oete svakojako da organ izu jete, ali ste u Javi p risiljen i da ih or-
ganizujete n a razu m an nain . Pored toga, v ero v atn o ete odv ojiti klase koje n e tre b a da
im aju p ristu p klasam a defin isan im u tek u em pak etu .
Klasa k ontrolie odakle se m oe p ristu p a ti n jen im lano vim a. K od iz d ru g o g pak eta n e
m oe da se pojavi, kae: Z dravo, ja sam Perin p rijatelj i oekuje da e d o b iti p ristu p za-
tienim , p ak etn im i p riv a tn im lan o vim a klase Pera. lan u se dozvoljava p ristu p sam o
na sledee naine:
1 . C lan proglasite jav n im (p u b lic). Tada svako i sa svakog m esta m oe da m u p ristu p i.
2. lan u om og u ite paketni p ristu p izostavljajui bilo kakve specifikatore p ristu p a , a
ostale klase stavite u isti paket s njim . Tada ostale klase to g paketa m o g u da p ristu -
p aju to m lanu.
3. Kao to ete videti u poglavlju Ponovno korienje klasa posv een om n asleivanju,
p o to m a k klase m oe da p ristu p a i zatienim i jav n im lano vim a (ali ne i priv at-
n im lanovim a) roditeljske klase. lan o v im a s p a k etn im p ristu p o m m oe da p ri-
stu p a saino ako su te dve klase u istom p ak etu . O nasleivanju i zatienim
lan ovim a n em o jte sada da b rinete.
4 . O bezbedite m eto d e koje itaju i m enjaju eljenu v re d n o st (koje se tak o e nazivaju
i m etode p ro itaj/po stav i - engl. get/set rnethods). U O O P -u je to n ajp am etn iji p ri-
stu p i sutinski je znaajan za zrn a Jave, kao to ete videti u poglavlju Grafika ko-
risnika okruenja.
/ / : p r is tu p / d e s e rt /K o la c ic . ja v a
/ / Pravi b ib lio t e k u
package p r is tu p . d e s e rt ;
170 Misliti na Javi
/ / : pristu p/Vecera.ja va
/ / K o r i s t i b i b li o t e k u .
import p r i s t u p . d e s e r t . * ;
m oete da nap rav ite objek at klase K olacic, je r je njegov k o n stru k to r javni i klasa je javna.
(K oncept javnih klasa detaljnije em o razm o triti kasnije.) M ed u tim , m eto d a lanica za-
g rizi() nije d o stu p n a klasam a iz datoteke V ecera.java, jer m eto d a z a g rizi() o m oguava
p ristu p sam o klasam a iz paketa d e se rt, pa e vas prevodilac spreiti da je u p o treb ite.
Podrazumevani paket
M oda e vas iznenaditi kada o tk rijete da e naredni p ro g ra m biti ispravno preveden iako
na prvi pogled izgleda da kri pravila:
/ / : p r is tu p / T o r t a . ja v a
/ / Pristupa k la s i iz druge (zasebne) je d in ic e za prevoenje (dato teke).
class Torta {
pu b lic s t a t i c void m a in (S trin g [] args) {
P ita x = new P i t a ( ) ;
x .f 0 ;
}
} / * I s p is :
P i t a . f ()
* ///:-
Poglavlje 6: Kontrola pristupa 171
/ / : p r i s t u p / P it a . ja v a
/ / Druga klasa.
class Pita {
void f ( ) { S y s t e m . o u t . p r i n t l n ( " P i t a . f ( ) ' ' ) ; }
} ///:-
U p rv o m tre n u tk u , ove dve dato tek e m ogli biste d a p o sm a tra te kao p o tp u n o odvojene
pa ip a k o b jek at klase Torta m oe d a n ap ra v i objek at klase Pita i d a pozove n je n u m e to d u
f()! (V odite ra u n a o to m e d a u svojoj prom en ljiv o j CLASSPATH m o ra te im a ti ta k u da
bi se ove datotek e p rav iln o prevele.) Pom islili biste d a klasa Pita i f() im aju p a k e tn i p ri-
stu p i d a su stoga n e d o stu p n e klasi Torta. O n e imaju p ak etn i p ristu p taj d eo zakljuka
je ispravan. D o stu p n e su klasi u dato teci Torta.java zato to se nalaze u isto m direktori-
ju m u i n em aju izriito im e paketa. Takve dato tek e Java tre tira kao deo p o d razu m ev an o g
p aketa za taj d ire k to riju m i stoga om o g u av a p ak etn i p ristu p svim o stalim k lasam a u
istom d ire k to riju m u .
/ / : pris tu p /S la d o le d .ja v a
/ / Prikazuje rezervisanu re " p r iv a t e " .
class SladoledSaVocem {
p r iv a t e SladoledSaVocem() {}
s t a t i c SladoledSaVocem napraviSladoledSaVocem() {
r e tu rn new SladoledSaVocemf);
}
172 Misliti na Javi
//: pristup/CokoladniKeks.java
// N ije mogu pristup lanu s paketnim pristupom u drugom paketu
import pristup.desert.*;
//: pristup/kolacic2/Kolacic.java
package pris tu p.kolacic2;
//: pristup/CokoladniKeks2.java
import pr istup.kolacic2.*;
Interfejs i realizacija
K ontrola p ristu p a se esto naziva i sakrivanje realizacije. Pakovanje p o d atak a i m etoda
u n u ta rk la sa u k o m binaciji sa skrivanjem realizacije esto se naziva kapsuliranje.' Kao re-
zultat dobija se tip p o d atak a sa svojstvenim obelejim a i o d re e n im p o n aan jem .
K ontrola p ristu p a n am ee o g ran ien ja u n u ta r tip a p o d a ta k a iz dva b itn a razloga. Prvi
je da od red ite ta p ro g ram eri klijenti sm eju da koriste, a ta ne. In tern e m eh an izm e m o-
ete slo b o d n o da u g rad ite u stru k tu ru , bez b rig e o to m e da e p ro g ram e ri klijenti sluajno
koristiti in tern e delove interfejsa.
To nas uvodi d ire k tn o u d ru g i razlog, a to je razdvajanje interfejsa i realizacije. A ko se
stru k tu ra koristi u vie p ro g ra m a, a p ro g ram e ri klijenti sam o m ogu da alju p o ru k e jav-
n o n i interfejsu, tad a m oete da m enjate sve to nije jav n o (znai sve to je prijateljsko, za.-
tieno ili p riv atn o ), a da ne po k v arite klijentske p ro g ram e.
Radi boljeg razum evanja, kao stil pravljenja klasa m o ete usvojiti da na p o etk u stavite
javne lanove, a zatim zatiene, p ak etn e i p riv atn e. P red n o st ovog naina je to to kori-
snik klase m oe d a k ren e o d v rh a i prvo vidi o n o to m u je b itn o (javne lanove, jer njim a
m oe da p ristu p i izvan date datoteke) a zatim e se zau stav iti kada naide na ostale lanove
koji su deo in tern e realizacije:
private void p r iv l( ) { / * . . . * / }
private void priv2( ) { / * . . . * / }
private void priv3( ) { / * . . . * / }
private ir t i ;
/ /
} ///:-
O vo e sam o delim ino olakati itanje jer su interfejs i realizacija i dalje zajedno. O d n o -
sno, i dalje vidite izvorni ko d - realizaciju - je r se o n a nalazi tu , u klasi. Pored toga, dok u-
m entacioni k o m en tari koje p odrava alatka Javadoc u m a n ju ju znaaj itljivosti prog ram a
za prog ram era klijenta. Prikazivanje interfejsa k o risniku klase u stvari je posao itaa klasa
(engl. class browser), alatke iji je zadatak d a nap rav i pregled svih raspoloivih klasa i pokae
ta se s njim a korisno m oe u rad iti (tj. koje lanice su d o stu p n e). Prikazivanje d o k u m en ta-
cije razvojnog okruenja za Javu p o m o u itaa W eba daje isti rezultat kao i ita klasa.
Pristup klasama
Specifikatori p ristu p a u Javi tak o e se m o g u u p o tre b iti d a o d red e koje e klase u n u ta rb i-
blioteke biti d o stu p n e n je n o m k o risn ik u. A ko elite d a klasa b u d e d o stu p n a p ro g ra m e ru
kliientu, stavite rezervisanu re p u b lic n a elo definicije klase. T im e od re u jete d a li pro -
gram er klijent u op te m oe da n ap rav i objekat date klase.
Da bi kon tro lisao p ristu p klasi, specifikator m o ra da se n a e pre rezervisane rei class.
Stoga m oete d a napiete:
import pristup.Spravica;
import pristup.*;
ta ako u n u ta r b iblioteke pristup im ate klasu k o ju k o ristite sam o za zadatke koje izvr-
ava klasa Spravica ili neka d ru g a javna klasa iz te biblioteke? N eete d a piete d o k u m e n -
tacije za p ro g ra m e ra k lijenta i m islite kako ete k asnije v ero v atn o h te ti d a p o tp u n o
izm en ite stvari i celu tu klasu izbacite i zam e n ite je n ek o m novom . D a b iste zadrali tu
m o g u n ost, m o ra te o sig u rati da n ijed an p ro g ra m e r klijen t ne p o sta n e zavisan o d o d re-
e n ih detalja realizacije skrivenih u n u ta r biblioteke pristup. Da biste to postigli, izosta-
vite rezervisanu re public ispred klase, p ri em u o n a d o b ija p a k e tn i p ristu p . (Ta klasa
m oe d a se k o risti sam o u n u ta r paketa.)
Veba 7: ( 1) N ap rav ite bib lio tek u pristup n a o sn o v u p re th o d n ih delova k oa koji o p isu ju
n ju i klasu Spravica. Z atim n a p rav ite o b jek at klase Spravica u klasi koja nije d eo pak eta
pristup.
K ada n ap rav ite k lasu s p ak etn im p ristu p o m , im a sm isla d a n jen a p o lja b u d u p riv a tn a
p olja b i uvek treb alo d a b u d u p riv atn a ali je p o p rav ilu u p u tn o d ati m e to d a m a je d n ak i
(p aketni) p ristu p k ao klasi. Poto se klasa s p ak e tn im p ristu p o m o b i n o u p o treb ljav a
sam o u n u ta r svog pak eta, m eto d e takve klase tre b a da u in ite jav n im sam o ako m o rate , a
to e v am rei prevodilac.
Z ap am tite da klasa n e m oe da b u d e p riv a tn a (tim e bi postala d o stu p n a sam o sebi)
n iti zatiena.6 Za p ristu p klasi, stoga, im ate sam o dva izbora: p ak etn i ili javni. A ko elite
da nik o dru g i n e m a p ristu p nekoj klasi, sve k o n stru k to re m o ete da p roglasite p riv atn im ,
im e ete spreiti sve osim sebe da n aprave ob jek at te klase. (I vi ete to m oi sam o u n u ta r
statin e lanice te klase.) Evo p rim era:
//: pristup/Rucak.java
// Pokazuje specifikatore pristupa k la s i. Klasu pretvarate
// u privatnu proglaavajui njene konstruktore privatnim:
class Supal {
private Supal() {}
// (1) Dozvoljava pravljenje statikom metodom:
public s ta tic Supal napraviSupu() {
return new Supal( ) ;
}
class Supa2 {
private Supa2() {}
// (2) Napravi statin i objekat i vra ti referencu ako je zahtevano.
// ("Sing ularni" projektni obrazac):
private s ta tic Supa2 psl = new Supa2();
public s ta tic Supa2 pristupO {
return psl;
}
public void f ( ) {}
}
" U n u tra n ja (e n g l. inner) klasa m o c b iti p riv a tn a ili z ati e n a, ali to je s p ec ija la n sluaj. Te klase e
b iti o b ja n je n e u p o g la v lju Unutranje klase.
Poglavlje 6: Kontrola pristupa 177
///: pristup/lokal:UpakovanaKlasa.java
package pr is tup.lokal;
class UpakovanaKlasa {
public UpakovanaKlasa () {
System.out.print1n("Pravljenje upakovane klase1');
}
}
///: pristup/strana/Strana.java
package pristup.strana;
import pristu p. lo ka l.*;
Saetak
U svakoj vezi b itn o je da sve uklju en e stran e p o tu ju izvesne granice. Kada pravite bibli-
o tek u , vi uspostavljate vezu s k o risn ik o m te biblioteke - p ro g ra m e ro m klijen to m - koji je
tako e p ro g ram er, ali koji koristi vau b iblioteku da bi n ap rav io neku aplikaciju ili jo
veu biblioteku.
Kad ne bi bilo pravila, p ro g ra m e ri klijenti m ogli bi da rade ta im je volja sa svim la-
n o v im a klase, ak i k ada biste vi vie voleli da ne rade d irek tn o s nekim od njih. Sve bi bilo
p o tp u n o izloeno.
O vo poglavlje se o d n o silo na pravljenje klase da bi se fo rm irala biblioteka: prvo, na
koji nain se klase p ak u ju u je d n u bib lio tek u i dru g o , nain na koji klasa kontrolie pri-
stu p svojim lanovim a.
Poglavlje 6: Kontrola pristupa 179
P ro cen a je da pro jek ti pisani n a jeziku C p o in ju da se uru av aju kada d o stig n u izm e-
u 50 K i 100 K redova koda. C im a je in stv en im enski p ro sto r, p a im en a p o in ju d a se
su d a ra ju te ih m o rate raspetljavati. U Javi, rezervisana re package, te h n ik a im en o v an ja
pak eta i rezervisana re import, o b ezb e u ju p o tp u n u k o n tro lu n ad im e n im a , im e se
p ro b le m sa su d ara n je m im en a lako zaobilazi.
Postoje dva razloga za k o n tro lu p ristu p a lanovim a. Prvi je obezb ed iti da korisn ici
d re ru k e podalje o d delova koje ne bi sm eli da diraju . Ti delovi su n e o p h o d n i za in te rn i
ra d klase, ali nisu deo interfejsa koji je p o treb an p ro g ram e rim a k lijentim a. Z ato p ro g la-
avanjem m eto d a i p olja p riv atn im p rav ite uslugu p ro g ram e rim a k lijen tim a - lako m o g u
da razlue ta je za njih b itn o , a ta m o g u d a ignoriu. Z bog to g a bolje ra z u m e ju klase.
D ru g i i najvaniji razlog k o n tro le p ristu p a jeste o m o g u iti p ro je k ta n tu bib lio tek e da
p ro m e n i u n u tra n ji izgled ldase b ez brige o to m e kako e to u ticati n a p ro g ra m e ra kli-
jen ta . N a p rim e r, ldasu isprva n ap rav ite n a jed an nain , a zatim otk rijete kako e se re-
k o n stru k cijo m k oda b itn o u b rz ati izvravanje. Ako su interfejs i realizacija jasn o
razd v o jen i i zatieni, to m oete da postig n ete bez p rim o ra v a n ja p ro g ra m e ra k lijenta da
p o n o v o p iu svoje p ro g ram e. K ontrola p ristu p a osigurava d a n ijed an p ro g ra m e r k lijent
ne p o sta n e zavisan o d realizacije koja se nalazi u osn o v i klase.
K ada im ate m o g u n o st da m en jate o sn o v n u realizaciju, ne sam o da m o ete da u n a -
pre u je te projekat, ve i da prav ite greke. Bez ob zira na to koliko paljivo p lan ira te i p ro -
jek tu jete, naprav iete greke. Ako zn ate da greke nee izazvati m n o g o tete, biete vie
rasp olo eni za eksperim ente, bre ete uiti i bre zavravati projekte.
K orisnik vidi javni interfejs, pa je to, p rilik o m analize i p ro jek to v an ja p ro g ra m a , naj-
vaniji deo klase koji treba da u rad ite kako valja. ak vam je i tu d ata izvesna slo b o d a da
m en jate. A ko interfejs ne ,,pogodite iz prve, uvek m oete da dodate d ru g e m eto d e, dokle
god ne izbacite neke koje je p ro g ram e r klijent ve u p o treb io u svom p ro g ra m u .
O b ra tite pan ju na to da se kon tro la p ristu p a u sred sre u je na o d n o s - i n ek u v rstu
k o m u n ik a c ije - izm eu au to ra biblioteke i n jenih spoljnih klijenata. Im a m n o g o situacija
u kojim a to nije sluaj. P rim era radi, sam i piete sav kod ili rad ite zajedno s m a lo m eki-
p o m i sve to napiete ide u isti paket. U tim situacijam a p o tre b n a je drugaija k o m u n i-
kacija, pa k ru to prid ravan je pravila p ristu p a m oe da sm eta. Tada bi p o d ra zu m e v a n i
(p ak etn i) p ristu p m ogao da b u d e o p tim alan .
Reenja o d a b r a n i h vebi data su u e l e k tr o n sk o m d o k u m e n t u Thinking Iti Java A nnotated Solution
Guide, koji se m o e kupiti na Iokaciji www.M indView.net
Ponovno korienje klasa
Jedna od najlepih m ogunosti u Javijeste ponovno korienje koda. Ali, da biste u tom p o slu
bili revolucionarni, sa kodom m orate u m eti da uradite m nogo vie od p u ko g kopiranja i
menjanja.
Sintaksa kompozicije
D o ovog m esta u knjizi esto sm o k oristili k o m p o ziciju - sm etan je referenci na objekte
u n u ta r nove klase. P retp o stav im o , na p rim e r, da elite da n a p rav ite objekat koji uva ne-
koliko o bjekata tip a S trin g , nekoliko p ro stih tip o v a i o b jek at neke d ru g e klase. Kod slo-
enih tipova, u n u ta r nove klase stavljate reference, d o k p ro ste tipove d ire k tn o definiete:
//: ponovnaupotreba/Prskalica.java
// Ponovna upotreba koda kompozicijom.
class Izvor {
private String s;
Izvor() {
System.out.pri n t ln("Izvor()");
s = "Konstruisan";
}
public String t o S t r i n g O { return s; }
}
private int i ;
private float f;
public String t o S t r i n g O {
return
"ventill = " + ventill + " " +
"venti!2 = " + ventil2 + " 11 +
"ventil3 = " + ventil3 + " " +
"ventil4 = " + ventil4 + "\n" +
"i = 11 + i + " " + "f = " + f + " " +
"izvor = " + izvor;
}
public static void main(String[] args) {
Prskalica prskalice = new Prskalica();
System.out.println(prskal i c e ) ;
}
} /* Ispis:
Izvor()
ventill = null ventil2 = null ventil3 = null ventil4 = null
i = 0 f = 0.0 izvor = Konstruisan
* ///:-
prevodilac p rim eu je kako p okuavate da na objek at tipa String ("izvor = ") nadoveete
objekat tipa Izvor. Poto na objek at tip a String m o ete da nadoveete sam o d ru g i takav
olijekat, o n kae: pretv oriu Izvor u tip String po ziv an jem m e to d e toString(). N akon
toga, o n m oe da k o m b in u je dva o b jek ta klase String i da rezultat pro sled i m eto d i Sy-
stem.out. println() (ili p re th o d n o u knjizi d efin isan im statin im m eto d a m a print() i
printnb()). Kad god elite da klasi koju p rav ite o m o g u ite takvo p o n aan je, sam o nap i-
ite m e to d u toString().
Prom enljive pro stog tipa koje su polja klase, au to m a tsk i su inicijalizovane v rednou
nula, kao to je n a p o m e n u to u poglavlju Sveje objckat. M e u tim , reference na objekte ini-
cijalizovane su v red n o u null i ako preko bilo koje od tih referenci p o k u ate da pozovete
neku m eto d u , izazvaete izuzetak - greku to k o m izvravanja. D o b ro je to ipak m oete
da ispiete null referencu, a da se p ri to m ne javi izuzetak.
Im a sm isla to to prevodilac ne pravi p o d razu m ev a n i objek at za svaku referencu, je r bi
to u m n o g im sluajevim a izazvalo n ep o tre b n e reijske trokove. Ako elite da reference
b u d u inicijalizovane, to m o rate da u rad ite sam i:
1. Na m estu gde se objekti definiu. To znai d a e uvek biti inicijalizovani p re nego to
k o n stru k to r b u d e pozvan.
2. U k o n stru k to ru te klase.
182 Misliti na Javi
//: ponovnaupotreba/Kada.java
// Inicijalizacija u konstruktoru i kompozicija.
import static ne t.mindview.util.Print.*;
class Sapun {
private String s;
Sapun() {
print{"Sapun()");
s = Konstruisan";
}
public String t o S t r i n g O { return s; }
}
p rin t(b );
}
} /* Ispis:
Unutar klase Kada()
Sapun()
sl = Srean
s2 = Srean
s3 = Radostan
s4 = Radostan
i = 47
igracka = 3 . 1 4
sapuncic = Konstruisan
* ///:-
Sintaksa nasleivanja
N asleivanje je sastavni deo Jave (i u o p te o b jek tn o o rijen tisa n ih jezika). U stvari, kada
pravite klasu, ispostavlja se da uvek p rim en ju jete nasleivanje. A ko eksplicitno ne nasle-
dite neku klasu, im plicitno ete n aslediti favinu p o d ra z u m e v a n u ko ren sk u kiasu O b ject.
S intaksa kom pozicije je oigledna, ali se za n asleivanje up otreb ljav a p o seb n a sin tak -
sa. Pri nasleivanju kaete nova klasa ie kao ta sta ra klasa. U p ro g ra m u to navodite pre
p o etn e vitiaste zagrade tela klase, piui rezervisanu re e x te n d s iza koje sledi im e
osnovnc kluse. Kada to uinite, au to m atsk i p reu zim a te sva polja i m eto d e o sn o v n e klase.
Evo p rim era :
//: ponovnaupotreba/Deterdzent.java
// Sintaksa i osobine nasleivanja.
import static net.mindview.util.Print.*;
class Cistac (
private String s = "Cistac";
public void dodaj(String a) { s += a; }
public void razredi() { dodaj(" razredi()"); }
public void sipaj() { dodaj(" sipaj()"); }
public void ribaj() { dodaj(" ribaj()"); }
public String toStringO { return s; }
public static void main(String[] args) {
Cistac x = new Cistac();
184 Misliti na Javi
M e u tim , ako bi n ek a klasa iz nekog d ru g o g pak eta nasledila klasu Cistac, o n a b i m ogla
da p ristu p a sam o n je n im jav n im lanovim a. D akle, da biste om oguili nasleivanje klase,
opte p rav ilo je da sva polja b u d u p riv atn a, a sve m eto d e javne (izvedena klasa tak o e
m oe da p ristu p a zatienim lanovim a; o to m e neto kasnije). N aravno d a u o d re en im
sluajevim a m o ra te u in iti izvesna prilag o av an ja, ali ovo je k o risn a sm ernica.
Klasa Cistac im a g ru p u m eto d a u svom interfejsu: dodaj(), razredi(), sipaj(), ribaj()
i toString(). Poto je klasa Deterdzent izvedena iz klase Cistac (p o m o u rezervisane rei
extends), njen interfejs au to m atsk i sadri i navedene m eto d e, iako ne v id ite d a su o n e u
njoj izriito definisane. Z nai d a nasleivanje m o ete d a p o sm a tra te kao p o n o v n o kori-
enje klase.
Na p rim e ru m eto d e ribaj() v id i se d a je m og ue m en jati m e to d u koja je ve bila defi-
nisan a u o sn o vno j klasi. U ovom sluaju, iz n ove verzije je p ozv an a i m eto d a iz osno v n e
klase. M e u tim , u m e to d i ribaj() nije ispravno d a se pozove sam o m eto d a ribaj(), je r bi
to b io rek u rziv an poziv, a to niste n am eravali. D a b i reila ovaj p ro b lem , Javina rezervi-
sana re super oznaava natk lasu (engl. superclass) koju tek u a klasa nasleuje. Stoga n a-
redba super.ribajO poziva verziju m eto d e ribaj() iz o sn o v n e klase.
Pri n asleivanju ne m o ra te ko ristiti sam o m eto d e o sn o v n e klase. Izvedenoj klasi m o -
ete d a dod ajete nove m eto d e na isti nain na koji b iste to radili i s bilo k o jo m d ru g o m
klasom : definiite ih. P rim e r za to je m etod a za p e n i().
U m eto d i Deterdzent.main() v idite da preko objekta klase Deterzent m o ete da p o -
zivate m eto d e koje su raspoloive za klasu Cistac i o n e za klasu Deterdzent (na prim er,
zapeni()).
Veba 2: (2) Iz klase D e te rd z e n t nasledite novu klasu. Redefiniite m eto d u rib a j(), a d o -
dajte i n o v u m e to d u p o d im e n o m ste rilisi().
//: ponovnaupotreba/Karikatura.java
// Poziv konstruktora pri nasleivanju.
import s ta tic net.m indview .util.P r in t.* ;
186 Misliti na Javi
class UmetnickoDelo {
UmetnickoDelo() { print("Konstruktor klase UmetnickoDelo"); }
}
Konstruktori sa argumentima
U p re th o d n o m p rim e ru su k orieni p o d ra zu m e v a n i k o n stru k to ri; o d n o sn o , oni nisu
im ali nikakve arg u m e n te . P rev o d io cu je lako da ih poziva, je r nem a su m n je koje arg u -
m ente treb a p roslediti. A ko o sn o v n a klasa n em a p o d raz u m e v a n i k o n stru k to r ili ako elite
da pozovete k o n stru k to r o sn o v n e klase kom e su p o tre b n i a rg u m e n ti, m o rate izriito po-
zvati k o n stru k to r o sn o v n e klase koristei rezervisanu re s u p e r i proslediti m u odgova-
rajuu listu arg u m en ata:
//: ponovnaupotreba/Sah.java
// Nasleivanje, konstruktori i argumenti.
import s ta tic net.m indview.uti1 .P r in t .*;
Poglavlje 7: Ponovno korienje klasa 187
class Igra {
Ig ra (in t i) {
printC'Konstruktor klase Ig ra ");
}
}
Delegiranje
Java ne podrava d ire k tn o trei o d n o s koji se naziva delegiratije. To je neto na pola p u ta
izm eu nasleivanja i k om pozicije, p o to u klasu k o ju p ra v ite sm etate o b jek at lan (kao
kom pozicija), ali u novoj klasi isto v rem en o ek sp o n ira te sve m eto d e to g objekta lana
(kao nasleivanje). N a p rim er, svem irskom b ro d u treb a m o d u l za upravljanje:
//: ponovnaupotreba/UpravljakiUreajiSvemirskogBroda.java
//: ponovnaupotreba/SvemirskiBrod.java
N aravno, S v em irsk iB ro d u stvari n ije jed an od o bjekata klase U prav Ijak iU re ajiS -
ve m irsk o gB ro d a, ak i ako o bjektu klase S v em irsk iB ro d , p rim e ra radi, m oete narediti"
da ide n a p red (). Tanije je rei da S v em irsk iB ro d sadri U p rav Ijak iU re ajiS v em irsk o g -
B roda. Istovrem eno, u o b jek tu ldase S v em irsk iB ro d ek sp o n iran e su sve m eto d e objekta
klase U prav ljakiU red ajiS v em irsk o g B ro d a.
O vu n ed o u m icu reava delegiranje:
//: ponovnaupotreba/DelegiranjeSvemirskogBroda.java
upravljakiUreaji.nazad(brzina);
}
public void nanie(int brzina) {
upravljakiU reaji.nanie(brzina);
}
public void napred(int brzina) {
upravljakiUreaji.napred(brzina);
}
public void nalevo(int brzina) {
upravljakiU reaji.nalevo(brzina);
}
public void nadesno(int brzina) {
upravljakiUreaji.nadesno(brzina);
}
public void turboPotisak(int brzina) {
up ravljakiUreaji.turboPotisak(brzina);
}
public void navie(int brzina) {
upravljakiU reaji.navie(b rzina);
}
public s ta tic void m ain(String[] args) {
DelegiranjeSvemirskogBroda t i t =
new DelegiranjeSvemirskogBroda("PVO t i t " ) ;
tit.napred(lO O );
}
} III---
V idi se kako su m etode pro sle en e p rip a d n o m o b jek tu tip a u p ra v lja k iU re a ji, pa je
interfejs zato je d n a k kao pri nasleivanju. M e u tim , deleg iran je o m o g u u je vie k o n tro -
le, p oto u objekat lan m oete p ren eti proizvoljan p o d sk u p svih m etoda.
Iako Java ne podrava delegiranje, im a m n o g o razv o jn ih alatki koje ga p odravaju. Re-
cim o, gornji p rin ie r je au to m atsk i g enerisan p o m o u razvojnog o k ru en ja JetB rains Idea.
V eba 11: (3) Izm enite D e te rd z e n t.ja v a tako da se u njoj koristi delegiranje.
class Pribor {
Prib o r(in t i) {
print("Konstruktor klase P rib o r");
}
}
}
public s ta tic void main(String[] args) {
PostavkaStola x = new PostavkaStola(9);
}
} /* Isp is:
Konstruktor klase Obicaj
Konstruktor klase Pribor
Konstruktor klase Kasika
Konstruktor klase Pribor
Konstruktor klase Viljuska
Konstruktor klase Pribor
Konstruktor klase Noz
Konstruktor klase Tanjir
Konstruktor klase TanjirZaVeceru
Konstruktor klase PostavkaStola
* ///:-
Iako vas prevodilac prisiljava da inicijalizujete osn ov ne klase i zahteva da to u in ite od-
m ah n a p o etk u k o n stru k to ra , o n ne vodi ra u n a o to m e d a li ste inicijalizovali objekte
lanove, pa m o rate sam i o to m e voditi rau na.
P rilino je zadivljujue kako su klase jasn o razdvojene. N ije vam ak p o tre b a n ni iz-
vorni k od m eto da da biste ih p o n o v o koristili. U veini sluajeva treb a sam o d a uvezete
paket. (O vo vai i za nasleivanje i za ko m poziciju.)
//: ponovnaupotreba/CADSistem.java
// Obezbeivanje pravilnog ienja
package ponovnaupotreba;
import s ta tic net.mindview.uti1. P rin t.*;
cl ass Obli k {
O blik( i nt i) { print("Konstruktor klase O b lik "); }
void ciscenje() { print(" ienje klase O b lik "); }
}
192 Misliti na Javi
U ovom sistem u sve je neka v rsta Oblika (koji je i sam tip a Object, jer im p licitn o na-
sleuje k orensku klasu). Svaka klasa redefinie m e to d u ciscenje() klase Oblik i p o red
ostalog, poziva i verziju te m etod e iz osn o v n e klase p o m o u rezervisane rei super. Poje-
dine vrste klase Oblik - Krug, Trougao i Linija - im aju svoje k o n stru k to re koji crtaju",
p rem d a bilo koja m e to d a to k o m ivotnog veka objekta m oe da u rad i neto to zahteva
ienje. Svaka klasa im a svoju m e to d u ciscenje() koja vraa stvari bez ikakve veze s m e-
m o rijo m , u stanje u kom e su bile pre nego to je objekat napravljen.
194 Misliti na Javi
U m eto d i main() m o ete d a p rim e tite dve n o ve rezervisane rei koje nee biti d etaljn o
o b janjene sve d o poglavlja O brada greaka pom ou izuzetaka, a to su try i finally. Rezer-
visana re try naznaava da je b lo k koji sledi (u n u ta r v itiastih zagrada) zatieni region,
to znai d a im a p o seb an tre tm a n . Jedan d eo to g p o se b n o g tre tm a n a o d n o si se n a k o d
u n u ta r b lo k a finally koja sledi iza to g zatienog regiona. Taj k o d se uvek izvrava, bez o b-
zira na to kako se iz b loka try izlazi. (P ri o b ra d i izuzetaka, b lo k try m oe se n ap u stiti na
vie n eu o bia jen ih naina.) U o vo m sluaju, b lo k finally kae: ,,Za x uvek pozovi m e to d u
ciscenje(), bez o b zira n a to ta se d o g a a.
U koliko jed an p o d o b je k a t zavisi o d d ru g o g , zap am tite da u svojoj m e to d i za ienje
(u ovom sluaju, m e to d i ciscenje()) tak o e m o rate da v odite ra u n a o p o retk u ienja
osnov n e klase i o b jekata lanova. Po prav ilu , treb a da p ra tite p rin c ip koji je uveo prevo-
dilac jezika C + + za svoje d estru k to re: prv o o b av ite sve ienje k oje je specifino za vau
klasu, i to red osled o m koji je o b rn u t o d redo sled a pravljenja. (U o p tem sluaju, za to je
p o tre b n o d a elem en ti o sn o v n e kiase i dalje b u d u u ivotu.) Z atim pozovite m e to d u za i-
enje o sno v n e klase, kao to je u n aem p rim e ru p o k azan o .
U m n o g im sluajevim a ienje nije p ro b le m i m o ete d a p u stite sakupljaa sm ea da
obavi posao. Ali, kada je izriito ienje p o tre b n o , n je m u m o ra te da p ristu p ite m arljivo
i paljivo, p o to n a sak u p ljan je sm ea ne m oete previe d a se oslo n ite. Sakupljanje sm ea
u o pte n e m o ra da se d o go d i, a ako se d o g o d i, m oe d a isti objekte bilo kojiin redosle-
d o m . N ajbolje je n e oslan jati se na sakuplja sm ea ni za ta o sim za o slobaanje m em o -
rije. Ako v am je ienje p o tre b n o , n a p rav ite svoje m eto d e za njega i ne oslanjajte se na
m eto d u finalize().
V eba 12: (3) D odajte o d g o v araju u h ijerarh iju m eto d a ciscen je() svim klasam a iz ve-
ban ja 9.
Sakrivanje imena
Ako je u osnovnoj klasi u Javi defin isano im e m eto d e koje je kasnije nekoliko p u ta pre-
klopljeno, redefinisanje tog im en a m eto d e u izvedenoj klnsi //ect sakriti n ijed n u verziju iz
o sn o v n e klase (za razliku o d C + + -a ). Stoga prek lap an je fu n k cio n ie bez obzira na to da li
je m eto d a definisana na to m nivou ili u o sn o v n o j klasi:
/ / : ponovnaupotreba/Sakrivanje.java
// Preklapanje imena metode osnovne klase u izvedenoj klasi
// ne sakriva v erz ije iz osnovne klase.
import s ta tic net.mindview.u t i1. Print
class Homer (
char doh(char c) {
p rin t("d o h (ch a r)");
return 'd ';
}
flo a t doh(float f) {
p rin t("d o h (flo a t)" ) ;
return l.O f;
}
Poglavlje 7: Ponovno korienje klasa 195
class Milhaus {}
Viciite da su sve preklopljene m eto d e klase Homer d o stu p n e u klasi Bart, iako Bart uvo-
di novu p reklopljenu m e to d u (tim e bi se u C + + - U sakrile m etode osnovne klase). Kao to
ete p roitati u n ared n o m poglavlju, m eto de istog im ena se m n o g o ee redefiniu p o m o -
u p o tp u n o istog potp isa i p o v ratn o g tipa kao i u osnovnoj klasi. Inae rezultati m o g u biti
zbun juju i (zbog ega to u C++-U i nije dozvoljeno, da ne biste napravili greku).
U Javi SE5 d o d a ta je an o tacija @Override, to nije rezervisana re, ali se m oe u p o -
trebljavati kao da jeste. Kada hoete da redefiniete m eto d u , m oete d o d ati tu an o tac iju i
prevodilac e prijaviti greku ukoliko je n e n a m e rn o preklo p ite um esto da je redefiniete:
//: ponovnaupotreba/Lisa.java
// {Compi1eTimeError} (Nee se prevesti)
V eba 13: (2) N ap rav ite klasu s m e to d o m k oja je prek lo p lje n a trip u t. N eka je nasledi n ova
klasa, dodajte jo je d n o p rek lap an je m eto d e i pok aite d a su sve etiri m eto d e d o stu p n e u
izvedenoj klasi.
//: ponovnaupotreba/Kola.java
// Kompozicija pomou javnih objekata.
class Motor {
public void s t a r t() {}
public void rik v e rc () {}
public void stop() {}
}
class Tocak {
public void naduvaj(int psi) {}
}
class Prozor {
public void podigni() {}
public void spusti () {}
}
class Vrata {
public Prozor prozor = new Prozor();
public void o tv o ri() {}
public void z a tvo ri() {}
}
public Kola() {
fo r (in t i = 0; i < 4; i++)
to ck o v i[i] = new Tocak();
)
public s ta tic void m ain(String[] args) {
Kola kola = new K o la ();
kola.leva.prozor.podigni( ) ;
kola.tockovi [ 0 ].naduvaj (72);
}
} ///= -
Poto je k o m p o z i ja kola u ovom sluaju deo analize p ro b le m a (a n e sam o d eo osnov-
no g p ro jek ta), proglaavan jem lanova jav n im p o m ae te p ro g ra m e ru klijen tu d a shvati
kako d a k oristi klasu, a tim e se i sm an ju je slo en o st k o d a koji a u to r klase m o ra d a napie.
Im ajte n a u m u da je ovo specijalan sluaj i d a polja u g lav n o m treb a da b u d u p riv atn a.
Pri nasleivanju polazite o d postojee klase i p rav ite n je n u specijalnu verziju. U
o ptem sluaju, to znai d a uzim ate klasu o p te n a m e n e i specijalizujete je za o d re e n e
potrebe. A ko m alo razm islite, uvideete k ako n em a sm isla d a klasu a u to p rav ite k o m p o -
zicijom o d klase v o zilo - a u to n e sadri vozilo, o n jeste vozilo. Relacija jesteizraav a se na-
sleivanjem a relacija sadri izraava se k o m p o zicijo m .
V eba 14: (1) U datoteci K ola.java klasi M o to r d o d ajte m e to d u serv is() i pozo v ite je iz
m eto de m a in ().
Rezervisana re protected
Poto ste savladali nasleivanje, rezervisana re p ro te c te d n ap o k o n d o b ija znaenje.
U id ealn om svetu, p riv a tn i lanovi bi uvek bili p o tp u n o p riv atn i, ali u stv arn im projek-
tim a nekad ho ete da neto sakrijete o d ire jav n o sti, a da ipak izvedenim klasam a dozvo-
lite p ristu p .
Rezervisana re p ro te c te d d o p rin o si p ra g m atizm u . O n a kae: O vo je p riv a tn o to se
tie korisnika klase, ali je d o stu p n o svakom ko ovu klasu nasledi ili bilo kom d ru g o m u
istom p ak etu . O d n o sn o , u Javi zatieno (engl. protectcd) au to m a tsk i p o d ra z u m ev a i pa-
ketni p ristu p .
lako m o ete prav iti zatiena polja, najbolje je d a p o lja b u d u p riv atn a - u v e k tre b a da
zad rite pravo da m en jate o sn o v n u realizaciju. Tada p o m o u zatienih m eto d a m oete
da dozvolite k o n tro lisan p ristu p n asled n icim a vae klase:
//: ponovnaupotreba/Ork.java
// Rezervisana re protected.
import s ta tic net.mindview.uti1. P r in t.*;
class Nitkov {
private String ime;
protected void postavi(String im) { ime = im; }
public N itkov(String ime) { this.ime = ime; }
public String toStringO {
198 Misliti na Javi
Svoenje navie
N ajbitniji vid nasleivanja nije o b ezbeivanje m eto d a n ovim klasam a. N asledivanje
predstavlja relaciju izm ed u nove i osn o v n e klase. Relacija m oe da se sam e kao nova
klasa je tipa postojee klase.
P reth o d n i opis nije izm iljen sam o da bi se objasnilo nasledivanje - jezik ga d irek tn o
podrava. Na p rim er, p o sm atrajte o sn o v n u klasu p o d im en o m Instrument, i izvedenu
klasu po d im en o m Duvacki. Poto nasleivanje podra/.um eva da su sve m etode osnovne
klase d o stu p n e i u izvedenoj klasi, svaku p o ru k u koju m oete da poaljete osnovnoj klasi,
m oete da poaljete i izveenoj klasi. Ako klasa Instrument im a m eto d u sviraj(), im ae je
i Duvacki in stru m en ti. To znai da, bez greke, m oem o rei kako je objek at tipa Duvacki
takoe i tip a Instrument. N aredni p rim e r pokazuje kako prevodilac p odrava tu notaciju:
Poglav[je 7: Ponovno korienje klasa 199
//: ponovnaupotreba/Duvacki.java
// Nasleivanje i svoenje navie.
class Instrument {
public voi s v ir a j() {}
s ta tic void melodija(Instrument i) {
/ /
i .s v ira j ( ) ;
}
}
Rezervisana re final
Z naen je Javine rezervisane rei finai im a nekoliko nijansi, u zavisnosti od ko n tek sta u
kom je u p o treb ljen a, ali o p te je: Ovo ne m oe da se m enja. M oete poeleti da p ro m en e
spreite zbog p ro jek ta ili efikasnosti. Poto su ti p rin cip i sasvirn razliiti, rezervisana re
final m oe se i p o g ren o u p o tre b iti.
U n a re d n o m o deljku razm atraju se tri sluaja u kojim a m oe da se u p o treb i rezervi-
sana re final: za p o d atk e, m e to d e i klase.
Finalni podaci
M nogi p ro g ram sk i jezici im a ju n ain da p revodiocu naznae kako je neki p o d a ta k ,,kon-
sta n ta n . K onstante su k o risn e iz dva razloga:
1. M ogu da zad aju k onstantne vrednosti p ri prevoenju koje se nikada nee p ro m en iti.
2. M ogu da predstavljaju v red n o sti koje inicijalizujem o to k o m izvravanja, a ne eli-
m o da b u d u m enjane.
Poglavlje 7: Ponovno korienje klasa 201
// : ponovnaupotreba/Finalni Podaci.java
// Efekat rezervisane rei fin al na polja.
import s ta tic ja v a .u til
import s ta tic net.mindview.util .P r in t.* ;
class Vrednost {
in t i ; // Paketni pristup
public Vrednost(int i) { th is .i = i }
1
public class FinalniPodaci {
private s ta tic Random slucajan = new Random(47);
private String id;
public F inalniPodaci(String id) { th is .id = id }
// Mogu da budu konstante pri prevoenju
private fin al int vrednostJedan = 9;
private s ta tic fin al in t VREDNOST_DVA = 99;
// Tipina javna konstanta:
public s ta tic final in t VREDNOST_TRI = 39;
// Ne mogu da budu konstante pri prevoenju:
private fin al int i4 = slucajan.nextlnt(20);
s ta tic fin al in t INT_5 = slucajan.nextlnt(20);
private Vrednost vl = new Vrednost(11);
private fin al Vrednost v2 = new Vrednost(22);
private s ta tic fin al Vrednost VRE_3 = new Vrednost(33);
// N izovi:
private fin al in t [] a = { 1, 2, 3, 4, 5, 6 };
public String toStringO {
202 Misliti na Javi
reference. (Koliko ja znam , ne postoji nain da sam e reference u nizu proglasite finalnim .)
Proglaavanje referenci finalnim ini se m anje korisnim o d proglaavanja prom enljivih
prostog tipa finalnim.
V eba 18: (2) N apravite klasu koja im a statin o finalno polje i finalno polje i p okaite raz-
like izm e u njih.
// : ponovnaupotreba/PraznoFinalno.java
// "Prazna" finalna polja.
class Poppet {
private int i ;
Poppet(int i i ) { i = i i ; }
1
public class PraznoFinalno {
private final int i = 0; // Inicijalizovana finalna promenljiva
private final int j ; // prazna finalna promenljiva
private final Poppet p; // prazna finalna referenca
// Prazna finalna polja MORAJU da budu in ic i j a l izovana u konstruktoru:
public PraznoFinalno () {
j = 1; // In ic ij a l izovanje praznog finalnog polja
p = new Poppet(l); // I n i c i j a l izovanje prazne finalne reference
}
public PraznoFinalno (in t x) {
j = x; // In icija liz o v a n je praznog finalnog polja
p = new Poppet(x); // In ic ijalizovanje prazne finalne reference
}
public sta tic void main(String[] args) {
new PraznoFinalno ( ) ;
new PraznoFinalno (47);
}
} III--
Finalnim poljim a m o rate da dodeiite v rednosti p o m o u izraza na m estu definicije ili
u svakom k o n stru k to ru . Na taj nain se g aran tu je da su finalna polja uvek in ijalizov ana
pre upotrebe.
Veba 19: (2) N apravite klasu s p razn o m finalnom referencom na objekat. U n u tar svih
k o n stru k to ra inicijalizujte prazan finalni elem ent. D okaite da finalni elem ent m o ra biti
inicijalizovan pre u p otreb e i da nakon toga vie ne m oe da se m enja.
204 Misliti na Javi
Finalni argumenti
A rgum ente m oete da pro g lasite fin aln im tak o to ih deklariete k ao finalne u listi argu-
m enata. To znai da u n u ta r m e to d e n e m oete m en jati o n o na ta taj a rg u m en t kao refe-
renca ukazuje:
//: ponovnaupotreba/FinalniArgumenti.java
// Upotreba rezervisane rei " fin a l" uz argumente metode.
class Stvar {
public void z a v r ti() {}
}
M etode f() i g() pokazuju ta se deava kada su arg um enti prostog tipa finalni: argum ent
m oete itati, ali ga ne m oete pro m en iti. To se koristi prvenstveno za prosleivanje poda-
taka an o n im n im u n u tran jim klasam a koje ete u poznati u poglavlju Unutranje klase.
Finalne metode
Za u p o tre b u finalnih m eto d a posto je dva razloga. Prvi je da se m eto da ,,zakljua kako bi
se spreilo da bilo koja klasa naslednica p ro m en i n jeno znaenje. To se radi zbog projekt-
n ih razloga, kada elim o da b u d e m o sigurni kako e p on aan je m etod e biti neprom enje-
n o p rilikom nasleivanja, o d n o sn o kako m eto d a ne m oe biti redefinisana.
Ranije se kao dru g i razlog za korienje finalnih m eto da navodila efikasnost. U pre-
th o d n im realizacijam a Jave, kada biste m eto d u proglasili finalnom , dozvoljavali ste pre-
vodiocu da sve pozive toj m eto d i u gradi d irek tn o u kod (engl. inline call). Kada bi
prevodilac naiao na poziv finalnoj m etod i, m ogao je (p o svom n a h o e n ju ) da preskoi
uobiajen poziv (stavi arg u m en te na stek, skoi na kod m eto de i izvri ga, vrati se, poisti
arg u m en te sa steka i razm o tri p o v ra tn u v red n o st). U m esto toga, poziv m etode m ogao je
da se zam eni k opijom stv arn o g k oda iz njenog tela. T im e su se elim inisali reijski trokovi
sam og poziva. N aravno, ako je m etod a velika, kod poinje da se poveava i verovatno ne
Poglavlje 7: Ponovno koridenje klasa 205
biste d o b iti poboljanje p erfo rm an si, jer b i sva u n ap re en ja bila zanem ariva u o d n o su na
vrem e izvravanja m etode.
U novijim verzijam a Jave, v irtu e ln a m ain a (ko n k retn o , tehnologije v ru ih taaka)
m oe da prep ozna takve situacije i p a m e tn o o d ab ere da li d a k oristi u m etan je k oda na
m estu poziva za finalnu m eto d u , p a vie ne treb a da p o m aete o p tim iz ato ru tako to ete
koristiti rezervisanu re fin al (p o p ravilu, to ne b i treb alo da rad ite). U Javi SE5/6, pustite
da se prevodilac i izvrno o k ru en je (JVM ) staraju o efikasnosti, a m e to d u proglasite fi-
n aln o m sam o ako elite izriito da spreite n jen o redefinisanje.1
Finalno i privatno
Svaka p rivatna m etod a u klasi im p licitn o je i finalna. Poto priv atn o j m eto d i ne m oete
da pristu p ite iz nasleenih klasa, ne m oete n i da je redefiniete. P rivatnoj m eto d i m oete
da dodelite specifikator final, ali njoj to ne daje nikakvo d o d a tn o znaenje.
O vo stanje m oe da izazove zab u n u - ako pokuate da redefiniete p riv atn u m eto d u (ko-
ja je im plicitno finalna), to ete sam o naizgled uspeti, jer prevodilac nee prijaviti greku:
//: ponovnaupotreba/IluzijaRedefinisanjaFinalnih.java
// Privatnu i l i privatnu finalnu metodu samo naizgled moete da redefiniete.
import static net.mindview.uti1. P r in t.*;
class SadrziFinalne {
// Identino kao i kada sto ji samo "priva te":
private final void f ( ) { p rin t("S a d rz iF in a ln e .f( ) " ) ; }
// Takoe automatski finalna:
private void g() { p rin t("S a d rz iF in a ln e .g ()" ) ; }
Finalne klase
Kada ozn aite da je cela klasa finalna (stavljajui rezervisanu re final pre njene definici-
je), saoptav ate da tu klasu ne elite da nasle u jete niti dozvoljavate bilo kom e da to uini.
D ru g im reim a, iz nekog razloga p ro jekat vae klase nikad se nee m enjati ili iz bezbed-
n o sn ih razloga ne elite da o m o g u ite nasledivanje.
//: ponovnaupotreba/Preistorijski.java
// Proglaavanje cele klase finalnom.
class MaliMozak {}
Paljivo sa final
Kada p ro jek tu jete klasu, m oe vam se uiniti lcao d o b ra ieja da m e to d u proglasite final-
n o m . M oda p om islite da ionako n em a anse da iko ikada reefinie vae m etode. Pone-
kad je to zaista tako.
Ipak, paljivo razm islite. U glavnom je teko pred v id eti kako e se klasa p o n o v o kori-
stiti, n aro ito klase opte naraene. Ako m eto d u proglasite fin aln o m , spreiete da vau
klasu p u te m nasleivanja u p o treb i neki d ru g i p ro g ram er, i to sam o zato to niste m ogli
zam isliti d a se o n a m oe koristiti na taj nain.
S ta n d a rd n a Javina biblioteka je d o b a r p rim er. N aroito klasa V ector iz Jave 1.0/1.1
koja se esto koristi i koja je m ogla da b u d e jo korisnija da nisu, u im e efikasnosti (to je
gotovo sig u rn o bila zabluda) sve m etode proglaene finalnim . Lako je p retp o stav iti kako
elite da nasledite i redefiniete tako fu n d am en taln o k o risn u klasu, ali su p ro je k tan ti ne-
kako odluili d a to nije u redu. Iro n in o - iz dva razloga. Prvo, klasa S tack je nasledena iz
klase V ector, to govori da Stack icstc V ector, m ada to i nije ba tano s logike take gle-
dita. U prkos to m e, sam i pro jek tan ti Jave izveli su tu klasu iz klasc V ector. im su n a taj
nain napravili Stack, treb alo je da shvate kako su finalne m eto d e previe ograniene.
D rugo, m noge najvanije m etode klase Vector, kao to su ad d E Ie m e n t() i eIem en tA t(),
sin h ro n izo v an e su (rezervisana re sy n ch ro n ized ). Kao to ete videti u poglavlju Paralel-
no izvravanje, to p rav i znaajne reijske trokove koji verovatno ponitavaju svu korist o d
toga to su inetode finalne. O va pria p o tv r u je teo riju da p ro g ram eri loe p ogaaju m esta
na kojim a treb a o p tim izovati. Zaista je loe to je tako nesp retan projekat uao u sta n d ard -
nu bib lio teku pa svi m orarn o da se b o rim o s njim . (Na sreu, kontejnerska biblioteka
208 Misliti na Javi
savrem ene Jave zam enjuje ldasu Vector klasom ArrayList, koja se po n aa m n o g o p rim ere-
nije. N aalost, i dalje do sta n o v ih p ro g ra m a k oriste sta ru k o n tejn ersk u bib lio tek u .)
V ano je n a p o m e n u ti d a klasa Hashtable, jo je d n a v an a klasa iz sta n d a rd n e bib lio -
teke Jave 1.0/1.1, tiema n ije d n u fin aln u m e to d u . Kao to je ve reen o n a d ru g im m estim a
u ovoj knjizi, prilin o je o igledno d a su neke klase p ro jek to v ali sasvim razliiti Ijudi. (Vi-
deete i da su im ena m eto d a u klasi Hashtable m n o g o k raa o d im en a u klasi Vector, to
je jo je d a n dokaz.) Ba to k o risn icim a b ib lio teke klasa ne bi treb alo d a b u d e oigledno.
Kada stvari nisu dosledne, k o risn ik sam o im a vie posla. To go v o ri d a p ro jek a t i k o d treb a
pregledati vie p u ta. (U k o n tejn ersk o j b ib lio teci sav rem en e Jave, klasa Hashtable je zam e-
n jen a klasom Hashmap.)
Inicijalizacija i nasleivanje
Da bism o dobili celovitu sliku o svem u ovom e, p o g le d a jm o ceo proces inicijalizacije
ukljuujui i nasleivanje. R azm o trite n are d n i p ro g ram :
//: ponovnaupotreba/Buba.java
// Potpuni proces in ic ija liz a c ije .
import s ta tic net.m indview .util.P r in t.* ;
class Insekt {
int i = 9;
i nt j ;
Insekt() {
' I k o n stru k to r je statina m etoda, m ada se rezervisana re s ta tic ne m ora eksplicitno navesti. Dakle,
preciznije je rei da se klasa uitava o n d a kada se pristupi biio kojem njen o m statinom lanu.
Poglavlje 7: Ponovno korienje klasa 209
p r in t("i = + i + , j = " + j ) ;
j = 39;
}
private s ta tic in t xl =
p r in t ln it ( in ic ijaliz o v a n a statina promenljiva In s e c t.x l ) ;
s ta tic in t p rin tIn it(S trin g s) (
p r in t (s );
return 47;
}
}
poziv se obavlja au to m atsk i, ali tak o e m o ete d a o d red ite koji k o n s tru k to r o sn o v n e klase
treb a da b u d e pozvan (prva o p eracija u k o n stru k to ru klase Buba) p o m o u rezervisane
rei super. K o n stru k to r osn o v n e klase p ro lazi k roz isti p ro ces i istim red o sled o m kao
k o n stru k to r izvedene klase. N akon obavljene k o n stru k cije o sn o v n e klase, pro m en ljiv e in -
stance inicijalizuju se p o p o retk u pisanja. K onano, izvrava se o statak tela k o n stru k to ra .
Veba 23: (2) D okaite da se klasa uitava sam o je d n o m . D o k aite d a uitavanje m oe da
b u d e p ro u zro k o v an o bilo p ravljenjem prve in stan ce te klase bilo p ris tu p o m statin o m
lanu.
Veba 24: (2) U dato teci Buba.java, iz klase Buba n asledite specifinu v rstu b u b e, drei
se istog fo rm ata kao kod postojeih klasa. P ratite i objasn ite rezu ltat p ro g ra m a .
Saetak
I nasleivanje i kom pozicija o m o g u av a ju da o d po sto jeih tip o v a n a p ra v ite nove. K om -
pozicija upotrebljav a postojei tip kao d eo o sn o v n e realizacije n o v o g tip a, a nasleivanje
pon o v o u potrebljava interfejs.
U nasleivanju, izvedena klasa o b u h v a ta interfejs o sn o v n e klase, p a m oe da b u d e sve-
dena navic ka osnovi, to je veom a b itn o za p o lim o rfizam (kao to ete videti u n ared -
n o m poglavlju).
U prkos veom a n aglaenom n asledivanju u o b jek tn o o rije n tisa n o m p ro g ra m ira n ju , u
p rvo m p ro lazu kroz p ro jek at treb alo b i d a se k o n cen trie te na k o m p o ziciju (ili na delegi-
ranje), a nasleivanje koristite sam o kada je n eo p h o d n o . K om pozicija u m e da b u d e flek-
sibilnija; Iukavo p rim en ju ju i nasleivanje na objekte lanove, m o ete im p ro m en iti
taan tip, a sam im tim i p o n aan je to k o m izvravanja. D ru g im reim a, p o n aan je objekta
nastalog p o m o u kom pozicije m o ete da m en ja te to k o m izvravanja.
Kada projektujete sistem , va cilj je d a p ro n a e te ili n ap rav ite sk u p klasa u k om e svaka
klasa im a specifinu n a m en u . Uz to, n ijed n a klasa ne treb a da b u d e ni prevelika (s toliko
m o guno sti da postaje n ezg rap n a da bi se p o n o v o koristila) ni p rem ala (toliko da ni vi ne
m oete da je koristite takvu kakva je ve je m o rate p ro iriti). U koliko p ro jek at p o stan e
previe sloen, esto p o m ae kada d o d a te nove objekte nastale cep an jem p ostojeih na
m anje delove.
Kada ponete da p ro jek tu jete sistem , vano je da shvatite kako je razvoj p ro g ram a p o -
stu p an proces, ba kao i ovekovo uenje. N jegova osnova je ek sp erim e n tisan je; m oete
b eskrajno dug o da an alizirate stvari, ali i dalje neete znati sve o d g o v o re kada se u p u stite
u projekat. Im aete m n o g o vie u sp eh a - i vie n ep o sred n ih p o d ata k a o rezu ltatim a - ako
,,uzgajate svoj projekat kao organsko bie koje se razvija, u m esto da ga o d je d n o m pravite
kao stakleni soliter. N asleivanje i k o m pozicija sp ad aju m e u najvanije alatke u objekt-
no o rijen tisan o m p ro g ra m ira n ju koje om o g u av aju takvo ek sp erim e n tisan je.
R eenja o d a b ra n ih vebi d a ta su u e le k tro n sk o m d o k u m e n tu Thinking in Jnva Annotated Solutiini
Guide, koji se m o e k u p iti n a VVeb lokaciji www.MindView.net.
Polimorfizam
Pitali su tne: M o lim vas, gospodine Bebide, recite hoe li iz vae m aine izai tani odgovori
ak i ako u nju unesetepogrene brojeve?N e m ogu da p o jm im k a kva je zbrka u glavam a Ijudi
koji p ita ju tako ta. arls Bebid (1791-1871)
//: polimorfizam/muzika/Nota.java
// Note koje e se s v ira ti na tnuzikim instrumentima.
package polimorfizam.muzika
//: polimorfizam/muzika/Instrument.java
package polimorfizam.muzika
import s ta tic net.m indview .util.P r in t.* ;
class Instrument {
public void sviraj(N ota n) {
print(''Instrum ent.sviraj ( ) " ) ;
}
}
III--
//: polimorfizam/muzika/Instrument.java
package polimorfizam.muzika
//: polimorfizam/muzika/Muzika2.java
// Preklapanje umesto svoenja navie
package polimorfizam.muzika
import s ta tic net.mindview.util .P r in t.* ;
Ovaj p ristu p dovodi d o eljenih rezu ltata, ali u z veliku m an u : za svaki novi Instru-
ment koji dodate, m o ra te d a n ap iete p o se b n u m eto d u . To n a sa m o m p o etk u zahteva
vie p ro g ram iran ja, ali tak o e znai da ete im ati i p u n o posla ako elite d a d o d a te n o v u
m e to d u slinu m eto d i m elodija() ili n o v u p o tk lasu klase Instrument. D o d ajte to m e
injenicu d a prevodilac nee p rijav iti p o ru k u o greci ako zab o rav ite da p rek lo p ite n eku
m e to d u , p a ceo proces ra d a s tip o v im a p o staje v eo m a nep o d esan .
Z ar n e bi bilo m n o g o lepe ako b iste m o g li d a napiete sam o je d n u m e to d u , iji b i ar-
g u m en t bila osn ov n a klasa, a ne neka p o seb n o izvedena klasa? O d n o sn o , zar ne bi bilo
fino ako biste m ogli z an em ariti in jen icu d a su to izvedene klase i m ogli da napiete p ro -
g ram tak o d a se ob raa sam o o sn o v n o j klasi?
P olim orfizam v am om oguava ba to. M e u tim , veina p ro g ra m e ra sa iskustvom u
p ro c e d u ra ln o m p ro g ra m ira n ju m a lo tee ra z u m e n ain n a koji p o lim o rfizam deluje.
Veba 1: (2) N apravite klasu Cikl s p o tk lasam a Unicikl, Bicikl i Tricikl. Pokaite da se
p rim e ra k svakog o d tih tipova m e to d o m v o z iti( ) m oe svesti navie na Cikl.
Zakoljica
P roblem s p ro g ram o m Muzika.java m oe d a se u oi n ak o n p o k retan ja p ro g ram a. Rezul-
tat e b iti poziv m eto d e Duvacki.sviraj(). D o b ijen je eljeni rezultat, ali ne izgleda logi-
n o zato to tak o radi. P o sm atrajte m e to d u melodija():
Svoenje navie
kroz dijagram
nasleivanja
K v a d ra t Trougao
o .n a crta j( ) ;
M ogli biste, ponovo, oekivati kako e b iti p o zv an a m eto d a nacrtajO klase Oblik, p o -
to je to ipak referenca n a Oblik - kako bi, o n d a, prev o d ilac m o g ao bilo ta d ru g o da u ra -
di? A ipak, zbog kasnog povezivanja (p o lim o rfizm a) poziv a se o d g o v araju a m e to d a
Krug.nacrtajO.
N ared n i p rim e r p o kazuje taj p rin c ip n a neto d rugaiji nain . N ajpre em o n ap rav iti
v iek ratn o u p otreb ljiv u b ib lio tek u tipo va Oblika:
//: polimorfizam/oblik/Oblik.java
package polimorfizam.oblik;
// : polimorfizam/obli k/Kvadrat.java
package polimorfizam.oblik;
import s ta tic net,mindview.uti1. P rin t.* ;
Prosirivost
V ratim o se sada p rim e ru s m u zik im in stru m e n tim a . P olim orfizam o m o g u u je da to m
sistem u d o d ate koliko god elite novih in s tru m en ata, bez p o treb e d a m en jate m eto d u
m eIo d ija (). U d o b ro p ro jek to v an o m O O P p ro g ram u , veina m eto d a ili sve nae m eto d e
p ratile bi m o d el p rim e n jen na m e to d u m eIo d ija() i k o m u n ik aciju obavljale sam o preko
interfejsa o sno v n e klase. Takav p ro g ram je proiriv; jer m oete da m u d o d ate novu fu nk-
c io n aln o st ako nove tipove p o d atak a nasledite iz zajednike o sn o v n e klase. M etode koje
obavljaju neki p osao preko interfejsa o sn o v n e klase, u o p te ne treb a da m en jate da bi pri-
hvatile i nove klase.
R azm o trite ta se deava ako u p rim e ru sa in stru m e n tim a d o d a m o nove m eto d e u
o sn o v n u klasu, kao i izvestan broj n o v ih klasa. D ijagram hijerarh ije nasleivanja d a t je na
slici:
Poglavlje 8: Polimorfizam 219
Sve ove nove klase p rav iln o rade sa starom i n e izm en jen o m m e to d o m m elo d ija (). ak
i ako se m eto d a m e lo d ija () nalazi u posebnoj d a to te i ako se interfejsu klase In s tru m e n t
d o d a ju n o \re m etode, m e lo d ija () e, bez po no v n o g prev o en ja, p rav iln o raditi. Evo i re-
alizacije dijagram a:
//: polimorfizam/muzika3/Muzika3.java
// Pro iriv program
package polimorfizam.muzika3;
import polimorfizam.muzika.Nota;
import s ta tic net,mindview.uti1 .P rin t.*;
class Instrument {
void sviraj(N ota n) { p rin t("In stru m en t.sviraj() " + n ); }
String sta () { return "Instrument"; }
void nastimuj() { p r in t( timovanje instrumenta"); }
}
N ove su m e to d a sta(), koja v ra a referen cu n a ob jek at klase String u kojem je o pis kla-
se, i m e to d a nastimuj() koja o m o g u av a da se svaki in s tru m e n t n a neki nain natim uje.
Svaki p u t k ada neto u b acite u niz orkestar u m eto d i m ain(), a u to m atsk i obavljate
svoenje navie ka klasi Instrument.
M eto da meIodija() je p o tp u n o im u n a na sve izm ene u p ro g ra m u i rad i p ravilno. Po-
lim o rfizam ba to om oguava. Izm en e u k o d u n e rem ete delove p ro g ra m a n a koje i ne bi
tre b alo da utiu. D ru g im reim a, p o lim o rfiza m je vana te h n ik a koja p ro g ra m e ru o m o -
guava da razdvoji o n o to se m e n ja o d o n o g to ostaje isto.
Veba 6: (1 ) P ro m e n ite d a to tek u Muzika3.java tak o d a m e to d a sta() p o stan e m e to d a to-
StringO iz korenske klase Object. P ro b ajte d a objekte klase Instrument ispisujete p o m o -
u m eto d e System.out.println() (bez ikakve konverzije).
Veba 7: (2) U d a to te k u Muzika3.java d o d ajte n o v u p o tk lasu klase Instrument i uverite
se da p o lim o rfizam rad i i za n o v i tip.
Veba 8: (2) Izm enite d a to te k u Muzika3.java tako da objekte klase Instrument p rav i na
sluajan nain kao u dato teci Oblici.java.
Veba 9: (3) N apravite h ijerarh iju nasleivanja klase Glodar: Mis, Pacov, Hrcak itd.
U o sn o v n o j klasi obezb ed ite m e to d e koje su zajednike za sve glodare i redefiniite ih u iz-
vedenim klasam a, tako da se razliito p o n aaju za razne tipove glodara. N apravite niz
objek ata klase Glodar, p o p u n ite ga razn im o b jek tim a p otklasa klase Glodar, pozovite
m eto d e definisane u o sn o v n o j klasi i v idite ta se dogaa.
Veba 10: (3) N apravite o sn o v n u klasu s dve m etode. Pozovite d ru g u m eto d u iz prve m e-
tode. N asledite tu klasu i redefiniite d ru g u m eto d u . N apravite objekat izvedene klase, sve-
dite ga navie d o njegovog pro sto g tip a i pozovite prv u m etod u. O bjasnite ta se deava.
//: polimorfizam/PristupPolju.java
// Neposredno pristupanje polju biva razreeno u trenutku prevoenja.
class Nad {
public int polje = 0;
public int p rib aviPolje () { return po lje; }
( /* Is p is :
nad.polje = 0, nad.pribaviPolje() = 1
pod.polje = 1, po d.pribaviPolje() = 1, pod.pribaviNadPolje = 0
* / / / :-
Kada se Pod objekat svede navie na Nad referencu, sva p ristu p an ja po ljim a razreava
prevodilac, p a o na zato nisu polim o rfn a. U ovom p rim eru , Nad.polje i Pod.polje ne do b i-
jaju isti m em orijski prostor. Z ato Pod zapravo sadri dva polja Polje: sopstveno i o n o koje
dobija o d klase Nad. M e u tim , Nad verzija nije o n a p o d razu m ev an a koja se d o b ija kada
izraz u pu uje na polje u klasi Pod; ako hoete Nad polje, m o rate izriito napisati nad.polje.
Iako m o d a izgleda da b i ovo m o g lo izazvati zab u n u , u p raksi se to gotovo n ik ad a n e
deava. Prvo, p o p rav ilu sva p o lja tre b a d a b u d u p riv atn a, p a im neete p ristu p a ti n ep o -
sredn o , nego sam o kao sp o red n i efekat p o zivanja m eto d a. Uz to, v erovatno neete d ati
isto im e p o lju osnov n e klase i p o lju izvedene klase, je r biste tako izazvali zbrku.
Ako je m e to d a statina, o n a se n e p o n a a p o lim o rfn o :
class StaticnaNad {
public s ta tic String s ta tic n a P rib a vi() {
return "Osnovna s ta tic n a P rib a vi( ) " ;
}
public String dinamicnaPribavi() {
return "Osnovna dinamicnaPribavi( ) " ;
}
}
Konstruktori i polimorfizam
K o n struktori se, kao i obino, razlikuju o d ostalih m etoda. To vai i u sluaju p olim orfizm a.
Iako k o n stru k to ri nisu po lim orfni (to su zapravo statine m etode, ali je njihova deklaracija
statinosti im plicitna), b itn o je da shvatite nain na koji o n i rade u sloenim hijerarh ijam a
i s polim orfizm om . To znanje e vam p o m o i da izbegnete n ep rijatn a zapetljavanja.
//: polimorfizam/Sendvic.java
// Poredak poziva konstruktora
package polimorfizam
import s ta tic net.m indview .util.P r in t.* ;
class Obrok {
Obrok() ( p rint("Obrok( ) " ) ; }
}
class Hleb {
Hleb() { p r in t("H le b ()"); }
}
class S ir {
S ir ( ) { p r in t ( " S ir ( ) " ) ; }
}
class Salata {
SalataO { p r in t (" S a la t a ()" ) ; }
}
Poglav[je 8: Polimorfizam 225
Nasleivanje i ienje
K ada n o v u klasu prav ite k o m p o zicijo m i n asledivanjem , uglav n o m neete m o ra ti da bri-
n ete o ciscenju; p o d o b jek ti se o b in o m o g u p rep u stiti sakupljau sm ea. U koliko ienje
ip ak treb a d a obavite, za svoju n o v u klasu m o rate sam i da n ap rav ite n eku m e to d u ci-
scenje() (ako im ate bolje im e, n azovite je drugaije). I p rilik o m nasleivanja, u izvedenoj
klasi m o rate da redefiniete m e to d u ciscenje() ako je p rilik o m saku p ljanja sm ea p o tre b -
n o nekakvo p o seb n o ienje. Kada u izvedenoj klasi redefiniete m e to d u ciscenje(), b it-
no je d a se setite da pozovete verziju te m eto d e iz osn o v n e klase, inae o sn o v n a klasa nee
biti oiena. To dokazuje n a red n i p rim er:
//: polimorfizam/Zaba.java
// ienje i nasleivanje.
package polimorfizam;
import s ta tic net.mindview.uti1 .P rin t.*;
class Karakteristika {
private String s;
Karakteristika(String s) {
th is .s = s ;
p rin t( "Pravljen je Karakteristike " + s );
}
protected void ciscen je() {
p rin t(" i e n je Karakteristike " + s ) ; }
}
}
class Opis {
private String s;
Opis(String s) {
th is .s = s ;
p rin t("P ra v lje n je Opisa " + s ) ;
}
prottected void ciscen je() {
p rin t(" i e rje Opisa " + s );
}
}
class ZivoBice {
private Karakteristika p =
new K a rak teristik a("ivo j e );
private Opis t =
Poglavlje 8: Polimorfizam 227
Svaka klasa u h ijerarh iji sadri i objekte lanove tipova K a ra k te ristik a i O p is, koji ta-
kode m o raju biti oieni. R edosled ienja treb a da je su p ro ta n red o sled u inicijalizacije,
za sluaj da je d an p o d o b jek at zavisi od dru g o g . Za polja to znai da redosled ienja tre-
ba da je su p ro tan redosledu d eklarisanja (p o to se p olja inicijalizuju o n im red o m kojim
su deklarisana). Za o sn o v n e klase (p ratei fo rm u u p o tre b ljen u za d estru k to re u C + + -u )
prv o treba da oistite izvedene klase, a zatim i o sn o v n e klase. R azlog je to to p ri ienju
izvedene klase m oete d a pozovete neke m eto d e iz o sn o v n e klase koje zahtevaju da kom -
p o n e n te osnovne klase jo b u d u ive, pa ne sm ete da ih u n itite pre vrem en a. Iz rezultata
p re th o d n o g p ro g ra m a v idite da se delovi objekta Z ab a iste re d o m su p ro tn im redosledu
kojim su pravljeni.
Iz ovog p rim era vidite sledee: iako ne m o ra te uvek sam i da istite, o n d a kada m orate,
taj proces zahteva p anju i znanje.
V eba 12: (3) Izm enite vebu 9 tako da prikazuje reosled inicijalizacije u osnovnoj klasi
i u izvedenim klasam a. Sada i osn o v n o j klasi i izvedenim klasam a d o d ajte objekte lanove
i pokaite kojim redosledom se inicijalizuju p rilik o m konstru k cije.
Poglav[je 8: Polimorfizam 229
//: polimorfizam/BrojanjeReferenci.java
// ienje deljenih objekata lanova.
import s ta tic net.m indview .util.P r in t.* ;
class Deljena {
private in t brojacref = 0;
private s ta tic long brojac = 0;
private fin al long id = brojac++;
public DeljenaO {
p rin t("P ra v l jenje 11 + th is );
}
public void dodajRef() { brojacref++; }
protected void c isce n je() {
if(- - b ro jacre f == 0)
p rint(" ienje " + th is );
}
public String toStringO { return "Deljena" + id ;}
class Kompozicija {
private Deljena deljena;
private s ta tic long brojac = 0;
private fin al long id = brojac++;
public Kompozicija(Deljena deljena) {
p rin t("P ra v lje n je " + th is );
this.d eljena = deljena;
th is.d elje n a .d o d a jR ef();
}
protected void ciscen je() {
p rin t(" i e n je " + th is );
del jena.ciscenjeO
}
public String toStringO { return "Kompozicija " + id ;}
for(Kompozicija c : kompozicija)
c .c is c e n je O ;
}
} /* Isp is:
Pravljenje Deljena 0
Pravljenje Kompozicija 0
Pravljenje Kompozicija 1
Pravljenje Kompozicija 2
Pravljenje Kompozicija 3
Pravljenje Kompozicija 4
ienje Kompozicija 0
ienje Kornpozicija 1
ienje Kompozicija 2
ienje Kompozicija 3
ienje Kompozicija 4
ienje Deljena 0
* ///.-
Statian brojac tip a long p ra ti bro j n ap rav ljen ih p rim e ra k a o b jek ta tip a Deljena i daje
v re d n o st prom enljivoj id. T ip brojaca je long u m esto int da b i se izbeglo p rek o raen je (u
ovom sluaju, to je sam o d o b ra praksa; v ero v atn o n ijed an p rim e r iz ove knjige nee
p ro u zrok o vati prekoraenje takvog brojaa). P rom enljiva id je fin a ln a , zato to ne oeku-
jem o da e m en jati v red n o st to k o in ivotnog veka ovog objekta.
Kada svojoj klasi p rid ru ite deljeni objekat, ne sm ete zabo rav iti da pozovete dodaj-
Ref(), ali e m eto d a ciscenje() p ra titi broj referenci i odlu iti kada da obavi ienje. Ova
teh n ik a zahteva o d a ta n tru d , ali ako su objekti koji zahtevaju ienje deljeni, nem ate
m n o g o izbora.
Veba 13: (3) D atoteci BrojanjeReferenci.java d o d ajte m e to d u finalize() da biste p ro-
verili postoji li stanja okonanja (videti poglavlje Inicijalizacija i ienje).
Veba 14: (4) Izm enite vebu 12 tako da jed an o d objekata lanova b u d e eljen s b ro-
jan jem referenci i pokaite da to ispravno radi.
jed an k o rak u pravljenju objekta klase koja je izvedena iz klase to g k o n stru k to ra , u v rem e
poziva tekueg k o n stru k to ra izvedeni delovi jo n isu inicijalizovani. M ed u tim , d in am ik i
povezan poziv see ka spoljanjosti11h ijerarh ije nasleivanja. O n poziva m e to d u izvede-
ne klase. Ako ga iskoristite u n u ta r k o n stru k to ra , pozvaete m e to d u koja m o d a rad i sa
lan ov im a koji jo uvek nisu inicijalizovani, to je sig u ran recep t za k atastrofu.
P rob lem m oete d a sagledate u n a re d n o m p rim e ru :
//: polimorfizam/PoliKonstruktori.java
// Konstruktori i polimorfizam
// ne pruaju ono to moda oekujete.
import s ta tic net.m indview.util.P r in t.* ;
class G lif {
void c r t a j( ) { print ("Gl i f . crta j ( ) " ) ; }
GlifO {
p r in t { " G lif ( ) pre metode c r t a j ( ) " ) ;
c rta j ( ) ;
p r in t ( " G lif ( ) posle metode c r t a j ( ) " ) ;
}
}
//: polimorfizam/KovarijantnoVracanje.java
class Zito {
public String toStringO { return " ito "; }
}
class Mlin {
Zito obradi() { return new Zito(); }
}
K ljuna razlika izm eu Jave SE5 i ran ijih verzija Jave lei u sledeem : ranije verzije bi
naterale redefinisanu verziju m eto d e obradi() da v rati objek at klase Zito, a ne Psenica,
iako je Psenica izvedena iz klase Zito i stoga je i dalje legitim an p o v ra tn i tip. K ovarijantni
p o v ra tn i tipovi o m oguavaiu specifiniji p o v ra tn i tip Psenica.
//: polimorfizam/Kompozicija.java
// Dinamika promena ponaanja objekta
// pomou kompozicije (projektni obrazac "stanje")
import static net.mindview.uti1.P r i n t .*;
class Glumac {
publi c voi d glumi( ) ;
234 Misliti na Javi
class Pozornica {
private Glumac glumac = new Sr ec an Gl um ac ();
public void p r om en i() { glumac = new T u za nG lu ma c( ); }
public void kreni () { glumac.glumi (); }
}
Oblik
nacrtajO
obrisi()
7V
Obrati se Obliku
Poruka Krug, Kvadrat, Linija
relacija ,.je" ili novi tip Oblika
Pretpostavimo
da ovo predstavlja
veliki interfejs
je kao"
Proirivanje
interfejsa
Obrati se objektu
Korisni deo
klase Koristan Poruka
KoriSugfdeo
Ako u ovom sluaju ne obavljate svoenje navie, to vas nee optereivati, ali esto
m oete da d o e te u situaciju kada tre b a p o n o v o o tk riti taan tip objekta kako biste mogli
da p ristu p ite njegovim d o d a tn im m e to d am a. U n a re d n o m odeljku p ok azu je m o kako se
to radi.
class Koristan {
public void f() {}
public void g() {}
}
U koliko elite da p ristu p ite p ro iren o m interfejsu objekta klase K orisn iji, p rim en ite
svodenje nanie. Ako je tip odgovarajui, o n o e b iti uspeno. U su p ro tn o m , dobiete izu-
zetak tipa C lassC astE xception. Za o b rad u ovog izuzetka nije n e o p h o d n o da piete poseban
kod, jer o n naznaava p ro g ram ersk u greku koja je m ogla d a se desi bilo gde u p ro g ram u .
K om en tar - oznaka {Throw sException} - kazuje sistem u za au to m atizo v an o prevoenje i
pakovanje (engl. build) p rim era iz ove knjige kako oekuje da e ovaj p ro g ra m prilikom
izvravanja generisati izuzetak.
RTTI je vie o d o bine konverzije. Postoji, na p rim er, nain da u stanovite tip pre nego to
po kuate da obavite njegovo svoenje nanie. K om pletno poglavlje Podaci o tipovim a p o-
sveeno je prouav an ju razliitih vidova po d atak a o tip o v im a prilik o m izvravanja u Javi.
V eba 17: (2) K oristei h ijerarh iju C ik l iz p rim e ra 1, m e to d u ra v n o te a () d o d ajte klasa-
m a U n icik l i B icikl, ali ne i klasi T ricik l. N apravite p rim e rk e sva tri tip a i svedite ih navie
n a niz tip a C ikl. Pozovite m e to d u ra v n o te a () za svaki elem en t to g niza i p o gledajte re-
zultate. Svedite nanie, pozovite m e to d u ra v n o te a () i p o g led ajte ta se deava.
Saetak
Po lim o rfizam znai razliiti o blici. U o b jek tn o o rije n tisa n o m p ro g ra m ira n ju im ate isti
interfejs osn o v n e klase i razliite oblike koji u p o treb ljav aju taj interfejs: razliite verzije
d in am ik i pov ezan ih m etoda.
U ov o m poglavlju videli ste da nije m ogue ra zu m e ti niti p rim e n iti p o lim o rfiz a m bez
u p o treb e ap strakcije p o d ata k a i nasleivanja. P o lim o rfizam je o so b in a koja ne m oe d a se
p o sm a tra izolovano (kao to m oe, n a p rim er, n ared b a svvitch), ve sam o kao deo vee
slike relacija izm e u klasa.
D a biste u p ro g ra m im a efikasno koristili p o lim o rfizam - a sam im tim i o b jek tn o o ri-
jen tisan e teh n ik e - m o ra te da p ro irite svoje p o im an je p ro g ra m ira n ja. P o red lanova i
p o ru k a zasebne klase, u zm ite u o b z ir i zajednike o so b in e m e u klasam a kao i njihove
m e u so b n e relacije. Iako to iziskuje znaajan n ap o r, o n se i te kako isplati. Postie se bri
razvoj p ro g ra m a, bolja organizacija koda, pro iriv i p ro g ra m i i lake od rav an je koda.
Reenja odabranih vebi data su u elektronskom dokum entu Thinking in Java Annotatcd Solution
Guide, koji se moe kupiti na lokaciji www.MindView.net.
Interfejsi
Interfejsi i apstraktne klase pruaju strukturiraniji naiti razdvajanja interfejsa od realizacije.
C + + IMA
T a k v i m e h a n i z m i n i s u t a k o C e s t i u p r o g r a m s k i m j e z i c i m a . P r i m e r a RA DI,
sam o p o sred n u p o d rk u za te koncepte. in jen ica da o n i p o sto je u Javi, govori d a su ih
pro je k tan ti jezika sm atrali d ovoljno b itn im da se za n jih ob ezbed i d ire k tn a p o d rk a kroz
rezervisane rei.
N ajpre em o ra z m o triti apstraktne kla seko je su o tp rilik e na pola p u ta izm e u o b in e
klase i interfejsa. Iako ete biti skloniji p ravljenju interfejsa, a p stra k tn a klasa je vana i
n e o p h o d n a alatka za pravljenje klasa koje im aju neke nerealizovane m etode. N e m o ete
uvek k o ristiti ist interfejs.
Klasa koja sadri ap strak tn e m eto d e naziva se apstraktna klasa. Ako kJasa sadri je d n u
ili vie ap strak tn ih m etoda, o n a m o ra biti kvalifikovana kao ap strak tn a . (U su p ro tn o m ,
prevodilac e prijaviti greku.)
Poto je a p stra k tn a klasa n e p o tp u n a , ta bi p revodilac treb alo da u rad i kada n eko p o-
kua da napravi objekat takve klase? Poto n e m oe da n ap rav i objek at a p strak tn e klase na
siguran nain, prevodilac e prijaviti greku. Na ovaj nain se o b ezb e u je p o tp u n o s t ap-
stra k tn e klase i vi ne m o rate da b rin ete o n jenoj ev en tu aln o j p o g ren o j u p o treb i.
A ko a p stra k tn u klasu n asled ite i elite d a p rav ite objekte to g novog tipa, m o ra te da
obezbedite definicije za sve a p stra k tn e m eto d e o sn o v n e klase. U koliko to ne u rad ite (a
m o ete i tako d a o dlu ite), ta d a i izvedena klasa o staje a p stra k tn a , te e vas prevodilac p ri-
siliti i da tu klasu oznaite rezerv isano m rei a b s tra c t.
A p strak tn u klasu m o ete d a n ap ra v ite i tak o d a ne sadri n ijed n u a p stra k tn u m eto d u .
To je k o risn o k ad a u klasi n e m a sm isla p ra v iti bilo kakve ap stra k tn e m etode, ali ipak elite
da spreite pravljenje o b jek ata te klase.
Klasa In s tr u m e n t iz p re th o d n o g poglavlja lako m oe da b u d e p retv o re n a u a p stra k tn u
klasu. Sam o neke m e to d e e b iti a p stra k tn e - ne m o ra ju sve. Evo kako to izgleda:
Interfejsi
Rezervisana re interface u n a p re u je k o n cep t apstrakcije. R ezervisana re abstract o m o -
guava da u klasi n ap rav ite je d n u ili vie m e to d a koje n em aju definicije - tim e obezbedu-
jete deo interfejsa, ali izostavljate o d g o v araju u realizaciju, koju e n ap rav iti naslednici te
klase. R ezervisana re interface o znaava p o tp u n o a p stra k tn u klasu, u kojoj uop te nem a
Poglavlje 9: Interfejsi 243
/ / : interfejsi/muzika5/Muzika5.java
// Interfejsi.
package interfejsi.muzika5;
import polimorfizam.muzika.Nota;
import static net.mindview.util.Print.*;
interface Instrument {
// Konstanta pri prevoenju:
int IZNOS = 5; // statina i finalna
// Ne moe da ima definicije metoda, ve samo deklaracije:
void sviraj(Nota n); // Automatski javne
void nastimuj();
}
Veba 7: ( 1) Izm enite vebu 9 iz pogiavlja Polim orfizam tak o da klasu Glodar p re tv o rite u
interfejs.
Veba 8: (2) U datoteci polimorfizam.Sendvic.java n a p ra v ite interfejs p o d im e n o m Br-
zaHrana (sa o d o gov araju im m eto d am a) i p ro m e n ite Sendvic tako d a realizuje i interfejs
BrzaHrana.
Veba9: (3) Izm enite p ro g ram Muzika5.java pravei a p stra k tn u klasu koja sadri zajed-
nike m eto d e po tklasa Duvacki, Udaraljke i Zicani.
Veba 10: (3) Izm enite d ato tek u Muzika5.java d o d aju i interfejs MozeDaSvira. D eklara-
ciju m eto d e sviraj( ) prebacite iz interfejsa Instrument u MozeDaSvira. Izvedenim klasa-
m a dodajte i interfejs MozeDaSvira, u b acujui ga u listu iza rezervisane rei implements.
Izm enite m eto d u m eiodija( ) tako da n jen a rg u m en t b u d e interfejs MozeDaSvira, um esto
interfejsa Instrument.
Potpuno razdvajanje
Kad g od m e to d a rad i s klaso m u m esto sa interfejsom , o g ran ien i ste na u p o tre b u te klase
i n jen ih podklasa. U koliko biste ba h teli da p rim e n ite tu m e to d u na n ek u klasu koja nije
u toj hijerarh iji, nem ate sree. Interfejs z n a tn o slabi to ogranienje. Stoga m oete da pie-
te kod koji je lake u p o tre b iti vie p uta.
Na p rim er, p retp o stav im o da im ate klasu Procesor s m e to d a m a im e ( ) i o b rad i( ) koja
p rim a ulazne podatk e, m odifikuje ih i alje na izlaz. O sn o v n a klasa se p ro iru je prilik o m
pravljenja vie razliitih v rsta Procesora. U ovom sluaju, p o d tip o v i Procesora m odifi-
kuju String objekte (vodite rau n a o to m e da k o v arijan tn i m o g u biti p o v ra tn i tipovi, ali
ne i tip o v i arg um enata):
//: interfejsi/klasaprocesor/Primeni.java
package interfejsi.klasaprocesor;
import java.util
import static net.mindview.uti1 .P r i n t .*;
class Procesor {
public String ime() {
return g e t C l a s s O . g e t S i m p l e N a m e O ;
}
Object obradi(Object ulaz) { return ulaz; }
}
return ( (String)ulaz).toLowerCase();
}
}
//: interfejsi/filtri/Talasnioblik.java
package interfejsi.filtri;
248 Misliti na Javi
ne m oete u p o tre b iti s m e to d o m Primeni.obradi(), iako bi to bilo lepo. U sutini, veza iz-
m ed u Primeni.obradi() i Procesora jaa je nego to je p o tre b n o , a to spreava k o d iz Pri-
meni.obradi() d a se p o n o v o upotreb ljav a ta m o gde bi to trebalo. O b ratite p an ju na to da
su i ulazi i izlazi tip a Talasnioblik.
D a je Procesor interfejs, o g ra n ien ja b i bila to lik o oslabljena d a biste m ogli k o ristiti
m eto d u Primeni.obradi() koja u zim a taj interfejs. Evo m o d ifik o v an ih verzija Procesora
i Primeni:
//: interfejsi/interfejsprocesor/Procesor.java
package interfejsi.interfejsprocesor;
//: in te rf ej si/interfejsprocesor/Primeni.java
package interfejsi.interfejsprocesor;
import static ne t. mi nd vi ew .u ti l.Print.*;
Prvi nain na koji m o ete p o n o v o u p o treb iti k o d jeste o n aj kada p ro g ram e ri klijenti
la p iu svoje klase tako d a b u d u usaglaene sa ov im interfejsom ; n a p rim er:
M e u tim , esto n e m oete da m o ifik u jete klase koje h o ete da u p o tre b ite . Za elek-
tron ske filtre, na prim er, p ro n a e n a je gotova b iblioteka, a nije pravljena nova. U takvim
sluajevim a m o ete u p o tre b iti p ro jek tn i o b razac A dapter (a d a p te r). N avodim o nain
kako u A d ap teru piete k o d koji e preuzeti postojei interfejs i n ap rav iti interfejs koji
vam je p o treb an :
! ..........A ........
i i Interfejs n i
: : ............A .......
M oete da n avedete koliko g o d elite interfejsa - svaki po staje nezavisan tip, ka kojem
m o ete da svedete navie n o v u klasu. U n a re d n o m p rim e ru p rik a za n a je k o n k re tn a klasa
k oja uz nekoliko interfejsa daje n o v u klasu:
//: interfejsi/Avantura.java
// Vie interfejsa
interface MozeDaSeBori {
void boriSe();
}
interface MozeDaPliva {
void p l i v a j O ;
}
interface MozeDaLeti {
void leti ();
}
class AkcioniJunak {
public void boriSe() {}
}
class Heroj extends AkcioniJunak
implements Mo ze D a S e B o r i , MozeDaPliva, MozeDaLeti {
public void plivaj() {}
public void leti () {}
}
novog tip a, m orate da napravite klasu u kojoj postoje definicije svih m etoda. Iako m eto d a
boriSe() nije izriito definisana u klasi Heroj,o n a dolazi u z klasu Akcionijunak, im e au to -
m atski p ostaje i deo klase Heroj, p a je m ogue n ap rav iti objekat te klase.
U klasi Avantura posto je etiri m eto d e iji su a rg u m en ti razn i interfejsi k o n k retn e kla-
se. K ada se n aprav i objekat klase Heroj, o n m oe d a se p ro sledi bilo kojoj o d tih m eto d a,
to znai da se m oe svesti navie ka svakom o d tih interfejsa. To se obavlja b ez p rep rek a
i bez p o se b n o g angaovanja p ro g ram era, zahvaljujui n ain u n a koji su interfejsi u Javi
p ro jekto vani.
Z a p a m tite da je u g o rn je m p rim e ru po k azan sutinski razlog p o sto jan ja interfejsa:
m o g u n o st da se obavi svoenje navie ka vie o sn o v n ih tipova. M e u tim , d ru g i razlog za
korienje interfeisa isti je kao i za korienje a p strak tn e osn ov ne klase: d a p ro g ra m e r kli-
je n t ne m o e da n ap ravi objekat te klase i d a b u d e svestan kako je to sam o interfejs.
Z bog toga se javlja pitanje: da li u p o tre b iti interfejs ili a p stra k tn u klasu? A ko o sn o v n u
klasu m oete da naprav ite bez definicija m eto d a i bez p ro m en ljiv ih , uvek od a b e rite in te r-
fejse u m esto ap strak tn ih klasa. U sutini, ako znate da e neto b iti osn ov na klasa, p rv o p o -
kuajte d a to napravite kao interfejs. (O to m e em o jo govoriti u saetku ovog poglavlja.)
Veba 12: (2) U datoteci Avantura.java d o dajte interfejs p o d im e n o m MozeDaSePenje
p rate i o b lik ostalih interfejsa u njoj.
Veba 13: (2) N apravite interfejs koji nasleuju dva d ru g a interfejsa. N eka trei interfejs
nasledi ta dva.:
//: i nterfejsi/HororPredstava.java
// Proirivanje interfejsa nasleivanjem.
interface Cudoviste {
void za p r e t i ();
}
interface Smrtonosno {
void u b i j ();
//: interfejsi/Sukobljavanjelnterfejsa.java
package interfejsi;
Prilagoavanje interfejsu
Jedan o d najvanijih razloga za u p o tre b u in terfejsa jeste m o g u n o st p o sto jan ja vie rea-
lizacija istog interfejsa. U je d n o stav n im sluajevim a, to se ra d i u o b lik u m e to d e koja p ri-
hvata interfejs, a vam a ostavlja d a ga realizujete i m eto d i p ro sled ite svoj objekat.
Stoga se interfejsi o b in o u p o treb ljav aju u p re th o d n o s p o m e n u to m p ro jek tn o m
o b rascu Strategy. N apiete m e to d u koja obavlja izvesne operacije, a ta m eto d a p rih v ata i
interfejs koji vi zadate. U sutin i, vi kaete: M oe u p o tre b ljav a ti m o ju m e to d u s bilo ko-
jim o b jek to m koji je usaglaen s m o jim interfejsom ". T im e vaa m e to d a po staje fleksibil-
nija, optija i upotrebljivija.
N a prim er, k o n stru k to r Java SE5 klase Scanner (o kojoj ete vie sazn ati u poglavlju
Z n akovn i nizovi) p rim a interfejs Readable. V ideete d a Readable nije a rg u m e n t n ijed n e
d ru g e m eto d e u stan d a rd n o j b iblioteci Jave - n ap rav ljen je sam o za Scanner, tako da
Scanner ne m o ra da ogranii svoj a rg u m e n t n a o d re e n u klasu. N a taj nain , Scanner
m oe da radi s vie tipova. A ko prav ite n o v u klasu i h o ete d a o n a b u d e u p o treb ljiv a s kla-
som Scanner, neka b u d e Readable (itljiva):
//: interfejsi/SlucajneReci.java
// Realizovanje interfejsa tako a bude usaglaen sa odreenom metodom.
import java.nio.*;
import ja va .u ti l.*;
} /* Ispis:
Yazeruyac
Fowenucor
Goeazimom
Raeuuacio
Nuoadesiw
Hageai kux
Ruqicibui
Numasetih
Kuuuuozog
Waqizeyoy
* ///:-
Interfejs Readable zahteva sam o realizaciju m eto d e read(). U m eto d i read(), argu-
m e n tu tipa CharBuffer dod ajete znakove (to se m o e u ra d iti n a nekoliko naina; v ideti
d o k u m e n ta c iju klase CharBuffer) ili vraate -1 kada ulaza vie nem a.
P retp o stav im o da im ate klasu koja nije realizovala Readable - kako ete postii da o n a
radi s klasom Scanner? Evo jed n e klase koja pro izv o d i sluajne realne brojeve (s p o k ret-
n im zarezom ):
//: interfejsi/SlucajniDouble.java
import ja v a . u t i l .*;
Fonovo sm o u p o treb ili p ro jek tn i o b razac A dapter, ali se u ovom sluaju prilag o en a
klasa m oe nap rav iti nasleivanjem i realizacijom interfejsa R ead ab le. D akle, koristei
pseu do viestruk o nasledivanje koje o m oguava rezervisana re in terfa ce, napravili sm o
novu klasu koja je i tip a S lu c a jn iD o u b le i tipa R eadable:
//: interfejsi/PrilagodjeniSlucajniDouble.java
// Pravljenje adaptera s nasleivanjem.
import java.nio.*;
import j a va .u ti1 .*;
Poto na ovaj nain svakoj postojeoj klasi m o ete d o d a ti interfejs, znai da m etoda
koja p rim a interfejs obezbeuje i n ain p rilag o en ja bilo koje klase za rad s to m m eto -
dom . U to m e lei m o korienja interfejsa u m esto klasa.
V eba 16: (3) N apravite klasu koja proizvodi niz znakova (objekata tip a ch a r). Prilagodite
tu klasu tako da se m oe u p o tre b iti za ulaz objekta tip a S can n er.
Polja u interfejsima
Poto su sva polja koja stavite u interfejs au to m atsk i statin a i finalna, interfejs je korisna
alatka za pravljenje g ru p a k o n sta n tn ih v red n o sti. Pre Jave SE5, to je b io jed in i nain da se
postig ne efekat koji daje rezervisana re e n u m u C -u ili C ++-U . D akle, naii ete na ova-
kav k o d n apisan p re Jave SE5:
//: interfejsi/Meseci.java
// Upotreba interfejsa za pravljenje grupa konstanti.
package interfejsi;
O b ra tite p an ju na to da je i ovde u p o treb ljen uob iajen i sti! pisanja statin ih finalnih
polja u Javi, ije su v red n o sti inicijalizovane k o n stan ta m a sve se pie velikim slovim a,
Poglavlje 9: Interfejsi 259
//: interfejsi/SlucajnePromenljive.java
// Inicijalizacija polja u interfejsu pomou
// nekonstantnih inicijalizacionih vrednosti
import java.util
//: interfejsi/TestirajSlucajnePromenljive.java
import static n e t .mindview.uti1 .Print.*;
Ugneivanje interfejsa
Interfejsi3 m o g u da b u d u u g n eden i u n u ta r d ru g ih klasa ili d ru g ih interfejsa. T im e se o t-
k riv a nekoliko veom a k o risn ih osobina:
//: interfejsi/ugnezdjivanje/Ugnezdjivanjelnterfejsa.java
package interfejsi.ugnezdjivanje;
class A {
interface B {
void f ();
}
public class Blmp implements B {
public void f() {}
}
private class BImp2 implements B {
public void f() {}
}
public interface C {
void f();
}
class Clmp implements C {
public void f() {}
}
private class CImp2 implements C {
public void f() {}
}
private interface D {
void f();
}
private class Dlmp implements D {
public void f() {}
}
public class DImp2 implements D {
public void f() {}
}
public D uzmiD() { return new DImp2(); }
private D dRef;
public void primiD(D d) {
dRef = d;
dRef.f();
}
interface E {
interface G {
void f ();
}
// Suvian public":
public interface H {
void f();
}
void g ( ) ;
// Ne moe da bude privatan unutar interfejsa:
//! private interface I {}
}
vatni ugneeni interfejs? M ogli biste p retp o stav iti kako o n m oe sam o da b u d e realizovan
kao priv atn a ugneena klasa u klasi D lm p, ali n am klasa A.DImp2 pokazuje d a o n takoe
m oe biti realizovan i kao jav n a klasa. Klasa A.DImp2, m ed u tim , m oe da se up otrebljava
sam o kao klasa tog o d re en o g tipa. Poto ne p ostoji nain da se spolja vidi kako ona, u
stvari, realizuje privatn i interfejs D, to je realizovanje p riv atn og interfejsa nain da n am et-
nete p rim e n u definicija nekog interfejsa, a da p ri to m e ne do d ate i inform aciju o tip u (od-
nosno , tim e neete dozvoliti svoenje navie).
M etoda uzm iD() u n o si d o d a tn u d ile m u po p ita n ju p riv atn o g interfejsa: o na je javna
m eto d a koja vraa referencu n a p riv a tn i interfejs. ta m oete da u rad ite s p o v ra tn o m
v redno u ove m etode? U m e to d i m ain() m o ete da uoite nekoliko po ku aja da se ta p o -
v ra tn a v red n o st u p o treb i, ali se svi o n i zavravaju n eu sp eh o m . P o v ratn u v red n o st jed in o
m oete d a p red ate d ru g o m o b jek tu koji im a ovlaenja da je koristi - u ovom sluaju,
d ru g o m o b jek tu klase A p rek o m e to d e p rim iD ( ).
Interfejs E po kazuje d a interfejsi m o g u d a b u d u ugn een i jed an u n u ta r drugog. Pra-
vila o interfejsim a - p o seb n o o n o da svi elem en ti interfejsa m o ra ju da b u d u javni - ovde
se strogo p o tu ju , pa je interfejs u g n e en u n u ta r d ru g o g interfejsa au to m atsk i javan i ne
m oe b iti proglaen p riv atn im .
Klasa Ugnezdjivanjelnterfejsa p o k azu je razliite naine na koje ugneeni interfejsi
m o gu da b u d u realizovani. P rilikom realizovanja interfejsa n e m o rate da realizujete i in-
terfejse koji su u njega u gneeni. Takoe, p riv atn i interfejsi ne m o gu da b u d u realizovani
van klase u kojoj su definisani.
U poetk u vam se m oe u in iti da ove m o g u n o sti postoje sam o zbog k on sistentno sti
sintakse. U p rin c ip u , kada zn ate da neka m o g u n o st postoji, sm a tram da m oete naii na
m esto na kom e e k o risn o d a vam poslui.
Interfejsi i Proizvoai
Interfejs bi trebalo da poslui kao p u t do vie realizacija, a tipian nain pravljenja objekata
usklaenih sa interfejsom jeste p ro jek tn i obrazac Factory M ethod (P roizvodna m etoda).
U m esto da k o n stru k to r pozivate n e p o sred n o , vi pozivate m eto d u za pravljenje proizvod-
n og objekta koji proizvodi realizaciju tog interfejsa - tim e bi, teorijski, va kod bio p o tp u -
no izolovan o d realizacije interfejsa, to bi om oguilo n e p rim etn u zam enu jed n e
realizacije d ru g om . Evo jed n o g p rim era koji e pokazati stru k tu ru obrasca Factory Method:
/ / : interfejsi/Proizvodjaci.java
import static ne t.mindview.util.Print.*;
interface Usluga {
void me t o d a l ( ) ;
void me t o d a 2 ( ) ;
}
interface ProizvodjacUsluga {
Usluga uzmiUslugu ();
}
Poglavlje 9: Interfejsi 263
Da n e m a obrasca Factory M ethod, negde u k odu m orali biste da navedete taan tip in-
terfejsa U slu g a koji se prav i, da bi on m ogao da pozove odgovarajui k on stru ktor.
Z ato da ovek do d aje jo jed an nivo posredovanja? Jedan od uobiajenih razloga je
pravljenje zajednikog kostura. P retp o stav im o da p ravite sistem za igranje igara; na pri-
m er, za igranje aha i dam e na istoj tabli:
//: interfejsi/Igre.java
// Kostur za Igre napravljen pomou Proizvodnih metoda.
import static net.mindview.uti1.Print.*;
264 Misliti na Javi
}
public static void main(String[] args) {
igraj Igru(new P r o i z v o d j a c D a m a O ) ;
igrajlgru(new Proizvodjacsah());
}
} /* Ispis:
Dama potez 0
Dama potez 1
Dama potez 2
ah potez 0
ah potez 1
ah potez 2
ah potez 3
* ///:-
Poglavlje 9: Interfejsi 265
Saetak
Lako je pasti u zam k u i sve interfejse p roglasiti d o b rim pa ih zbog toga uvek treb a p ret-
p ostav iti k o n k re tn im klasam a. N aravno, u m esto svake klase g otovo uvek se m oe n a p ra -
viti interfejs i Proizvoa.
M no gi su podlegli to m iskuenju i n apravili interfejse i Proizvoae gde go d su m ogli.
Razlog: m o d a e zatrebati dru g aija realizacija, p a tu ap strak ciju treb a d o d a ti uvek. To se
pretv orilo u svojevrsnu p re ra n u o p tim izaciju p ro jek ta.
Svaku apstrakciju treba da m otivie o d re en a stv arn a p o treb a. Ako vam zatreb aju , in-
terfejse treba da d o d ate tek p rilik o m p o n o v n e p o d ele na proste faktore. N em ojte taj d o-
d a tn i nivo indirekcije stavljati o d m a h i svugde, je r tim e poveavate sloenost. D o d atn a
sloenost je bitna, i ako m e neko n atera da p ro e m kroz n ju sam o da b ih na kraju shvatio
kako je interfejs d o d a t ,,za svaki slu aj, a bez prav o g razloga p o su m n ja u u sve p ro jek te
te osobe.
U m esna sm ern ica je radije koristite klase nego interfejse. Ponite o d klasa, pa ako se
ispostavi da su interfejsi n e o p h o d n i, ponovo sve p o d elite na p roste faktore. Interfejsi su
od line alatke, ali je lako p reterati s njih o v o m u p o tre b o m .
R e e n ja o d a b r a n ih v e b i d a ta su u e le k tr o n s k o m d o k u m e n t u T liitikin g in Java A n n o ta te d S olution
G uide , ko ji sc m o e k u p iti n a lo k a c iji w w w .M in d V iew .n et.
Unutranje kfase
D efiniciju klase m oete da stavite u n u ta r definicije neke druge klase. Takva klasa se naziva
u n u tra n ja klasa (engl. inner class).
U n u t r a Sn j a k l a s a j e v r e d n a , z a t o St o o m o g u u j e d a k l a s e l o g i k i G R U PlSETE I DA
k o n tro liete n jih o v u m e u so b n u viljivost. Vano je shvatiti da su u n u tra n je klase b itn o
razliite o d kom pozicije.
N a p rv i pogled, u n u tra n je klase izgledaju kao jed n o stav an m eh an iz am za sakrivanje
koda: p rek o n jih u gra u jete klasu u n u ta r drug e klase. N auiete d a u n u tra n ja klasa p ru -
a i vie o d toga - o n a je svesna p risustv a klase koja je o k ru u je i m oe s n jo m d a k o m u -
n icira. Iako su za vein u u n u tra n je klase sasvim n o v k on cep t, p o m o u n jih m oete da
piete finiji i jasn iji ko d , m a d a niko n e jam i d a e takav i biti.
D o k uite o u n u tra n jim klasam a, n jihova sv rh a esto nije oigledna, pa navikavanje
n a njih m oe d a p o traje. N akon opisa o sn ov ne sintakse i sem an tike u n u tra n jih klasa, u
o d eljk u Z ato u n u tra n je klase? nai ete p rim ere koji e o b jasniti p re d n o sti u n u tra -
njih klasa.
N akon to g odeljka, u o statk u poglavlja detaljnije je raz m o tren a sintaksa u n u tra n jih
klasa. Te m o g u n o sti su d o d ate rad i p o tp u n o sti jezika, ali vam v ero vatno nee treb ati, na-
ro ito ne isprva. Z ato e vam p o etn i delovi poglavlja zasa verovatno biti dovoljni, a de-
taljnije istraivanje m oete sm a tra ti referen tnim m aterijalo m .
U p o treb a u n u tra n je klase u n u ta r m eto d e p o sa lji() izgleda kao i u p o tre b a bilo koje
d ru g e klase. U ovom sluaju, jed in a vana razlika je to to su im en a u g n e en a u n u ta r
klase P o s iljk a l. U skoro ete videti da to nije jed in a razlika.
Spoljna klasa e ee im ati m e to d u koja v raa referencu n a u n u tra n ju klasu, kao to
se vidi u m e to d a m a za() i sad r():
//: unutrasnjeklase/Posiljka2.java
// Vraanje reference na unutranju klasu
} /* Ispis:
Tanzanija
* ///:-
Ako elite da o bjek at u n u tra n je klase n ap rav ite izvan neke n estatin e m eto d e spoljne
klase, kao tip to g objekta m o rate d a navedete Im eSpoljneKlase.ImeU nutranjeKlase, kao
to se vid i u m e to d i m a in ().
Veba I: (1) N apiite klasu Spoljna koja sadri u n u tra n ju klasu Unutrasnja. Klasi Spolj-
na d o d ajte m e to d u koja vraa o b jek at tip a Unutrasnja. U m e to d i m a in ( ) n ap rav ite i ini-
cijalizujte referencu n a o b jek at klase Unutrasnja.
//: unutrasnjeklase/Sekvenca.java
// uva niz objekata
interface Selektor {
boolean kraj();
Object t e k u c i ();
void sledeci ();
}
' U ovom pogledu, ugneene khise u C + + -u veom a se razlikuju, jer su o n e sam o m ehanizam za sakri-
vanje im ena. U C++-U ne postoji veza sa okolnim objektom niti podrazum evana prava pristupa.
Poglavlje 10: Unutranje klase 269
Klasa Sekvenca ob u h v ata sam o n iz fiksne d u in e elem enata tip a Object. M oete da
pozovete m e to d u dodaj() kako biste d o d ali n o v elem en t tip a Object na kraj niza (ako u
n je m u im a m esta). Za traen je elem en ata niza p o sto ji interfejs Selektor. To je p rim e r p ro -
jek tn o g o brasca Iterator (ite ra to r), o kojem ete vie saznati u nastavku knjige. Selektor
om og u av a d a p rov erite d a li ste na k raju niza (m eto d a kraj()), da pogledate tekui obje-
k at (m e to d a tekuci()) i da se p o m erite na sledei elem en t u n izu (m eto d a sledeci()).
Poto je Selektor interfejs, njega m ogu da realizuju i m noge d ru g e klase na neki svoj na-
in, a taj interfejs m oe biti arg u m en t m n o g ih m eto d a, im e se prav i generiki kod.
U naem p rim e ru , p riv a tn a klasa SelektorSekvence prua fu n k cio n aln o st interfejsa
Selektor. U m eto d i main() se, n ak o n pravljenja objekta klase Sekvenca, u taj objekat d o -
daje nekoliko objek ata tipa String. Z atim se poziv an jem m eto d e selektor pravi Selektor
koji se k oristi za p o m e ra n je p o o b jek tu klase Sekvenca i za p ristu p svakom elem en tu.
Na prvi pogled, pravljenje klase SelektorSekvence izgleda p o p u t jo jedne u n u tra n je
klase. P ro u im o je paljivije. O b ratite p an ju na to da se sve m eto d e - kraj(), tekuci() i
sledeci() o b raaju referenci obs koja nije deo klase SelektorSekvence, ve je p riv atn o
polje o k oln e sp oljn e klase. U n u tran ja klasa, m e u tim , m oe da p ristu p a m eto d am a i p o-
Ijima spo ljne klase kao da p rip ad a ju njoj. Ta o so b in a m oe da b u d e veom a p o g o d n a, kao
to se vidi u p re th o d n o m p rim e ru .
Z nai, u n u tra n ja klasa im a au to m atsk i p ristu p lanovim a klase koja je okruuje.
Kako se to deava? U n u tran ja klasa skriveno uva referencu na onaj objekat spoljne klase
koji je tu u n u tra n ju klasu n apravio. P rilikom p ristu p a n ja lanovim a spoljne klase up o -
trebljava se ta (skrivena) referenca. Prevodilac se, na sreu, b rin e o svim d etaljim a um esto
vas. Sada k o n an o m oete da shvatite zato u n u tra n ja klasa m oe da se n apravi sam o za-
je d n o sa o b jek to m spo ljne klase (kada je, kao to ete videti, u n u tra n ja klasa n estatin a).
Za k o n stru k ciju objekta u n u tra n je klase p o tre b n a je referenca na objekat spoljne klase i
prevodilac e se p o b u n iti ako toj referenci ne m oe da pristu p i. U veini sluajeva, ovaj
scenario se odigrava bez intervencije p ro g ram era.
Veba 2: (1) N apravite klasu koja uva jedan String i im a m eto d u toStringf) koja taj String
prikazuje. D od ajte nekoliko p rim erak a te klase o b jek tu tipa Sekvenca i prikaite ih.
Veba 3: (1) Izm en ite vebu 1 tako da Spoljna im a p riv atn o polje tipa String (koje inici-
jalizuje k o n stru k to r), a Unutrasnja m eto d u toStringO koja to polje prikazuje. N apravite
objekat tipa Unutrasnja i p rik aite ga.
270 Misliti na Javi
//: unutrasnjeklase/TackaThis.java
// Kvalifikovanje pristupa objektu spoljne klase.
public class TackaThis {
void f() { System.out.println("TackaThis.f()"); }
public class Unutrasnja {
public TackaThis spoljna() {
return TackaThis.this;
// Golo "this" bi bilo "this" od klase Unutrasnja
}
}
public Unutrasnja unutrasnja() { return new U n u t ra sn ja (); }
public static void main(String[] args) {
TackaThis dt = new TackaThis();
TackaThis.Unutrasnja dti = d t . u n u tr as nj a( );
dt i. sp oljna().f();
}
} /* Ispis:
TackaThi s .f ()
* ///:-
//: unutrasnjeklase/TackaNova.java
// Neposredno pravljenje unutranje klase operatorom .new.
Z nai, ako n em ate o b jek at spo ljn e klase, ne m oete d a n ap rav ite n i objekat u n u tra n je
klase, zbog toga to objekat u n u tra n je klase m o ra biti povezan sa sp o ljn o m klasom . M e-
u tim , u koliko prav ite ugtieenu klasu (sta ti n u u n u tra n ju klasu), njoj referenca na
ob jek at spoljne klase nije p o tre b n a .
Evo kako bi se o p e ra to r ,n ew p rim e n io u p rim e ru Poiljka:
//: unutrasnjeklase/Posiljka3.java
// Pravljenje instanci unutranje klase operatorom .new
V eb a4 : (2) Klasi S ek ven ca.S elek torS ek v en ce d o d ajte m eto d u koja proizvodi referencu
na sp o ljn u klasu Sekvenca.
Veba 5: (1) N apravite klasu koja im a u n u tra n ju klasu. U o dvojenoj klasi n ap ravite in-
stan cu u n u tra n je klase.
//: unutrasnjeklase/Odrediste.java
public interface Odrediste {
String pr oc it aj Oz na ku();
} ///= -
272 Misliti na Javi
//: unutrasnjeklase/Sadrzina.java
public interface Sadrzina (
int vrednost();
1III--
Sada S a d rz in a i O d re d is te p red stav ljaju interfejse d o stu p n e p ro g ra m e ru klijen tu koji
koristi nau biblio tek u klasa. (Setite se d a su svi lano vi interfejsa au to m atsk i javni.)
Kada d obijete referencu n a o sn o v n u klasu ili n a interfejs, m o g u e je da u o p te ne m o -
ete d a otk rijete stvarni tip objekta, kao to je p rik aza n o u sledeem p rim eru :
//: unutrasnjeklase/ProbnaPosiljka.java
poznaje te lanove, niti m oe d a im p ristu p a bez ogranienja. Ka priv atn oj u n u tran jo j klasi
(ili ka zatienoj u n u tra n jo j klasi ako niste neki o d naslednika), u stvari, ne m oete d a oba-
vite n i svoenje nanie, je r ne m oete da p ristu p ite n jen o m im enu , kao to se vidi u klasi
P ro b n aP o siljk a. Privatne u n u tran je klase stoga o m oguavaju p ro jek tan tu klase da p o tp u -
no sprei zavisnost o d tip a i da p o tp u n o sakrije p o d atk e o realizaciji. Pored toga, proiriva-
nje interfejsa je beskorisno, iz perspektive p ro g ra m e ra klijenta, je r o n ne m oe da p ristu p i
ostalim m eto d am a koje nisu deo javnog interfejsa. T im e se takoe Javinom prevodiocu
om oguava da pravi efikasniji kod.
V eba 6: (2) N apravite interfejs koji sadri b arem je d n u m e to d u u so pstv eno m paketu.
D o dajte zatienu u n u tra n ju Jdasu koja realizuje taj interfejs. U treem p ak etu nasledite
svoju kJasu i, u n u ta r m eto d e, v ratite o bjek at zatiene u n u tra n je kJase, svodei navie na
interfejs to k o m vraanja.
V eba 7: (2) N aprav ite Idasu koja im a p riv a tn o p o lje i p riv a tn u m eto d u . N ap rav ite u n u -
tra n ju klasu ija m eto d a m en ja polje spo ljne kJase i poziva m e to d u spo ljne kJase. U d ru -
goj m e to d i spoljne kJase n a p ra v ite objek at u n u tra n je ldase i pozo vite n je n u m e to d u , a
zatim pok aite dejstvo na objekat spo ljn e kJase.
V eba 8: (2) U tv rd ite d a li spo ljn a ldasa im a p ris tu p p riv a tn im elem en tim a svoje u n u tra -
nje klase.
Prvi p rim e r prikazu je pravljenje cele klase ija je oblast vaenja je d n a m eto d a (um esto
da je oblast vaenja d ru g a klasa). To je lokalna unutranja klasa:
//: unutrasnjeklase/Posiljka5.java
// Ugneivanje klase unutar metode.
Klasa POdrediste je deo m eto d e odr(), a ne deo klase Posiljka5. Z bog toga klasi POd-
rediste ne m o ete da p ristu p ite izvan m eto d e odr(). O b ra tite p a n ju na svoenje navie
u n ared b i return - m eto d a odr() vraa sam o referencu na o sn o v n u klasu, klasu Odredi-
ste. N aravno, to to je im e klase POdrediste navedeno u n u ta r m eto d e odr() ne znai da
o bjekti klase POdrediste n akon p o v ratk a iz te m eto d e nee biti ispravni.
O b ratite p anju na to da ste za im ena u n u tran jih klasa u svim klasam a u istom poddi-
rek to riju m u m ogli da koristite identifik ato r POdrediste, a da ne o e d o sukoba im ena.
N ared n i p rim e r p o kazuje kako u n u tra n ju klasu m oete da u g nezdite u n u ta r proiz-
voljne oblasti vaenja:
//: unutrasnjeklase/Posi1jka6.java
// Ugneivanje klase unutar oblasti vaenja
/ / : unutrasnjeklase/Posiljka7.java
// Metoda koja vraa anonimnu unutranju klasu.
M etoda sad r() k o m b in u je generisanje p o v ratn e v red n o sti i d e fin i ju klase koja p red -
stavlja tu p o v ra tn u vrednost! Pored toga, klasa je anotiim na n em a im e. D a stvari b u d u
jo gore, izgleda kao da poin jete da pravite n o v objek at klase Sadrzina, ali tad a, p re nego
to d o d e te do take i zareza, kaete: Sam o tren u ta k , sada u da u b acim definiciju klase.
276 Misliti na Javi
//: unutrasnjeklase/Posiljka7b.java
// Proirena verzija programa Posiljka7.java
//: unutrasnjeklase/Posi1jka8.java
// Anonimna unutranja klasa koja poziva konstruktor osnovne klase.
//: unutrasnjeklase/Omotac.java
public class Omotac {
private int i;
Poglavlje 10: Unutranje klase 277
public 0motac(int x) { i = x; }
public int vrednost{) { return i; }
} ///:-
P rim etili ste kako O m o ta c im a k o n stru k to r koji zahteva a rg u m en t, da bi bilo m alo za-
nim ljivije.
Z n ak taka i zarez n a k raju a n o n im n e u n u tra n je klase n e oznaava kraj tela klase. O n
oznaava kraj izraza koji u d ato m sluaju sadri i a n o n im n u klasu. D akle, u p o tre b a take
i zareza p o tp u n o je ista kao i bilo gde d ru g d e u p ro g ram u .
Inicijalizaciju o b jek ta a n o n im n e klase m o ete d a obavite n a m e stu n a k o m e definiete
polja:
//: unutrasnjeklase/Posi1jka9.java
// Anonimna unutranja klasa koja obavlja inicijalizaciju.
// Kraa verzija datoteke Posiljka5.java.
I I : unutrasnjeklase/KonstruktorAnonimne.java
// Pravljenje konstruktora za anonimnu unutranju klasu.
import static n e t .mindview.uti 1 .P r in t.*;
abstract class Osnovna {
public Osnovna(int i) {
print("Konstruktor klase Osnovna, i = " + i);
}
public abstract void f ();
}
278 Misliti na Javi
//: unutrasnjeklase/PosiljkalO.java
// Upotreba "inicijalizacije instanci" za konstrukciju
// anonimne unutranje klase.
/ / : unutrasnjeklase/Proizvodjaci.java
import static net.mindview.uti1 .Prin t .*;
interface Usluga {
void m e t o d a l ();
void m e t o d a 2 ( ) ;
}
interface ProizvodjacUsluga {
Usluga uzmiUslugu ();
}
//: unutrasnjeklase/Igre.java
// Kostur za Igre napravljen pomou unutranjih klasa.
import static net.mi nd vi ew .u ti l.Print.*;
Ugneene klase
A ko vam n e treb a veza izm eu n jen ih o b jek ata i o b jek ata sp oljn e klase, u n u tra n ju klasu
m oete da proglasite statin o m . O n a se o b in o naziva ugneena klasa2. D a biste shvatili
znaenje kvalifikatora sta tic kada se p rim e n i na u n u tra n je klase, setite se da objekat obi-
ne u n u tra n je klase im p licitn o uva referencu n a o b jek at spoljn e klase koja ga je napravila.
Kada kaete da je u n u tra n ja klasa statin a, ovo ne vai. U gneena klasa znai da:
1. Za pravljenje o b jek ta u g n e en e klase nije p o tre b a n o b jek at spo ljne klase.
2 . Iz objekta u g n e en e klase ne m o ete d a p ristu p ite o b jek tu sp o ljn e klase.
U gneene klase se jo p o n e em u razlik u ju o d n e stati n ih , tj. o b i n ih u n u tra n jih
klasa. Polja i m e to d e nestatin e u n u tra n je klase m o g u d a b u d u sam o n a sp o ljn o m n iv ou
klase, o d n o sn o n estatin a u n u tra n ja klasa ne m o e d a im a stati n e p o d atk e , statina
polja niti statin e u n u tra n je klase. M e u tim , u g n e e n e (statin e u n u tra n je ) klase
m o g u sve to da sadre:
//: unutrasnjeklase/Posiljkall.java
// Ugneene klase (statine unutranje klase)
2 O tprilike slino u gne enim klasam a u C + + -u , sem to te klase ne m o gu p ristu p a ti priv atn im la-
n ov im a kao u Javi.
Poglavjje 10: Unutranje klase 283
//: unutrasnjeklase/KlasaLIInterfejsu.java
// {main: K1asaUInterfejsu$Test}
//: unutrasnjeklase/PristupPriVisestrukomllgnezdjivanju.java
// Ugneene klase mogu da pristupe svim lanovima
// na svim nivoima klasa u koje su ugneene.
class PVU {
private void f() {}
class A {
private void g() {}
1 Jo je d n o m z a h v a lju je m M a r tin u D a n e ru .
Poglavlje 10: Unutranje klase 285
public class B {
void h() {
g();
f0;
}
}
}
}
public class PristupPriVisestrukomUgnezdjivanju {
public static void m a i n (String[] args) {
PVU pvu = new P V U () ;
PVU.A pvua = pvu.new A();
PVU.A.B pvuab = pvua.new B();
pvuab.h();
}
} ///= -
D a b ism o ovo d etaljnije p ro u ili, ra z m o trim o situ aciju u kojoj im a m o dva interfejsa
koja nekako m o ra m o d a realizu jem o u jed n o j klasi. Z b o g fleksibilnosti interfejsa m o ete
da b irate je d n u o d dve m o g u n o sti: je d n a klasa ili u n u tra n je klase:
interface A {}
interface B {}
class X implements A, B {}
class Y implements A {
B napraviB() {
// Anonimna unutranja klasa:
return new B() {};
}
}
public class Visestrukilnterfejsi {
static void uzimaA(A a) {}
static void uzimaB(B b) {}
public static void main(String[] args) {
X x = new X ();
Y y = new Y ( ) ;
u z i m aA (x );
uz i m a A ( y ) ;
uz i m a B ( x ) ;
uz im aB (y .n ap ra vi B( ));
}
} lll--~
//: unutrasnjeklase/VisestrukaRealizacija.java
// Ako su u pitanju konkretne ili apstraktne klase unutranje klase su
// jedini nain za dobijanje efekta "viestrukog nasleivanja realizacij e " .
package unutrasnjeklase;
class D {}
abstract class E {}
class Z extends 0 {
E napraviE() { return new E() {}; }
}
Poglavlje 10: Unutranje klase 287
//: un utrasnjeklase/PovratniPozivi.java
// Upotreba unutranjih klasa za povratne pozive
package unutrasnjeklase;
import static n e t . mi nd vi ew .u ti l.Print.*;
interface MozeDaSePoveca {
void povecaj();
}
class MojaPovecaj {
public void povecaj() { print("Druga operacija"); }
static void f(MojaPovecaj mp) { m p . p o v e c a j (); }
}
MozeDaSePoveca uzmiReferencuZaPovratm'Poziv() {
return new Z a k l j u c a k O ;
class Poziva {
private MozeDaSePoveca referencaZaPovratniPoziv;
Poziva(MozeDaSePoveca cbh) { referencaZaPovratniPoziv = cbh; }
void kreni() { referencaZaPovratniPoziv.povecaj (); }
}
//: unutrasnjeklase/upravljac/Upravljac.java
// Generiki kostur za sve upravljake sisteme.
package unutrasnjeklase.upravljac;
import j a va .u ti1 .* ;
if(d.spreman()) {
S y s t e m . o ut .p ri nt ln (d);
d.akcija();
1 i s t a D o g ad ja ja .r em ov e(d );
}
}
} III--
M eto d a pokreni( ) k ru i k ro z k o p iju listeDogadjaja, traei Dogadjaj koji je spre-
man( ) za p o k re tan je . Z a svaki Dogadjaj koji je spreman( ), isp isuju se p o d aci objek-
tov om m e to d o m toStrin g( ) i poziv a m eto d a akcija( ). Z atim se Dogajaj uklanja iziiste.
U viate d a za sad a ne zn ate n ita o to m e ta tano klasa Dogadjaj radi. To i jeste sr
ovog p o stu p k a; k ako razdvaja o n o to se m en ja o d o n o g to o staje isto . O d n o sn o , da is-
k o ristim svoj te rm in , vektor p ro m e n e p red stav lja razliite akcije razliitih v rsta objeka-
ta klase Dogadjaj koje definiete pravei razliite p o tk lase za dogadaje.
N a o v o m m e s tu n a scen u stu p a ju u n u tra n je klase. O n e o m o g u a v a ju dve stvari:
1. C elu realizaciju p ro g ram a koji upotreb ljav a k o stu r u pravljanja m oete da sm estite u
je d n u klasu, im e kap su lirate sve to je za tu realizaciju p o treb n o . U n u tran je klase se
up o treb ljav aju d a iskau vie razliitih akcija koje su p o tre b n e za reavanje problem a.
2. U n u tra n je klase p o je d n o sta v lju ju o v u realizaciju, a vi ste u m o g u n o sti d a lako
p ristu p ite la n o v im a sp o ljn e klase. Bez ov ih m o g u n o sti, p ro g ra m bi m ogao da
p o sta n e to lik o k o m p lik o v an a a biste m o rali d a p o tra ite altern ativ u .
R a z m o trim o je d n u realizaciju k o stu ra u p rav lja n ja k oja u p rav lja fu n k cijam a staklene
bate.4 Svaka akcija je p o tp u n o razliita: paljen je svetla, uklju iv an je vode i term o stata,
ukljuivanje zv o nca i p o n o v n o p o k re ta n je sistem a. K o stur u p rav ljan ja o m o g u u je d a se
taj razliiti k od lako razdvaja. U n u tra n je klase o m o g u av aju da p o m o u sam o jed n e kla-
se n a p ra v ite vie izvedenih verzija o sn o v n e klase D o g a d ja j. Za svaki tip akcije napraviete
nov u u n u tra n ju klasu izvedenu iz klase D o g ad ja j i k o d za u p rav ljan je n apisati u n u ta r
m e to d e ak cija( ).
Kao to je za k o stu r u p rav ljan ja u o b iajen o , klasa U p ra v Ija n je S ta k le n o m B a sto m je
izvedena iz Idase U p rav ljac:
P rom enljive svetlo, voda i term ostat p rip a d a ju sp o ljn o j klasi UpravljanjeStaklenom-
Bastom, a ipak u n u tra n je klase m o g u d a im p ristu p e bez u p o tre b e k valifikatora i bez p o -
sebn ih dozvola. U stv a rn o m p ro g ra m u , veina m eto d a ak cija( ) bi ukljuivala n eku vrstu
up rav ljan ja h ard v ero m .
Poglavlje 10: Unutranje klase 295
Veina klasa izvedenih iz klase Dogadjaj sline su, ali se klase Zvono i Restart izdvajaju.
Klasa Zvono pokree zvonce i u listu dogaaja dodaje jo jed an objekat klase Zvono, tako
da e p o n o v o zazvoniti neto kasnije. O b ra tite p a n ju na to da u n u tran ja klasa izgleda go-
tovo kao v iestruko nasleivanje: klasa Zvono im a sve m eto d e kao i klasa Dogadjaj, a ta-
koe izgleda kao da im a i sve m eto d e spoljne klase UpravljanjeStaklenomBastom.
Klasa Restart do b ija niz objek ata Dogadjaj koje d od aje upravljau. Poto je Restart
sam o jo je d n a v rsta klase Dogadjaj, u m eto d i Restart.akcija( ) u listu takoe m oete da
d o d a te i o bjekat klase Restart, kako bi se sistem s v rem en a n a v rem e po no vo p o k ren u o .
N a red n a klasa kon fig u rie sistem tako to p rav i o bjek at klase UpravljanjeStaklenom-
Bastom i d o d ajte razn e v rste obj'ekata Dogadjaj. O vo je p rim e r p ro je k tn o g ob rasca C om -
m a n d (n a re d b a ) - svaki o b jek at klase listaDogadjaja jeste zah tev kap su liran kao objekat:
c la s s ImaUnutrasnju {
cla s s Unutrasnja {)
1
public c la s s NaslediUnutrasnju extends Im aUnutrasnju.Unutrasnja {
//! N aslediU nu trasn ju() { } // Ne moe da se prevede
NaslediUnutrasnju(Im aUnutrasnju iu ) {
iu .su p e rO ;
}
p ub lic s t a t ic void m a in (S trin g [] args) {
ImaUnutrasnju iu = new ImaUnutrasnju ( ) ;
NaslediUnutrasnju i i = new N a s le d iU n u tra s n ju (iu );
}
} III--
Poglavlje 10: Unutranje klase 297
c la s s J a j e {
p riv a te Zumance z;
protected c la s s Zumance {
p u b lic Zumance() { p r in t("Ja je .Z u m a n c e ()" ) ; }
}
public J a j e ( ) {
p r i nt("Novo J a j e ( ) ) ;
z = new Zumancef);
}
}
c la s s Ja je 2 {
p rotecte c la s s Zumance {
p u b lic Zumance{) { p rin t("Ja je 2 .Z u m a n c e ()" ) ; }
p u b lic void f ( ) { p r in t("Ja je 2 .Z u m a n c e .f()" ) ; }
}
p riv a te Zumance z = new ZumanceO;
publ ic J a je 2 () { print("N o vo J a j e 2 ( ) " ) ; }
p u b lic void ubaciZumance(Zumance zz) { z = zz; }
p u b lic void g () { z . f ( ) ; }
}
in te rfa c e Brojac {
in t n e x t();
return new L o k a ln iB ro ja c ( ) ;
}
// Is to sa anonimnom unutranjom klasom:
B rojac L o k a ln iB ro ja c 2 (fin a l Strin g ime) {
return new B ro ja c () {
// Anonimna unutranja klasa ne moe imati imenovani
// konstruktor, nego samo i n i c i j a l i z a t o r in stan ce:
{
pri nt ("B r o ja c O " ) ;
}
public in t nex t() {
p rin tn b (im e ); // Pristu p an je lo k aln o j fin a ln o j
return broj++;
}
};
}
p u b lic s t a t ic void m a in (S trin g [] args) {
LokalnaUnutrasnjaKlasa l i c = new Lo k a ln aU n u trasn jaK la sa();
300 Misliti na Javi
Brojac
cl = 1 ic.uzmiBrojac("Lokalna unutranja "),
c2 = 1 ic.uzmiBrojac("Anonimna unutranja ");
for(int i = 0; i < 5; i++)
p r i n t( cl .n ex t( ));
for(int i = 0 ; i <5; i++)
p r in t( c2 .n ex t( ));
}
} /* Ispis:
LokalniBrojac()
Brojac()
Lokalna unutranja 0
Lokalna unutranja 1
Lokalna unutranja 2
Lokalna unutranja 3
Lokalna unutranja 4
Anon im na unutranja 5
Anonimna uriutranja 6
An on im na unutranja 7
Anon im na unutranja 8
Anonimna unutranja 9
* ///:-
Bro jac.class
LokalnaUnutrasnjaKlasa$l. c l ass
Lokal naUnutrasnjaKlasa$lLokalniBrojac.class
LokalnaUnutrasnjaKlasa.klasa
Poglavlje 1 Unutranje klase 301
Saetak
Interfejsi i u n u tra n je Jdase n a p re d n iji su k o n cep ti o d on ih ii p o sto je u m n o g im O O P
jezicim a. N a p rim er, u C ++-U ne p o sto ji nita nalik njim a. ( i zajed no reavaju isti p ro -
b lem koji je i C + + p o k u ao d a rei p o m o u v iestru ko g nasieivanja. Isp ostavilo se d a se
u C + + -u v iestru k o nasleivanje p rilin o teko upotreb ljava, d o k su Javini in terfejsi i
u n u tra n je Iase m n o g o p ristu p an iji.
Iako su te m o g u n o sti p rilin o jasne, n jih o v a u p o tre b a je 1 f anje pro je k to v an ja, p o p u t
p o lim o rfiz m a. S v re m e n o m ete sve b olje p rep o zn av ati situa c u k o jim a tre b a da k ori-
stite in terfe js ili u r.u tra n ju klasu, ili i je d n o i d ru g o isto v re ire U o v o m tre n u tk u , bilo
bi d o b ro d a p o zn ajete b a re m n jih o v u sin tak su i sem an tik u. 1 o se b u d e te sretali sa nji-
m a, sve vie ete ih prih v atati.
Reenja odabranih vebi data su u elektronskom dokum entu Thin 1ln Java A n n o ta ted S olu-
tions G uide, koji se moe kupiti na lokaciji www.MindView.net.
MojaKlasa referenca
c la s s Jabuka (
p riv a te s t a t ic long b ro jac;
p riv a te fin a l long id = brojac++;
p ub lic long id ( ) { retu rn id ; }
}
c la s s Narandza {}
O v d e bi d o b r o d o lo p re k la p a n je o p e ra to ra . K o n te jn e rsk e k la se u je z ic im a C + + i C # p ro iz v o d e istiju
s in ta k s u z ato to se u p o tre b lja v a p re k la p a n je o p e r a to r a .
304 Misliti naJavi
( ( Ja b u k a )ja b u k e .g e t (i)). i d ( ) ;
// Narandza se o tk riv a tek p rilik o m iz vravan ja
}
} /* (Po k re n ite da b is te v id e li r e z u lta t) * / / / -
p ublic c la s s JabukelNarandzePoinocuGenerickihTipova {
p ub lic s t a t i c void m a in (S trin g [] args) {
ArrayList<Jabuka> jabuke = new A rrayList< Ja b u k a > ();
f o r ( i n t i = 0 ; i < 3 ; i++)
jabuke.add(new Ja b u k a O );
// Greka koja se p r i j a v l j u j e u vreme prevoenja:
// jabuke.add(new N arandzaO );
f o r ( i n t i = 0; i < j a b u k e .s iz e ( ) ; i++)
S y ste m .o u t.p rin tl n (jab uk e.g et ( i ) . i d ( ) ) ;
// Sintaksom foreach:
fo r(Jab u k a c : jabuke)
S y s t e m .o u t .p r in t ln ( c .id ( )) ;
}
} /* Is p is :
0
1
2
0
1
2
* ///:-
Sada e p revo d ilac spreiti stavljenje o b jek ta tip a N a ra n d /a m e u ja b u k e , p a e se ta
greka p rijav iti u v rem e p rev o en ja, a ne u v rem e izvravanja.
O b ra tite p a n ju i na to da p rilik o m v a en ja stavki iz Liste vi e nije p o tre b n o svoenje
tip o v a. P oto Lista zna koji tip sadri, o n a obavlja svoenje k a<ta vi pozovete g et(). D akle,
ne sa m o da p rev o d ilac zbog gen erik ih tip o v a p roverava tip o b jek ata koji stavljate u ko n -
tejn er, nego je i sintaksa p rilik o m u p o tre b e objek ata u n jem u istija.
P rim e r p o k azu je i sledee: ako v am ne tre b a in d ek s svakop (lem en ta, za izb o r svakog
ele m e n ta u Listi m oete u p o tre b iti sin tak su foreach.
K ada tip o b jek ta u k o n te jn e ru zadate kao g eneriki p ara m t ir, ne m o ra te u k o n te jn e r
stavljati sa m o taj tip, p o to svoenje navie rad i i s gen erik im p o v im a kao i sa o stalim
tip o v im a:
//: cuvanje/GenerickiTipoviISvodjenjeNavise.java
import java.util
Osnovni pojmovi
Kontejnerska b iblioteka Jave 2 obavlja z ad a tak uvanja objek ata" i deli ga u dva zasebna
pojm a, izraena u o b lik u o sn o v n ih in terfe jsa bibliote'ke:
1. Collection (kolekcija): g ru p a p o je d in a n ih e lem en ata na koje je esto p rim en jen o
jedno ili vie pravila. List (lista) m o ra d a uva elem ente u o d re e n o m redosledu, Set
(skup) ne m oe da sadri p o n o v ljen e elem ente, a Queue (red) daje elem ente red o m
koji zadaje disciplina ekanja (o b in o istim red o m kojim su elem enti u m etan i).
2. Map (mapa): g ru p a p aro v a o b je k a t-k lju , koja o m o g u av a p ro n alaen je objekta
p om ou njegovog kljua. ArrayList o m o g u av a p ro n alaen je objekta p o m o u nje-
govog indeksa, pa n a neki n ain p rid ru u je brojeve o b jek tim a. M apa om oguava
pronalaenje objekta p o m o u n je m u p rid ru e n o g drugog objekta. N ju nazivaju i
asocijativan niz, zato to objekte aso cira (p rid ru u je ) d ru g im o b jek tim a, ili renik,
zato to objekat trai p o m o u kljua, k ao to se u reniku definicija trai p o m o u
rei. Mape su m o n e p ro g ra m sk e alatke.
Iako to nije uvek m ogue, bilo bi id ealn o da vei d eo vaeg k oda rad i s tim interfejsim a,
a da jedino m esto na kojem ete sp o m e n u ti taan tip koji u p o treb ljav ate b u d e m esto pra-
vljenja instance. Dakle, ovako m o ete n a p ra v iti Listu:
/ / : cu vanje/JednostavnaKolekcij a . ja va
import j a v a . u t i l
P oto se u o v om p rim e ru u p o treb ljav aju sam o m eto d e interfejsa Collection, o dgova-
rao bi svaki ob jek at klase nasle en e o d to g in terfejsa, ali ArrayList predstavlja najosno v-
niji tip sekvence.
Im e m e to d e add() n av o d i na p o m isa o d a o n a u kolekciju (Collection) d o d aje n o v ele-
m e n t. M e u tim , u d o k u m e n ta c iji je p recizn o naved en o da add() ini d a ovaj p rim e ra k
klase C ollection sadri d a ti e le m e n t. To je u ra e n o zbog sk u p a (potklase Set), koji ele-
m e n t d o d a je kolekciji sam o ukoliko se o n ta m o ve n e nalazi. U sluaju klase ArrayList i
svih vrsta Listi, add() uvek znai ,,d o d ati, p o to Liste dozvoljavaju p o stojan je d u p lik ata.
K roza sve kolekcije m o ete p rolaziti sin ta k so m foreach, kao u p re th o d n o m p rim e ru .
U n astav k u poglavlja n au iete da u p o treb ljav ate fleksibilniji Iterator.
Veba 2: (1 ) Izm enite p ro g ra m JednostavnaKolekcija.java tako da se za c upotrebljava Set.
Veba 3: (2) Izm en ite p ro g ra m unutrasnjeklase/Sekvenca.java tako da m u m oete d o -
dati p ro izvoljan bro j elem en ata.
//: cuvanje/DodavanjeGrupa.java
// Dodavanje grupa elemenata objektima tip a C o lle c tio n .
import j a v a . u t i 1.* ;
p u b lic c la s s DodavanjeGrupa {
p u b lic s t a t i c void m a in (S trin g [] args) {
C o l1ection<Integer> k o le k c ija =
new A rra y L is t< In te g e r> (A r ra y s .a s L is t(l, 2, 3, 4, 5 )) ;
308 Misliti na Javi
/ / : cuvanje/KaoNekakvaLista.java
// A rr a y s .a s L is t () samo nagaa o kojem se tip u ra d i.
import j a v a .u t il
class Sneg {}
c la s s Prsac extends Sneg {}
c lass Slab extends Prsac {}
c la s s Krupan extends Prsac { }
c la s s Krpe extends Sneg {}
c lass S lo ta extends Sneg { }
pu b lic c la s s KaoNekakvaLista {
p ub lic s t a t ic void m a in (S trin g [] args) {
List<Sneg> snegl = A r r a y s .a s L is t (
new K rp e (), new S l o t a ( ) , new P r s a c ( ) ) ;
// Nee se p r e v e s t i:
// List<Sneg> sneg2 = A r r a y s .a s L is t (
// new S la b ( ) , new K ru p a n (j);
Poglavlje 11: uvanje objekata 309
public c la s s Is p is iv a n je K o n te jn e ra {
s t a t ic C o lle c tio n popuni(C ollection< String> k o le k c ija ) {
kolekci ja.add C 'pacov'1) ;
kolekci ja.a d d C 'm a k a ");
kolekci ja .a d d C 'k u e ");
k o le k c ija .a d d ("k u e ");
return k o le k c ija ;
}
s t a t ic Map popuni(Map mapa) {
mapa.put C'pacov'1, "Zb u n jen i" ) ;
mapa.put("maka , "M ica'1) ;
m apa.put("kue", " L e s i " ) ;
310 Misliti na Javi
m apa.put(''kue", B o b i");
return mapa;
}
p u b lic s t a t ic void m a in (S trin g [] args) {
print(popuni(new A rrayList< Strin g> ( ) ) ) ;
print(popuni(new L in k e d L is t< S tring> ( ) ) ) ;
p rin t(p o p u n i(new HashSet<String> ( ) ) ) ;
print(popuni(new TreeSet<String> ( ) ) ) ;
print(popuni(new LinkedHashSet<String> ( ) ) ) ;
print(popuni(new HashMap<String, String> ( ) ) ) ;
p rin t(p o p u n i(new TreeMap<String, String> ( ) ) ) ;
print(popuni(new LinkedHashMap<String, String> ( ) ) ) ;
}
} /* Is p is :
[pacov, maka, kue, kue]
[pacov, maka, kue, kue]
[kue, maka, pacov]
[pacov, maka, kue]
{kue=Bobi, maka= M ica, pacov=Zbunjeni}
{maka= Mica, kue=Bobi, pacov=Zbunjeni}
{pacov=Zbunjeni, maka= M ica, kue=Bobi}
* ///:-
b re vaenje elem enata, iako red o sled njegovog skladitenja izgleda b esm islen (esto je
vano sa m o da li je objek at lan o d re en o g sk u p a iz kategorije Set, d o k redo sled elem en a-
ta u to m sk u p u n em a znaaja). A ko je p o re d a k skladitenja vaan, m o ete u p o tre b iti
TreeSet koji objekte uva u rastu e m p o re tk u p o re en ja, ili LinkedHashSet koji ih uva
u re d o sle d u kojim su bili u m etan i.
M ap a (koja se naziva i asocijativan niz) o m o g u av a p ro n alaen je o b jek ta p o m o u nje-
govog kljua, kao u jed n o stav n o j bazi p o d atak a . O b jek at p rid ru e n k lju u jeste njegova
vrednost. U koliko im ate M a p u u kojoj su im e n a drava p rid ru e n i im e n im a n jih o v ih
glavn ih g rad ova i elite d a saznate koji je glavni g ra d G ruzije, p retraiv an je ob avljate p o -
m o u kljua ,,G ruzija - gotovo kao da je u p ita n ju indeks niza. Z bog takvog p o n aan ja
M ap a p rih v ata sam o po jed an p rim e ra k svakog kljua.
Map.put(klju, vrednost) u m ee u m a p u v re d n o st (o n o to hoete d a u sk lad itite) i
p rid ru u je je o re e n o m k lju u (p o m o u kojeg ete tu v re d n o st p ro n ai).
Map.get(klju) daje v red n o st p ri ru e n u d a to m kljuu. U g o rn je m p rim e ru sa m o su d o -
davan i p aro v i k lju -v re d n o st, je r p retraiv an ja n ije bilo. To e b iti p o k a zan o kasnije.
Im a jte u v id u da ne m o ra te zad ati veliinu M ap e (n iti se za to u o p te starajte), je r o n a
svoju veliinu podeava a u to m atsk i. P o red toga, M ap e sam e u m e ju d a isp iu svoj sadraj,
pri e m u se p rik azu ju p arovi k lju -v re d n o st. U M a p am a se kljuevi i v re d n o sti ne uvaju
u o n o m p o retk u kojim su u m e ta n i, zato to realizacija tip a H a sh M a p u p o treb ljav a veom a
brz alg o ritam koji o d re u je taj p oredak.
U p rim e ru su u p o treb lje n a tri o sn o v n a tip a Mapa: HashMap, TreeMap i Linked-
HashMap. Kao i HashSet, HashMap o b ezb edu je n ajb ru te h n ik u p retraiv an ja; takoe,
ni ta m a p a ne uva svoje elem en te u lako razu m ljiv o m p o retk u . U m ap i tip a TreeMap
kljuevi su p o re a n i u ra stu em p o re tk u , a u m a p i tip a LinkedHashMap u p o re tk u u m e-
tan ja, p ri e m u je zad ran a b rz in a p retra iv a n ja tip a HashMap.
Veba 4: (3) N apravite generatorsku klasu koja vraa im ena (kao objekte tipa String) likova
vaeg o m iljeno g film a (ili Sneane i sedam p atuljaka ili Ratova zvezda, nije vano) svaki p u t
kada pozovete next(), i vraa se na p o eeta k liste sa im en im a likova kada d o e d o n jen og
kraja. U p o treb ite taj g e n erato r za p o p u n ja v an je o b in o g niza i po jed n o g p rim e rk a tipova
ArrayList, LinkedList, HashSet, LinkedHashSet i TreeSet. Z atim ispiite sadraj svakog
od tih kontejnera.
Liste
Liste uv aju elem en te u o d re e n o m p o retk u . Interfejs List kategoriji C ollection do aje
vie m e to d a za u m e ta n je i uklan jan je elem enata iz sred ine Liste.
Postoje dva tip a Liste:
O sn o v n i tip, ArrayList, izv rstan je za p ristu p a n je elem en tim a n a su m i n im red o-
sled o m , ali je sporiji p rilik o m u m eta n ja i u k lan jan ja elem en ata iz sred in e Liste.
T ip LinkedList o b ezb e u je o p tim a la n sekvencijalni p ristu p , a ni u m e ta n je i ulda-
n jan je elem enata iz sred in e Liste ne kota m n o g o . LinkedList je relativ no sp o r p ri-
likom p ristu p a n ja elem en tim a n a su m in im red o sled om , ali su njegove m o g u n o sti
vee nego o ne tip a ArrayList.
312 Misliti na Javi
Iteratori
U svakoj kon tejn ersk o j klasi m o ra p o sto jati n ain d a se elem enti d o d a ju i izvade. O sn o v n i
za d atak k o n te jn e ra i jeste da n eto sadri. U klasi List, o b jek ti se u m e u m eto d o m a d d (),
a m eto d a g e t ( ) je jed an o d n ain a da se pro itaju.
Ako p o n ete da razm iljate na viem niv o u o k o n tejn ersk o j biblioteci, pojavljuje se je-
d a n n e o statak : m o ra te ta n o zn ati tip k o n tejn era d a biste ga koristili. To na prv i po gled
ne izgleda loe, ali ta ako n ap iete k o d za Listu, a kasnije o tk rijete da bi isti k o d treb alo
da p rim e n ite na sk u p (Set)? Ili, p rim e ra radi, elite da nap iete generiki kod koji ne zna
(ili m u nije b itn o ) s kojim tip o m k o n tejn era radi, kako biste m ogli da ga koristite s razli-
itim tip o v im a k o n te jn e ra a d a ga pri to m n e piete ponovo?
O vakva apstrak cija se p o stie k o rien je m iteratora (i to je p ro je k tn i obrazac). Ite ra to r
je o bjek at iji je zad atak da se p o m e ra kroz niz o b jek ata i d a izabere svaki o bjek at u to m
n izu, p ri em u p ro g ra m e r k lijent ne zna (ili m u nije vano) kakva je s tru k tu ra tog niza.
P ored toga, ite ra to r se o b i n o naz.iva lak o b jek at (engl. light-w eight), je r koristi m alo re-
sursa. Z b o g toga ete za iterato re esto v iati naizgled u d n a o g ran ien ja; na p rim er, Ja-
vin Iterator m oe da se kree sa m o u je d n o m sm e ru . Sa ite ra to ro m ne m oete b o gzn a ta
da rad ite, o sim da:
1. Z a tra ite o d k o n te jn e ra da vam m e to d o m iterator( ) p ro sledi Iterator. D obijeni
Iterator je sp re m a n da v ra ti prv i elem en t niza posle prv og poziva njegove m eto d e
n e x t().
2. D obijete sledei o b jek at u n izu p o m o u m e to d e n e x t().
316 Misliti na Javi
3 . U stanovite da li im a j o ob jekata u n iz u p o m o u m e to d e h a s N e x t( ).
4. U k io n ite posled nji elem en t koji je ite ra to r v ra tio p o m o u m e to d e r e m o v e ( ).
D a b ism o videli kako o n radi, o p e t e m o u p o tre b iti kJasu P et i n jen e m e to d e , o p isan e
u poglavlju Podaci o tipu:
rem ov e() spada u takozvane o p cio n e m etod e (im a ili jo), to znai da je ne m o raju realizovati sve
realizacije Ite ra to ra . O tom e govorim o u poglavlju Detaljno raztnatranje kontejnera. Kako svi stan-
d ard ni kon tejn eri Java biblioteke realizuju rem o v e(), o tom e ne m o rate da b rin ete fdok ne dodete do
sp o m e n u to g poglavlja).
Poglavlje I 1; uvanje objekata 317
U oili ste d a m eto d a ispisiS ve() nita ne zna o vrsti sekvence kroz koju prolazi, a to po-
kazuje p rav u sn ag u Ite ra to ra : m o g u n o st da razdvoji o p eraciju pro laska kroz sekvencu
o d njen e stru k tu re . Z ato se k atk a kae da ite ra to ri objedinjuju pristup kontejneritna.
V eba 8: (1) P repravite vebu 1 tako da se za k reta n je kroz L istu u p o tre b lja v a Ite ra to r
kada se pozove skoci().
V eba 9: (4) P repravite p ro g ram u n u tra sn je k la se /S e k v e n c a .ja v a tako da S ekvenca radi
sa Ite ra to ro m u m esto sa S electo ro m .
V eba 10: (2) P repravite vebu 9 iz poglavlja P olim orfizam tako da se G lo d a ri uvaju u Ar-
ray L isti i da se za k retan je kroz niz G lo d a ra u p o tre b ljav a Ite ra to r.
V eba 11: (2) N apiite m e to d u koja u p o treb ljav a I te r a to r za p ro lazak kroz k o n tejn er (ob-
jekat tipa C o lle c tio n ). M e to d o m to S trin g O ispiite sadraj svih o b jekata u k o ntejneru .
P o p u n ite o b je k tim a sve vrste k o n tejn era i n a svaki o d njih p rim e n ite svoju m eto d u .
318 Misliti na Javi
Listlterator
Za liste p o sto ji n a p red n iji iterato r, Listlterator. D ok se Iterator m oe p o m e ra ti sam o
u n a p re d , Listlterator je d v o sm eran . T akode, u m e da pro izv ed e indekse sledeeg i p re t-
h o d n o g elem e n ta u o d n o su n a m esto n a koje ite ra to r p ok azu je u listi, kao i d a m e to d o m
set() z a m e n i p o sled n ji e lem en t koji je p osetio. P ozivom m e to d e listIterator() nap rav iete
Listlterator koji p ok azu je n a p o eta k Liste, a zadavanjem arg u m e n ta n (kao u listltera-
tor(n)) nap ra v ie te Listlterator koji p o inje p o k azu ju i n a in d eks n u listi. Evo p rim e ra
u k o jem su p o k az an e sve n av ed ene m o gu n osti:
//: c u v a n je / Ite ra c ij a L i s t e . ja va
import ty p e in fo .p e ts .* ;
import j a v a . u t i l .* ;
p u b lic c la s s It e r a c i ja L is t e {
p u b lic s t a t i c void m a in (S trin g [] args) {
List<Pet> 1jubimci = P e t s .a r r a y L is t ( 8 ) ;
Lis tIte ra to r< P e t> i t = 1ju b im c i.1 i s t I t e r a t o r ( ) ;
w h i1 e (it.h a s N e x t())
S y s t e m .o u t .p r in t(it.n e x t () + " , + it.n e x tln d e x () +
" , " + it.p r e v io u s In d e x () + " ; " ) ;
S y s te m .o u t .p r in tln ();
// Unazad:
whi1e ( i t.h a s P re v i ous( ) )
S y s t e m .o u t .p r in t (it .p r e v io u s ( ).id ( ) + " " ) ;
S y s te m .o u t .p r in tln ();
S y s te m .o u t.p rin tln (lju b im c i);
i t = 1ju b im c i.1 i s t I t e r a t o r ( 3 ) ;
w h ile (it.h a s N e x t ()) {
it .n e x t ();
i t . s e t ( P e t s . randomPet( ) ) ;
}
S y s te m .o u t.p rin tln (lju b im c i);
}
} /* Is p is :
Rat, 1, 0; Manx, 2, 1; Cymric, 3, 2; Mutt, 4, 3; Pug, 5, 4; Cymric, 6,
5;
Pug, 7, 6; Manx, 8, 7;
7 6 5 4 3 2 1 0
[R a t, Manx, Cymric, Mutt, Pug, Cymric, Pug, Manx]
[R a t, Manx, Cymric, Cymric, Rat, EgyptianMau, Hamster, EgyptianMau]
* ///:-
Ulanana lista
I klasa LinkedList realizuje osn o v n i interfejs List kao ArrayList, ali o d re e n e o p eracije
(u m e ta n je u sre d in u Liste i uklan jan je iz nje) obavlja efikasnije n ego ArrayList. S d ru g e
stra n e , m an je je efikasna za o p eracije p ristu p a n ja nesekvencijalnim red o sled o m .
LinkedList d o d aje i m e to d e koje o m o g u av aju d a je u p o tre b im o kao stek, k ao red za
ekanje (Queue) iii d v o stra n i red za ekanje (engl. double-ended queue, deque).
N eke o d ovih m e to d a su p se u d o n im i (alijasi) ili m e d u so b n e n e z n a tn e varijacije, d a bi
se o b ila im en a p o z n ata u k o n tek stu o d red en e u p o tre b e (n a ro ito u re d o v im a ek an ja).
N a p rim er, getFirst() i elem ent() iden tin e su - o n e vraaju elo (p rv i elem en t) liste, a da
ga ne u k lo n e, i gen eriu izuzetak NoSuchElementException ako je Lista p razn a. M eto d a
peek() je n jihov a varijacija koja vraa null ako je lista p razn a.
Id e n ti n e su i m eto d e removeFirst() i remove() o n e u k lan jaju i v raaju kao rezu ltat
elo liste, i g eneriu izuzetak NoSuchElementException ako je lista p raz n a, d o k n jih ov a
varijacija poll() 11 to m sluaju vraa null.
addFirst() um ee elem en t n a p o etak liste.
offer() je ista kao add() i addLast(). Sve o n e d o d aju e lem en t na rep (kraj) liste.
removeLast() uklanja i vraa poslednji elem en t liste.
N ared n i p rim e r p ok azu je o snovne slinosti sp o m e n u tih m eto d a i razlike iz m e d u njih.
U n je m u se ne ponavlja p o n aan je p rik azan o u p ro g ra m u MogucnostiListe.java:
p u b lic c la s s Stack<T> {
p riv a te LinkedList<T> s k la d is te = new L i nkedList<T> ();
p u b lic void push(T v) { s k la d is te .a d d F ir s t ( v ) ; }
p u b lic T peek() { return s k l a d i s t e . g e t F i r s t ( ) ; }
p u b lic T pop() { return s k la d is te .re m o v e F irs t( ) ; }
p u b lic boolean empty() { return s k la d is te .is E m p ty ( ) ; }
p u b lic S trin g to S trin g O { return skl adi s te . to S tr i ng ( ) ; }
} ///:-
p u b lic c la s s StekTest {
p u b lic s t a t ic void m a in (S trin g [] args) {
Stack<String> stek = new S tack < Strin g > ();
fo r (S t r in g s : "Moj pas ima buve". s p li t (" ) )
s t e k .p u s h (s );
w hi1e ( ! stek.em pty( ) )
System .out. p r i n t ( s t e k .pop() + " " ) ;
}
} /* I spi s :
buve ima pas Moj
* ///:-
U koliko u svom k o d u h o ete da u p o tre b ite ovu klasu Stack, m o raete p o tp u n o da spe-
cificiratc n jen paket - ili p ro m e n ite im e klase kada je b u d e te pravili; u p ro tiv n o m , vero -
v a tn o ete izazvati suk o b s klasom Stack iz pak eta java.util. P rim e ra radi, ukoliko u g ornji
listing uvezem o ja v a .u til.* , m o ra e m o da u p o treb ljav a m o im en a p aketa kako b ism o
spreili d v o sm islen o st im en a i sukobe:
//: cuvanje/StekSukob.java
import n e t.m in d v ie w .u til.* ;
p u b lic c la s s StekSukob {
p u b lic s t a t ic void main (S tr in g [] args) {
n e t.m indview .u t i 1. Stack< String> stek =
322 Misliti na Javi
O b e klase Stack im aju isti interfejs, ali u p ak e tu java.util ne p o sto ji zaje dn iki interfejs
Stack - verovatno zato to je o rig in a ln a, loe p ro jek to v an a klasa java.util.Stack u Javi 1.0
usvojila to im e. Iako java.util.Stack p osto ji, LinkedList p ravi bolji stek, p a p re d n o s t treb a
dati p ristu p u o stv aren o m u pak etu net.mindvievv.util.Stack.
Izb o r realizacije klase Stack kojoj treb a dati p re n o s t in oete k o n tro lisa ti eks-
p licitn im uvozom :
Sada e svako upu iv an je na klasu Stack izabrati verziju net.m indview .util, a da biste
izabrali java.util.Stack, m o ra te u p o tre b iti p o tp u n o im e koje o b u h v a ta i im e paketa.
Veba 15: (4) U p ro g ram sk im je z i m a stekovi se esto u p o treb ljav aju za izraun avan je
v red n o sti izraza. Izrau n ajte sledei izraz koristei paket net.m indview.util.Stack, gde +
znai stavite n a stek sledee sIovo, a - zn ai skinite v rh steka i ispiite ga:
,,+ U + n + c t e + r + t + a -+ i-+ n + t+ y ---- 1- - + r + u + l+ e + s
Funkcionalnost skupa
Skup (Set) ne m o e da sadri vie o d je d n e in stan ce v re d n o sti objekta. U k oliko p ok u ate
da d o d ate vie od je d n e instance ekviv alen tno g objekta, Set e spreiti d u p liran je . Set se
najee u p otreb ljav a za u tv rd iv an je p rip a d n o sti, pa je lako saznati da li je o d re e n i o b -
jek at u o d re d e n o m sk u p u . Z ato je za Set pretraiv an je o b i n o najvanija o p eracija, pa se
najee b ira realizacija HashSet, o p tim iz o v an a za b rz o pretraiv anje.
Set (sku p ) im a isti interfejs kao Collection, to znai da nem a d o d a tn ih fu nk cija kao
to im aju dve razliite liste. S kup je isti kao kolekcija, sam o se razliito p o n aa. (O vo je
p rim e r savrenog korienja n asledivanja i p o lim o rfizm a: za izraavanje d rug aijeg po-
n aanja.) Set u tv r u je p rip a d n o st na o sn o v u ,,v red n o sti objekta. O b jan je n je o d ega se
sastoji v re d n o st objekta sloeno je, kao to ete v ideti u poglavlju D etaljno razm atranje
kontejnera.
Poglavlje I 1: uvanje objekata 323
p ub lic c ia s s SkupCelihBrojeva {
p u b lic s t a t ic void m a in (S trin g [] args) {
Random slu cajan = new Random(47);
Set<Integer> skupcelihb = new H ashSet< Integer> ();
f o r ( i n t i = 0; i < 10000; i++)
sk u p c e lih b .a d d (s lu c a ja n .n e x tln t(3 0 ));
S y ste m .o u t.p rin tln (s k u p c e lih b );
1
} /* Is p is :
[15, 8, 23, 16, 7, 22, 9, 21, 6, 1, 29, 14, 24, 4, 19, 26,
11, 18, 3, 12, 27, 17, 2, 13, 28, 20, 25, 10, 5, 0]
* ///:-
U skup je d o d a to deset hiljada slu ajnih b ro jev a izm e u 0 i 29, pa je lako zam isliti kako
svaki o d tih b rojeva im a m n o g o d u p lik ata. Pa ipak, p rilik o m ispisa se vidi d a skup sadri
sam o po je d n u in stan cu o d re e n e v red n o sti.
P rim etili ste da brojevi u rezu ltatu n em aju sm isleni p o red ak . U zrok to m e je tran sfo r-
m isan je kljua (engl. hashing), koje HashSet u p o treb ljav a rad i vee b rzin e - o n o je o b -
jan jen o u poglavlju D elaljno razm atranje kontejnera. R edosled koji o drava HashSet
razlikuje se od redosleda u TreeSet ili LinkedHashSet, p o to svaka realizacija skladiti
elem en te n a razliit nain. TreeSet ih uva u re en e u c rv e n o -c rn o j s tru k tu ri stabla, d o k
HashSet p rim e n ju je tra n sfo rm isan je kljua, p ro je k to v an o specijalno rad i b rzo g pro-
nalaenja. I LinkedHashSet up o trebljav a je u c rv en o -crn o j s tru k tu ri stabla, d o k HashSet
p rim e n ju je tran sfo rm isan je kljua rad i brzog p ro n ala e n ja , ali n a izg ledp o m o u u lan a n e
Iiste od rava elem en te u p o re tk u u m etan ja.
A ko ho ete da rezultati b u d u u re en i, m o ete u p o tre b iti TreeSet u m esto HashSeta:
//: cuvanje/UredjenSkupCelihBrojeva.ja va
import j a v a . u t i l .* ;
pu b lic c la s s UredjenSkupCelihBrojeva {
p ub lic s t a t ic void m a in (S trin g [] args) {
Random slu cajan = new Random(47);
SortedSet<Integer> skupcelihb = new T reeSet< In teg er> ();
f o r ( i n t i = 0; i < 10000; i++)
sk u p c e lih b .a d d fs lu c a ja n .n e x tln t(3 0 ));
System .out. pri n tln (s k u p c e lih b );
}
} /* Is p is :
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
* ///:-
324 Misliti na Javi
p u b lic c la s s OperacijeSaSkupovima {
p u b lic s t a t i c void m a in (S trin g [] args) {
Set<String> skupl = new H ashSet< String> ();
C o lle c tio n s .a d d A ll(s k u p l,
" A B C D E F G H I J K L ".s p lit(" " ) ) ;
sk u p l.a d d ("M ");
p r in t (" H : " + s k u p l.c o n ta in s (" H "));
p r in t (" N : " + s k u p l.c o n ta in s (" N "));
Set<String> skup2 = new H ashSet< String> ();
C o lle c tio n s .a d d A ll(s k u p 2 , "H I J K L " . s p l i t ( " " ) ) ;
p rin t("sk u p 2 deo skupal: 11 + sk u p l.co n tain sA U (skup2)) ;
sk u p l.rem oveC 'H ");
p r in t("s k u p l: " + s k u p l);
p rin t("sk u p 2 deo skupal: " + sk u p l.c o n ta in sA ll (skup2)) ;
sk u p l.rem o veA ll(sk u p 2 );
p rin t("sk u p 2 uklonjen iz skupal: " + sk u p l);
C o lle c tio n s .a d d A ll(s k u p l, "X V Z " . s p l i t ( " " ) ) ;
p r i n t ( " 'X Y Z' dodati skupul: " + skupl) ;
}
} /* Is p is :
H: true
N: fa ls e
skup2 deo skupal: true
sk u p l: [D, K, C, B, L, G, I , M, A, F, J , E]
skup2 deo skupal: fa ls e
skup2 uklonjen iz skupal: [D, C, B, G, M, A, F, E]
'X Y Z' dodati skupul: [Z, D, C, B, G, M, A, F, Y, X, E]
* ///:-
p u b lic c la s s JedinstveneReciAbecedno {
p u b lic s t a t ic void m a in (S trin g [] args) {
Set<String> reci =
new T reeSet< Stri n g > (S tring.CASE_INSENSITIVE_ORDER);
r e c i . addAl1(
new T e x tFile ("O p e ra c ije Sa Sk u p o vim a .ja va ", "\W + "));
S y s t e m .o u t .p r in t ln (r e c i);
}
} /* Is p is :
[A, add, ad d A ll, args, B, C, c la s s , C o lle c tio n s , con tain s, c o n ta in s A ll,
cuvanje, D, d o d a ti, E, F, f a ls e , G, H, HashSet, I , import, iz , J , ja v a ,
K, L, M, main, mindview, N, n et, new, OperacijeSaSkupovima, Is p is ,
P r in t , p u b lic , remove, rem oveAll, S e t, skupl, skupal, skupul, skup2,
s p l i t , s t a t i c , S tr in g , tru e , uklonjen, u t i l , void, X, V, Z]
* ///:-
Funkcionalnost mape
M ap iran je je d n ih objek ata n a d ru g e m o e biti izu zetn o m o a n n ain reavanja p ro -
g ram ersk ih zadataka. P rim e ra rad i, u z m im o p ro g ra m za ispitivanje sluajnosti brojeva iz
Javine klase R a n d o m . U id ea ln o m sluaju, R a n d o m bi davala savreno raspodeljene
sluajne brojeve, ali da biste to ispitali, m o ra te d a generiete vie slu ajn ih brojeva i da iz-
b ro jite o n e koji p rip a d a ju razliitim opsezim a. M a p a reava taj zad atak s lakoom ; u
ovom sluaju, klju je bro j koji p ro izv o d i klasa R a n d o m , a v re d n o st je bro j p u ta koliko se
taj broj pojavio:
U m eto d i m a in (), a u to m atsk o pak o v an je p retv ara slu ajn o g en erisan in t u referencu
objekta tip a In te g e r koja se m oe staviti u m a p u tipa H ash M a p . (U k o n tejn e r ne m oete
da stavite v re d n o st p ro sto g tip a, ve sam o referencu na objekat.) M eto d a g et() vraa n u ll
ukoliko takvog kljua nije b ilo u k o n te jn e ru (to znai da je taj broj prv i p u t p ro n a e n ).
U p ro tiv n o m , m eto d a vraa p rid ru e n u In te g e r v re d n o s t kljua koja se poveava za jedan
(a u to m a tsk o pakovanje p o n o v o p o jed n o stav lju je izraz, ali se obavlja p retv aran je u In te-
g e r i iz njega).
Evo p rim e ra u kojem se o b jek ti tip a P et p ro n a la ze p o m o u tek stu aln o g opisa, tj. obje-
k ata tip a S trin g . P okazan o je i kako se m e to d a m a c o n tain sK e y () i c o n tain sV a lu e () ispi-
tu je da li M ap a sari o d re e n i klju, o n o sn o v red n o st:
p u b lic c la s s Mapaljubimaca {
p u b lic s t a t i c void m a in (S trin g [] args) {
Map<String,Pet> mapaljubimaca = new HashMap<String,Pet>();
mapaljub im aca.put("M oja maka", new C a t (" M ic a " )) ;
mapaljub im aca.put("M oj pas", new D o g ("B ru n o "));
m apaljubim aca.put("Moj h rak ", new H am ste r("Bo ko "));
p rin t(m ap alju b im aca);
Pet pas = m apaljubim aca.get("Moj p a s ");
p r in t ( p a s ) ;
print(m apaljubim aca.containsKey("M oj p a s " ) ) ;
p rin t(m a p alju b im a c a .c o n ta in sV a lu e (p a s));
}
} /* Is p is :
{Moja maka=Cat Mica, Moj hrak=Hamster Boko, Moj pas=Dog Bruno}
Dog Bruno
true
true
* ///:-
p ub lic c la s s MapaLista {
pu b lic s t a t ic Map<Person, List< ? extends P e t
1jud iSljub im cim a = new HashMap<Person, L ist< ? extends P e t ( ) ;
s t a t ic {
1jud iSljub im cim a.pu t(new P e r s o n ("Z o r a "),
A rra y s .a s L is t(n e w Cymric("Mol i ) ,new M u t t(" a r k o '')));
1ju d iS l jubimcima.put(new P e rs o n (''K a ta "),
A rra y s .a s L is t(n e w C a t ( e l j k a " ) ,
new C a t ( " E lz a " ) , new D o g C 'M a rg a re ta ")));
1ju d iS1 jub im cim a.put(new Person( " M ir n a " ) ,
A r r a y s .a s L is t (
new PugC'Lui i l i Luis D is a li Meh"),
new C a t("S ta n e i l i Smradi el Negro"),
new C a t( "P i nkola " ) ) ) ;
1jud iS1 jub im cim a.put(new Person( L u k a "),
A r r a y s .a s L is t (new R a t ( " F a z i" ) , new R a t ( " F i z i " ) ) ) ;
1ju d iS l jubimcima.put(new P e r s o n (" Is a k " ),
A rra y s .a s L is t(n e w R a t("P e g a v i ) ) ) ;
328 Misliti na Javi
) /* Is p is :
l j u d i : [Person Luka, Person M irna, Person Is a k , Person Zora, Person Kata]
lju b im c i: [[R a t Fa z i, Rat F i z i ] , [Pug Lui i l i Luis D is a li Meh, Cat Stane
i l i Smradi el Negro, Cat P in k o la ], [Rat P e g a v i], [Cymric M o li, Mutt a rk o ],
[Cat e ljk a , Cat E lz a , Dog M argareta]]
Person Luka ima:
Rat Fazi
Rat F iz i
Person Mirna ima:
Pug Lui i l i Luis D is a li Meh
Cat Stane i l i Smradi el Negro
Cat Pinkola
Person Isak ima:
Rat Pegavi
Person Zora ima:
Cymric Moli
Mutt arko
Person Kate ima:
Cat e ljk a
Cat Elza
Dog Margareta
* ///:-
Mapa m oe da vrati skup svojih kljueva, kolekciju svojih v re d n o sti ili sk u p svojih
p arova. M etoda keySet() p rav i sk u p svih kljueva u m ap i ljudiSljubimcima, koja se u
foreach n ared b i u p o treb ljav a za ite rira n je k ro z Mapu.
Veba 17: (2) K lasu MorskoPrase iz vebe 1 stavite u m a p u tak o da im e o b jek ta klase
MorskoPrase kao String b u d e klju za o b jek at koji stavljate u tab elu . U zm ite Iterator za
sk u p koji daje m e to d a keySet( ) i u p o tre b ite ga za k retan je k ro z m a p u i p ro n alaen je
o b jek ta klase MorskoPrase za svaki klju, p o to m ispiite svaki klju i p o zo v ite m e to d u
sk a ce( ) za svaki objekat.
Veba 18: (3) P o p u n ite m a p u HashMap p a ro v im a k lju -v re d n o st. Ispiite rezu ltate tako
da po k aete u re e n je p o he k o d u . Izvadite p arove i u red ite ih p o k ljuu, a rez u ltat stavite
u m a p u LinkedHashMap. Pokaite d a je red o sled u m e ta n ja zad ran .
Veba 19: (2) P o n o v ite p re th o d n u vebu sa sk u p o v im a HashSet i LinkedHashSet.
Veba 20: (3) P rep rav ite vebu 16 tako d a se b ro ji uestalo st pojave svakog sam oglasnika.
Poglavije 11: uvanje objekata 329
//: cuvanje/QueueDemo.java
// P r a v lje n je reda za ekanje od klase L in k e d L ist svoenjem navie
// na Queue.
import ja v a . u t i l
p u b lic c la s s QueueDemo {
p u b lic s t a t ic void printQ(Queue redZaCekanje) {
w hile(redZaC ekanje.peek() != n u ll)
System .out.print(redZaC ekanje.rem ove() + " " ) ;
S y s te m .o u t .p r in tln ();
}
p u b lic s t a t ic void m a in (S trin g [] args) {
Queue<Integer> redZaCekanje = new L in k e d L ist< In te g e r> ();
330 Misliti na Javi
p u b lic c la s s PriorityQueueDemo {
p u b lic s t a t ic void m a in (S trin g [] args) {
PriorityQueue<Integer> p rio rite tn iR e d =
new PriorityQ u eu e< Integer> ();
Random slu cajan = new Random(47);
f o r ( i n t i = 0; i < 10; i++)
p r io r ite tn iR e d .o ff e r (s lu c a ja n .n e x tIn t(i + 1 0 ));
QueueDemo.pri ntQ (pri o ri te tn i Red);
new PriorityQueue<Character>(skiipZnakova);
QueueDemo.printQ(characterPQ);
}
} /* Is p is :
0 1 1 1 1 1 3 5 8 14
1 1 2 3 3 9 9 14 14 18 18 20 21 22 23 25 25
25 25 23 22 21 20 18 18 14 14 9 9 3 3 2 1 1
A A B C C C D D E E E F H H I I L N N 0 0 0 0 S S S T T U U U W
W U U U T T S S S O O O O N N L I I H H F E E E D D C C C B A A
A B C D E F H I L N O S T U W
* ///:-
p u b lic c la s s P o r e d je n je ln t e r fe js a iIt e r a t o r a {
p u b lic s t a t ic void is p is i(Ite r a to r < P e t> i t ) {
w h ile (it.h a s N e x t ()) {
Pet p = i t . n e x t ( ) ;
S y s te m .o u t .p r in t(p .id () + + p + " ");
}
S y s te m .o u t .p r in tln ();
}
p u b lic s t a t ic void is p is i(C o lle c tio n < P e t> lju b im c i)
fo r (P e t p : lju b im c i)
S y s te m .o u t.p rin t(p .id () + + p + " ");
S y s te m .o u t .p r in tln ();
}
p u b lic s t a t i c void m a in (S trin g [] args) {
List<Pet> lis ta lju b im a c a = P e t s .a r r a y L is t ( 8 ) ;
Set<Pet> skupljubimaca = new HashSet<Pet>( lis t a lju b im a c a );
Map<String,Pet> mapaljubimaca =
new LinkedHashM ap<String,Pet>();
S t r in g [] imena = ( " R a lf , E r ik , Robin, L e js i, " +
" B r i t n i , Sima, Tufna, P a p e r j a s t " ) . s p l i t ( " , " ) ;
f o r ( i n t i = 0; i < im ena.length; i++)
m ap alju b im aca.p u t(im en a[i], 1i s ta lju b im a c a .g e t( i ) ) ;
i s p i s i (1i s t a lju b i m aca);
is p is i(s k u p lju b im a c a );
i spi s i (1 i s ta lju b im a c a .i t e r a t o r ( ) ) ;
i s p is i(s k u p ljub im aca.i t e r a t o r ( ) ) ;
S y s te m .o u t.p rin tln(m apaljubim aca);
System .o ut.p ri n tln(m apalju bim aca.keySet( ) ) ;
i s p i s i (mapaljubim aca.v a l ues( ) ) ;
is p is i(m a p a lju b im a ca .v a lu e s( ) . i t e r a t o r ( ) ) ;
}
} /* Is p is :
0 :Rat l:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
4:Pug 6:Pug 3:Mutt l:Manx 5:Cymric 7:Manx 2:Cymric 0:Rat
0 :Rat l:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
4:Pug 6:Pug 3:Mutt l:Manx 5:Cymric 7:Manx 2:Cymric 0 : Rf! 1
{R alf= R at, Erik=Manx, Robin=Cymric, Lejsi= M utt, Britni= Pu g, Sima=Cymric,
Tufna=Pug, Paperjast=Manx}
334 Misliti na Javi
public c la s s SekvencaKolekcija
extends A bstractC o l1ection<Pet> {
p riv a te P e t[] ljubim ci = P e ts .c r e a te A r r a y (8 );
p ublic in t s iz e () { return 1ju b im c i.le n g th ; }
public Iterator<Pet> it e r a t o r ( ) {
return new Iterato r< P et> () {
p riv a te in t indeks = 0;
public boolean hasNext() {
return indeks < 1ju b im c i.le n g th ;
}
p ublic Pet n ex t() { return 1jub im ci[index+ + ]; }
p ublic void remove() { // N ije realizovano
throw new UnsupportedO perationException();
}
};
}
public s t a t ic void m a in (S trin g [] args) {
SekvencaKolekcija c = new S e k v e n c a K o le k c ija ();
P o r e d je n je ln t e r fe js a iIt e r a t o r a .i s p is i ( c ) ;
P o r e d j e n j e ln t e r f e j s a il t e r a t o r a . is p is i( c . it e r a t o r ( ) ) ;
}
} /* Is p is :
0:Rat l:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
0:Rat l:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx
* ///= -
Poglav[je 11: uvanje objekata 33 5
//: cu vanje/SekvencaBezKolekcije.java
import ty p e in fo .p e ts .* ;
import j a v a . u t i l . * ;
c la s s Sekvencaljubim aca (
protected P e t [] lju b im ci = P e t s .c r e a te A r r a y (8 );
}
Pravljenje Iteratora je n ajrazd v o jen iji nain povezivanja sekvence i m eto d e koja p rim a
tu sekvencu, a pri to m se klasa sekvence o g ran iav a z n a tn o m anje nego kada se im ple-
m e n tira klasa Collection.
Veba 30: (5) Izm en ite p ro g ra m ColIectionSequence.java tako d a ne nasle uje Abstract-
Collection, nego da realizuje Collection.
336 Misliti na Javi
Foreach i iteratori
D o sad sm o foreach sin tak su u g lav n o m up otreb ljav ali s nizovim a, ali o n a rad i i sa svim
o b jek tim a Collection. Z apravo, ve ste videli nekoliko p rim e ra za to u k o jim a se u p o tre -
bljavala ArrayList, ali ovo je o p ti dokaz:
p u b lic c la s s PromenljiveOkruzenja {
p u b lic s t a t ic void m a in (S trin g [] args) {
fo r(M ap .En try stavka: S y s te m .g e te n v ().e n try S e t()) {
S y s te m .o u t.p rin tln (s ta v k a .g e tK e y () + " : " +
s ta v k a .g e tV a lu e O );
}
}
} /* (Po k re n ite da b is te v id e li re z u lta te ) *///:-
System .getenv( )' vraa Mapu; en tryS et( ) p rav i sk u p (Set) e lem en ata Map.Entry, a
p o to je sk u p iterab ilan , m oe se u p o treb iti u fo reach petlji.
F oreach n ared b a rad i s nizovim a i sa svim to je iterab iln o , ali to ne znai d a je svaki niz
au to m a tsk i iterab ilan , niti da se obavlja ikakvo a u to m atsk o pakovanje:
Ova metoda nije postojala pre Jave SE5, poto se smatralo da bi bila previe usko povezana sa opera-
tivnim sistemom, pa bi se krilo pravilonapii jednom, izvravaj bilo gde. injenica da metoda sada
postoji k.izuje da su projektanti Jave nakon pojave .NET-a postali pragmaliniji.
338 Misliti na Javi
}
} /* Is p is :
1 2 3 A B C
* ///:-
Pokuaj da se niz p ro sle d i kao ite rab ila n arg u m e n t, n e uspeva. N e p o sto ji a u to m atsk a
konverzija u Iterable; m o ra te je o bav iti ru n o .
Veba 31: (3) Izm en ite polimorfizam/oblik/GeneratorSlucajnihOblika.java tako da
p o sta n e iterab ilan . M orate d o d a ti k o n s tru k to r koji p rim a broj elem en ata koji ite ra to r tre-
b a d a n ap ra v i p re zaustavljanja. D o kaite d a to radi.
Adapterska metoda
ta ako im a te ite ra b iln u klasu i h teli b iste d a d o d a te je d a n ili vie n o v ih n ain a u p o tre b e
te klase u fo reach naredbi? P rim e ra rad i, p re tp o sta v im o d a b iste hteli d a b irate h o ete li
k roz listu rei ite rira ti u n a p re d ili u n azad . U koliko sam o n asledite tu klasu i redefiniete
m e to d u iterator( ), zam en iete p o sto je u m e to d u i neete m o i d a b irate.
Jed n o reenje sam n azvao A dapterska m etoda. A dapterski d eo p o tie iz p ro je k tn ih
o b razaca, p o to m o rate o b ezb ed iti o d re e n i interfejs d a biste zadovoljili foreach n ared b u .
K ada im ate je d a n interfejs a tre b a v am d ru g i, p ro b le m ete reiti u koliko napiete adapter.
O vde h o u da dodam m o g u n o st pravljenja iterato ra u n azad p o d ra z u m e v a n o m ite rato ru
u n a p re d , p a ne m o g u da ga redefiniem . U m esto toga, d o d a u m e to d u koja proizvodi ite-
ra b ila n o b jek at koji se p o to m m oe u p o tre b iti u foreach naredb i. Kao to ete videti, tim e
d o b ija m o vie n ain a u p o tre b e fo reach sintakse:
//: cuvanje/AdapterskaMetoda.ja va
// "Adapterska metoda" omoguava upotrebu foreach
// sin tak se s dodatnim vrstama it e r a b iln ih objekata.
import j a v a . u t i l .* ;
p u b lic c la s s AdapterskaMetoda {
p u b lic s t a t ic void m a in (S trin g [] args) {
R eversib leA rrayList< Strin g > ra l =
new R eversib leA rrayList< Strin g > (
A rra y s .a s L is t("T o be or not to b e " . s p l i t ( " " ) ) ) ;
// Metodom it e r a t o r ( ) grabi se obian it e r a t o r :
fo r (S t r in g s : r a l)
S y s te m .o u t.p rin t(s + " " ) ;
S y s te m .o u t .p r in tln ();
// D ajte ga iterab iln om objektu po svom izboru
f o r (S t r in g s : ra l .obrn utoO )
Sy ste m .o u t.p rin t(s + " " ) ;
}
} /* Is p is :
To be or not to be
be to not or be To
* ///:-
} /* Is p is :
Pre meanja: [1 , 2, 3, 4, 5, 6, 7, 8, 9, 10]
Nakon meanja: [4, 6, 3, 1, 8, 7, 2, b, 10, 9]
n iz : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Pre meanja: [1 , 2, 3, 4, 5, 6, '/, 8, 9, 10]
Nakon meanja: [9, 1, 6, 3, 7, 2, 5, 10, 4, 8j
n iz : [9, 1, 6, 3, 7, 2, 5, 10, 4, 8]
* ///:-
Saetak
Java im a vie n a in a za u v an je objekata:
1 . N iz povezuje n u m e ri k e in d ek se sa o b jek tim a. O n sad o b jek te p o z n ato g tip a, pa
n ak o n u zim a n ja o b jek ta iz niza ne m o ra te da v rite k rziju tip o v a. N iz m oe da
b u d e v ie d im e n z io n ala n i da sadri p ro ste tipove. M e li m , ne m o ete d a m u p ro -
m en ite veliinu.
2. K olekcija sadri p o jed in a n e elem en te, d o k m a p a sad ri povezane parove. P o m o u
Javinih g en erik ih tip o v a zadajete tip objekta koji c u v ati u k o n te jn e ru , p a u
njega ne m o ete staviti p o g rean tip i ne m o ra te da i iijate tip elem en ata kada ih
izvadite iz njega. I kolekcije i M ap e a u to m atsk i : rii; lavaju svoju veliinu n akon
d o d a v a n ja i u ld an jan ja elem en ata. K o n tejn er re uioe ad ri p ro ste tipove, ali se
a u to m a tsk o p akov an je stara za p rev o en je p ii, :tih i u r . i o m o tak e tipove koji se
uvaju u k o n te jn e ru , i o b rn u to .
3. P o p u t niza, lista tak o e povezuje n u m erik f u. * o b jek tim a; nizovi i liste
m o g u se sm a tra ti u re e n im k o n te jn erim a .
4. U p o treb ite listu ArrayList ako esto k o risfite a ristu p , a LinkedList ako
esto um eete i u k lan jate elem en te n sredini
5 . R edovi za ek an je i stekovi p rav e se p o m o u l c i , ; .in 'L ist.
6. Mapa je nain za povezivanje objekai; ,, ... >je d ru g im objek tim a. Klasa
HashMap je p ro jek to v an a za b rz p ristu p , dok ite e M a p cuva kljueve u u re e n o m
red o sledu i zato nije ta k o b rz a krtO ria sh M .,| '<' HashMap uva svoje ele-
m en te u u re d e n o m red o sled u , ali tra n sfo rm ' ev o b ezbe u je b rz p ristu p .
342 Misliti na Javi
7. Set uva sam o objekte razliitih v red n o sti. Klasa HashSet o b e z b e u je p ro n alaen je
m a k sim a ln o m b rz in o m , d o k TreeSet uva e lem en te u u re e n o m red o sled u . Klasa
LinkedHashSet uva svoje elem en te u u re e n o m red o sled u .
8. N em a p o tre b e da se u n o v im p ro g ra m im a k o riste stare klase Vector, Hashtable i
Stack.
Pogledajte p o jed n o stav ljen d ijag ram Javinih k o n te jn e ra (bez a p stra k tn ih klasa i starih
k o m p o n e n a ta ). U n jem u su sa m o interfejsi i klase koje ete red o v n o sretati.
i 1 f
LinkedHashMap
ArrayList LinkedList PriorityQueue
Alatke
i Comparator ! Arrays
IjnkedHashSet
V idite d a p o sto je sam o etiri k o n tejn ersk e k o m p o n e n te : Map, List, Set i Queue, i
sam o dve ili tri realizacije svake o d njih (rea liza je klase Queue iz pak eta java.util.con-
current nisu p rik aza n e n a d ija g ra m u ). N ajee ete u p o tre b lja v ati k o n te jn e re oiviene
d eb e lo m p u n o m lin ijo m .
T akastim o k v irim a obeleeni su interfejsi, a o k v irim a s p u n o m lin ijo m o b in e (k o n -
kre tn e ) klase. Isp rek id an e p ra zn e strelice u k azu ju da o d re e n a klasa realizuje interfejs.
Strelice s p u n o m lin ijo m u k azu ju da klasa m oe da prav i o b jek te klase na koju po k azu je
strelica. Na p rim er, bilo koja kolekcija m oe da pravi Iterator, d o k List m o e da n ap rav i
Listlterator (kao i ob ian Iterator, p o to je List izvedena iz Collection).
Evo p rim e ra u kojem se vidi razlika izm e u m e to d a razn ih klasa. K od je naveden u
poglavlju G eneriki tipovi; ovde ga sam o p ozivam d a b ih d o b io rezu ltate. U n jim a se vide
i interfejsi koje realizuje p o je d in a klasa ili interfejs:
public c la s s KontejnerskeMetode {
p ub lic s t a t ic void m a in (S trin g [] args) {
R azlikeKon tejnerskih M etoda.m ain (args);
1
} /* Is p is : (prim er)
C o lle c tio n : [add, ad d A ll, c le a r , con tain s, c o n ta in s A ll, equals, hashCode,
isEmpty, it e r a t o r , remove, rem oveAll, r e t a in A U , s iz e , toA rray]
Poglavlje 11: uvanje objekata 343
In t e r f e j s i u k la s i C o lle c tio n : [ It e r a b le ]
Set extends C o lle c tio n , dodaje: []
In t e r f e j s i u k la s i S e t: [C o lle c tio n ]
HashSet extends S e t, dodaje: []
In t e r f e j s i u k la si HashSet: [S e t, C loneable, S e r ia liz a b le ]
LinkedHashSet extends HashSet, dodaje: []
In t e r f e j s i u k la s i LinkedHashSet: [S e t, C loneable, S e r ia liz a b le ]
TreeSet extends S e t, dodaje: [ p o llL a s t , navigableHeadSet,
d escen d in g lte rato r, lovver, headSet, c e ilin g , p o l lF i r s t , subSet,
n a v ig a b le T a ilS e t, comparator, f i r s t , f lo o r , la s t , navigableSubSet,
h igher, t a il S e t ]
In t e r f e j s i u k la s i T reeSet: [N avig a b leS et, C loneable, S e r ia liz a b le ]
L is t extends C o lle c tio n , dodaje: [1 i s t l t e r a t o r , indexOf, g et, s u b L is t,
s e t, la stln d ex 0 f]
In t e r f e j s i u k la s i L is t : [C o lle c tio n ]
A rra y L is t extends L is t , dodaje: [ensu reC apacity, trim ToSize]
In t e r f e j s i u k la s i A rra y L is t: [ L i s t , RandomAccess, Cloneable,
S e r ia liz a b le ]
Lin k e d L ist extends L is t , dodaje: [p o llL a s t, o f f e r , d escen d in g lterato r,
a d d F irs t, peekLast, rem oveFirst, p e e k F irs t, removeLast, g e tLa st,
p o l lF i r s t , pop, p o l l , addLast, rem oveFirstO ccurrence, g e t F ir s t ,
element, peek, o ffe rL a s t, push, o f f e r F i r s t , removeLastOccurrence]
In t e r f e j s i u k la s i L in k e d L ist: [ L i s t , Deque, C loneable, S e r ia liz a b le ]
Queue extends C o lle c tio n , dodaje: [o f f e r , element, peek, p o ll]
In t e r f e j s i u k la s i Queue: [C o lle c tio n ]
PriorityQ ueue extends Queue, dodaje: [comparator]
In t e r f e j s i u k la s i Prio rityQ u eu e: [S e r ia liz a b le ]
Map: [ c le a r , containsKey, con tain sV alu e, e n try S e t, equals, g et, hashCode,
isEmpty, keySet, put, p u tA ll, remove, s iz e , values]
HashMap extends Map, dodaje: []
In t e r f e j s i u k la s i HashMap: [Map, Cloneable, S e r ia liz a b le ]
LinkedHashMap extends HashMap, dodaje: []
In t e r f e j s i u k la s i LinkedHashMap: [Map]
SortedMap extends Map, dodaje: [subMap, comparator, f ir s t K e y , la stK e y ,
headMap, tailM ap]
In t e r f e js i u k la s i SortedMap: [Map]
TreeMap extends Map, dodaje: [descendingEntrySet, subMap, p o l1L a s tE n try ,
la stK e y , flo o rE n tr y , la s t E n t r y , lowerKey, navigableHeadMap,
n avig ab leTaiIMap, descendingKeySet, ta ilM a p , c e ilin g E n tr y , higherKey,
p ol1F i rs tE n try , comparator, f ir s t K e y , flo o rK e y, h ig h erEn try,
f i r s t E n t r y , navigableSubMap, headMap, lo w erEn try, c e ilin g K e y]
In t e r f e js i u k la s i TreeMap: [NavigableMap, C loneable, S e r ia liz a b le ]
* ///:-
V idite da svi sku p ovi (o b jek at tip a Set) sem tip a TreeSet im a ju p o tp u n o isti interfejs
kao Collection. List i Collection se z n a tn o razlik u ju , iako List zahteva m e to d e koje su u
interfejsu Collection. S d ru g e stran e , m eto d e in terfe jsa Queue su sam o staln e; za p ra-
vljenje fu n k cio n aln e realizacije reda za ekanje (Queue), m e to d e interfejsa Collection
nisu p o treb n e. N ajzad, jed in a d o d irn a tak a klasa Map i C ollection jeste injenica da
Map m oe da pravi kolekcije p o m o u m eto d a en tryS et( ) i v a lu es( ).
344 Misliti na Javi
Koncepti
C i d ru g i stariji jezici esto su im ali i po nekoliko em a za o b ra d u greaka koje su p o p ra -
vilu bile u tv rd e n e d o g o v o ro m , o d n o sn o nisu bile deo p ro g ram sk o g jezika. U glavn om se
vraala p o seb n a v red n o st ili se p o stavljao in d ik ato r, a p rim alac bi p o sm a tra o v red n o st,
o d n o s n o in d ik a to r i odlu iv ao d a li je sve u red u. M e u tim , to k o m g o d in a o tk riv e n o je da
p ro g ra m e ri koji koriste b ib lio tek u o b i n o sebe sm a traju n epogreivim i razm iljaju u sti-
lu: ,,Da, greke se m od a deavaju d ru g im a, ali u m om k od u ih n e m a . Z b o g toga ne izne-
n a u je to n isu proveravali uslove p o d ko jim a je nastajala greka (a p o n e k a d su uzroci
greke bili previe glupi d a bi se p ro v erav ali).1 Kada biste bili d o v oljn o paljivi d a traite
greku posle svake m eto d e, va k o d bi se p retv o rio u neitljivu n o n u m o ru . P oto su p ro -
gram e.ri i dalje m ogli da o d rav aju sistem e n ap isan e o p isa n o m te h n ik o m , o d b ijali su da
p riz n a ju istinu: ovakav p ristu p isp rav ljan ju greaka u m n o g o m e je og ran iav ao pisanje
velikih, sn a n ih p ro g ra m a koji bi se lako odravali.
R eenje je d a se p o stu p k u o b ra d e greaka o d u z m e p riro d n o st i da se ojaa fo rm aln o st.
O vaj nain , zapravo, im a d u g u isto riju , je r se obrada izuzetaka (engl. exception handling)
sree jo u o p e ra tiv n im sistem im a iz ezdesetih g o d in a p ro lo g veka, ak i u n a re d b i on
error goto iz p ro g ra m sk o g jezika BASIC. Tako se o b ra d a greaka u jeziku C + + zasnivala
na jeziku A da, a Javina p rete n o n a C + + - U (iako vie podsea n a o b jek tn i Pascal).
Osnovni izuzeci
Vanredno stanje (engl. exceptional condition) jeste p ro b le m koji spreava n astavak ra d a te-
kue m e to d e ili p ro g ra m sk o g blo k a. V ano je razlikovati v a n re d n o stanje o d u o b iajen og
p ro b lem a, s kojim m o ete d a se izb o rite u tek u em o k ru e n ju . Kada n astu p i v an re d n o
stanje, n e m o ete nastav iti o b ra d u zato to n e m a te n e o p h o d n e in fo rm acije da biste se iz-
b o rili s p ro b le m o m u tekuem okruenju. M o ete sam o d a iskoite iz tekueg o k ru en ja i
da p ren esete p ro b le m u vie o k ru en je. To se deava kada se p o jav i izuzetak.
Jednostavan p rim e r je deljenje. D a b i se izbeglo d eljenje n u lo m , d o b ro je prov eriti de-
lilac u n ap red . Ipak, ta zaista zn ai k ad a je delilac nula? M oda znate, u k o n tek stu p ro b le-
m a koji p o k uavate da reite o d re e n o m m e to d o m , kako ete se izb oriti s d eliocem koji
je n u la. M e u tim , ako je to n eo ek iv an a v re d n o st, s n jo m ne m o ete d a se izbo rite i zbog
toga m o ra te da generiete izu zetak u m e sto da nastavite s to m p u ta n jo m izvravanja.
K ada n astan e izuzetak, deava se n ekoliko stvari o d je d n o m . Prvo, p rav i se objekat izu-
zetka na isti n ain kao svi d ru g i Javini o bjekti: u d in am ik o j m em o riji, o p e ra to ro m new .
P o tom se ak tu eln a p u ta n ja izvravanja (o n a koja se ne m oe n astav iti) zaustavlja, a refe-
renca n a o bjekat izuzetka izbacuje se iz tre n u tn o g ok ru en ja. U to m tre n u tk u , k o n tro lu
izvravanja p re u z im a m e h a n iz am o b ra d e izuzetaka i p o in je da tra i odg ov arajue m esto
s kog bi se nastav ilo izvravanje p ro g ra m a . To o dg o v araju e m esto je blok za obradu izu-
zetaka (engl. exception handler), iji je z ad a ta k d a rei p ro b lem p rim e n o m d rugaijeg p ri-
stu p a p ro b le m u , ili d a p ro sto nastav i izvravanje o d neke d ru g e take.
Kao jed n o sta v a n p rim e r g en erisan ja izuzetka, p o sm a tra jm o referencu na objekat koja
se zove t. M oe se desiti d a v am b u d e p ro sle e n a referenca koja nije inicijalizovana, to
ete h teti d a p ro v erite p re n eg o to p rek o te reference p o k u ate da pozovete neku m eto d u .
M oete da poaljete in fo rm ac ije o greci u vie o k ru en je ako na p rav ite o bjekat koji p red -
stavlja te in fo rm acije i zatim ga ,,izbacite iz tek u eg k on tek sta. To se zove generisanje izu-
zetka (engl. throw ing an exception). Evo k ako izgleda:
i f ( t == n u ll)
throw new Nul1P o in te rE x c e p tio n ();
Poglavlje 12: Obrada greaka pomou izuzetaka 347
Argumenti izuzetka
P o p u t b ilo kog Javinog objekta, izuzeci se uvek prave u dinam ik o j m em o riji p o m o u
o p e ra to ra new . Taj o p e ra to r zau zim a p ro s to r u m em o riji i poziva k o n stru k to r. U svim
sta n d a rd n im izu zecim a p o sto je dva k o n stru k to ra: jed a n je p o d razu m ev an i, a d ru g i im a
arg u m e n t tip a zn ako v nog niza u koji se m o g u sm estiti vane in fo rm acije o izuzetku:
Hvatanje izuzetka
D a b iste videli kako se hvata izuzetak, p rv o m o ra te da ra z u m e te p o ja m uvane oblasti
(engl. guarded region). To je d eo k o d a koji m o e d a g en erie izuzetke, iza koga sledi k o d
koji o b ra u je te izuzetke.
Blok try
A ko se n alazite u n u ta r m eto d e i g en eriete izu zetak (ili neka d ru g a m e to d a k o ju p ozivate
iz te m e to d e generie izuzetak), izu zetak e p ro u z ro k o v a ti n a p u ta n je m eto d e. A ko ne e-
lite da th r o w izazove izlazak iz m e to d e, m o ete d a uv ed ete sp ecijalan b lo k u n u ta r te m e-
to d e koji e h vatati izuzetak. To se zove ispitni blok (engl. try block), z ato to isp ro b av ate
razn e pozive m eto d a. Isp itn i b lo k je o b ia n p ro g ra m sk i b lo k isp red koga se nalazi rezer-
visana re try :
tr y {
// Kod k o ji moe da generie izuzetke
)
tr y {
// Kod k o ji moe da generie izuzetke
} c a tc h (T ip l id l) {
// Obrada izuzetaka tip a 1
} catch(Tip2 id2)
// Obrada izuzetaka tip a 2
} catch(Tip3 id3) {
// Obrada izuzetaka tip a 3
}
// i t d . ..
Poglavlje 12: Obrada greaka pomou izuzetaka 349
Svaka o d red n ica catch (b lo k za o b ra d u izu zetak a) n alik je m aloj m e to d i koja p rih v a ta
sam o je d a n a rg u m e n t o d re d e n o g tip a. Id en tifik ato r (id l, id2 itd.) m o e se k o ristiti u n u -
ta r p ro ced u re, p o p u t a rg u m e n ta m eto d e. Id e n tifik a to r se p o n e k a d n e k o risti je r tip izu -
zetka p ru a d o v oljn o in fo rm ac ija za o b ra d u , ali a rg u m e n t ip ak m o ra d a postoji.
Blokovi za o b ra d u izuzetaka m o ra ju da slede o d m a h posle isp itn o g bloka. Ako n asta n e
izuzetak, m e h an iza m njegove o b ra d e tra i p rv i b lo k iji a rg u m e n t o d g o v a ra tip u izu zet-
ka. P o to m se izvrava taj b lo k , n a k o n ega se sm a tra d a je izu ze tak o b ra e n . T raenje blo -
kova za o b ra d u izuzetak a zaustavlja se p o izv rav an ju to g b loka. Izvrava se sam o p rv i
o d go v araju i blok; p o stu p a k se. razlikuje o d n a re d b e Switch u kojoj je n a k o n svake o d -
re d b e case p o tre b n a n are d b a break da b i se spreilo izvravanje o stalih grana.
O b ra tite p a n ju n a to d a u n u ta r isp itn o g b lo k a n ekoliko poziv a razliitih m eto d a
m o e da generie isti izuzetak, ali v a m za o b ra d u sv ih tre b a sa m o je d a n blok.
Vau klasu izuzetka m o ra te d a izvedete iz neke o d po sto jeih klasa izuzetaka, ako je
m og ue iz o n e ije je znaenje blisko sm islu novog izuzetka (m a d a to esto nije m o gu e).
N ajp rostiji nain za pisanje n ovog tip a izuzetka jeste p re p u s titi p re v o d io c u d a n a p ra v i
p o d ra z u m e v a n i k o n stru k to r, to g otovo da ne zahteva p isan je koda:
p ublic c la s s Nasleivanjelzuzetaka {
p ub lic void f ( ) throvvs Jednostavanlzuzetak {
System .o u t.prin tln("Bacam Jednostavanlzuzetak iz f ( ) " ) ;
throw new Jednostavanlzuzetak ( ) ;
}
p u b lic s t a t ic void m a in (S trin g [] args) {
Nasleivanjelzuzetaka sed = new N a sle iv a n je lz u z e ta k a ();
try {
s e d .f ( ) ;
} catch(JednostavanIzuzetak e) {
S y s te m .e rr.p rin tln (''U h v a tio sam ga! " ) ;
}
}
} /* Is p is :
Bacam Jednostavanlzuzetak iz f ( )
Uhvatio sam ga!
* ///:-
D o d a ti kod je k ratak i sadri sam o dva k o n stru k to ra koji d efin iu n ain p rav ljen ja izu-
zetka tip a Mojlzuzetak. U d ru g o m k o n stru k to ru se, p o m o u rezervisane rei super, eks-
p lic itn o poziva k o n stru k to r o sn o v n e klase sa a rg u m e n to m tip a String.
U blok ov im a za o b ra d u izuzetaka poziva se jed n a o d Throvvable m eto d a: printStack-
Trace( ). Kao to vidite iz rezultata, tim e se d o b ijaju in fo rm acije o n iz u m e to d a koje su bile
pozivane pre dolaska na m esto gde se desio izuzetak. O vde se in fo rm ac ije o p o lo aju na
steku izvravanja alju u to k po d atak a System.out i au to m atsk i hvataju i isp isu ju na izlazu.
M ed u tim , ako pozovete p o d ra z u m e v a n u verziju:
e .p rin tS ta c k T ra c e ( ) ;
Izuzeci i zapisivanje
Izlaz biste m o gli i da zapiete (engl. log) p o m o u m e to d a klase java.util.logging. Iako je
zapisivanje d etaljn o o b jan je n o u d o d a tk u n a lokaciji h ttp ://M indV iew .net/B ooks/B ettcr-
Java, e le m e n ta rn o zapisivanje je to lik o je d n o sta v n o da ga ve ovde m o em o u p o treb iti.
Uhvatio LoggingException
Aug 30, 2005 4:02:31 PM Z ap isivan jelzu zetk a <init>
SEVERE: Z ap isivan jelz u z etk a
a t Z ap isiva n je Iz u z e ta k a .m a in (Z a p isiva n je Iz u z e ta k a .ja va :2 4 )
S tatin a m e to d a Logger.getLogger( ) p ra v i zap isn ik (engl. logger), tj. ob jek at tip a Log-
ger sa a rg u m e n to m tip a String (o b in o im e n o m p ak eta i klase u k o jim a je n asta la greka)
koji svoj izlaz alje u System.err. U za p isn ik se najlake u p isu je ta k o d a se pozove m e to d a
p rid ru e n a niv o u p o ru k e k o ju treb a zapisati; ovde je u p o tre b ljen a m e to d a sev ere( ). Za
prav ljen je zn a k o v n o g niza p o ru k e za zapisnik, hteli b ism o d a u p o tre b im o ispis steka
(engl. stack trace) na m e stu gde je izu zetak baen , ali m eto d a printStackTrace( ) p o d ra -
z u m e v a n o n e daje String. D a b ism o d o b ili String, m o ra m o u p o tre b iti p rek lo p ljen u
printStackTrace( ) koja kao a rg u m e n t p rim a o b jek at java.io.PrintWriter. (Sve e to b iti
d e taljn o o b ja n je n o u poglavlju Javin ulazn o -izla zn i sistem .) U koliko PrintWriter k o n -
s tru k to r u p re d a m o o b jek at tip a java.io.StringWriter, izlaz se m oe p re tv o riti u String
m e to d o m to S trin g ( ).
Iako je p ris tu p u p o tre b lje n u klasi Zapisivanjelzuzetka veo m a k o m fo ra n , zato to svu
in fra s tru k tu ru zapisivanja u g ra u je u sam izuzetak i stoga rad i a u to m a tsk i b ez ikakve in-
terven cije p ro g ra m e ra klijenta, ee se deava d a hvatate i zapisujete tu e izuzetke, pa
p o ru k u za zap isn ik m o ra te d a generiete u b lo k u za o b ra d u izuzetaka:
p u b lic c la s s DodatniElementi {
p ub lic s t a t ic void f ( ) throws MojIzuzetak2 {
p rin t("Iz b acu jem MojIzuzetak2 iz metode f ( ) 11) ;
throw new M o jIzu zeta k2 ();
}
pu b lic s t a t ic void g () throws MojIzuzetak2 {
p rin t("Iz b acu jem MojIzuzetak2 iz metode g( ) " ) ;
throw new M ojIzuzetak2("Nastao u metodi g ( ) " ) ;
}
p ub lic s t a t ic void h () throws MojIzuzetak2 {
p rin t("Iz b acu jem MojIzuzetak2 iz metode h ( ) " ) ;
throw new M ojIzuzetak2("Nastao u metodi h ( ) " , 47);
}
pu b lic s t a t ic void m a in (S trin g [] args) {
tr y {
f0;
} catch(M ojIzuzetak2 e) {
e.p rin tS ta c k T ra c e (S y s te m .o u t);
}
try {
g();
} catch(M ojIzuzetak2 e) {
e .p rin tS ta c k T ra c e (S y s te m .o u t);
}
try {
h () ;
Poglavlje 12: Obrada greaka pomou izuzetaka 355
} catch(M ojIzuzetak2 e) {
e .p rin tS ta c k T ra c e (S y s te m .o u t);
S y s te m .e r r.p r in tln ("e .v re d n o s t() = " + e .v r e d n o s t ());
}
}
} /* Is p is :
Izbacujem MojIzuzetak2 iz metode f ( )
MojIzuzetak2: D etaljna poruka: 0 null
at D o d atn iElem en ti.f(D o d atn iElem en ti.java :2 2 )
at Dodatni E lem e n ti. mai n(DodatniE1em enti. java :3 4 )
Izbacujem MojIzuzetak2 iz metode g ()
MojIzuzetak2: D etaljna poruka: 0 Nastao u metodi g ()
a t D od atn iElem en ti.g(D odatniElem en ti. java :2 6 )
a t DodatniElem enti.m ain(Dodatni Elem en ti. java :3 9 )
Izbacujem MojIzuzetak2 iz metode h ()
M ojIzuzetak2: D etaljna poruka: 47 Nastao u metodi h ()
at D odatn iElem enti.h (D o datn iElem enti.java:30 )
at D odatniElem enti,m ain(D odatniElem enti.java:44)
e .v re d n o s t() = 47
* ///:-
Specifikacija izuzetaka
U Javi bi tre b alo da o bav estite p ro g ra m e ra k lijen ta koji poziva vau m e to d u o izuzecim a
koje o n a m o e da generie. To je utivo, p o to o n aj koji poziva m e to d u ta d a ta n o zna
kako d a u h vati sve m ogu e izuzetke. N aravno, ako je d o stu p a n izvorni k o d , p ro g ra m e r
k lijent bi m ogao da ga pregleda i p ro n a e sve n a red b e throw, ali se b iblioteke esto ne
isp o ru u ju sa izv o rn im k o d o m . Da bi se spreilo pojavljivanje p ro b lem a , Java o b ezb e u je
sin ta k su (i prim orava vas da je k o ristite) koja o m o g u u je da utivo kaete p ro g ra m e ru
k lijen tu koje izuzetke g enerie o d re e n a m eto d a. To je specifikacija izuzetaka i pojavljuje
se n ak o n spiska arg u m e n a ta , u deklaraciji m etode.
Specifikacija izuzetaka k o risti d o d a tn u rezerv isan u re throws, iza koje sledi spisak
svih m o g u ih tipov a izuzetaka. D efinicija vae m e to d e m ogla b i d a izgleda ovako:
void f () { / / . . .
N a ovaj n a in bie uhvaen svaki izuzetak, pa bi ovakav blok tre b a lo staviti na kraj liste
za o b ra d u . T im e se izbegava p re u z im a n je n ad len o sti o d blok o v a za o b ra d u k o n k re tn ih
izuzetaka, koji b i ev en tu a ln o m ogli da slede.
P oto je klasa E x c e p tio n o sn o v a svih klasa izuzetaka koje su p ro g ra m e ru vane, ovim
p o stu p k o m ne d o b ija te m n o g o o d re en ijih in fo rm ac ija o izuzetku, ali m o ete da p o zo -
vete m e to d e njene natklase T h ro w ab Ie :
S trin g getM essage( )
S trin g g etL o caIized M essag e()
O n e d aju d e ta ljn u p o ru k u ili p o ru k u koja je p rilag o e n a o d re d e n o m lo k aln o m geo-
grafsk o m p o d ru ju .
S trin g to S trin g ( )
Poglavlje 12: Obrada greaka pomou izuzetaka 357
p u b lic c la s s MetodeKlaseException (
p ub lic s t a t ic void main (S t r in g [] args) {
try {
throw new Exception("Evo iz u z e tk a '');
} catch(Exception e) {
p rin t("U h v a tio sam iz u z e ta k ");
p r i n t ( "getM essage(): " + e.g etM essag e()) ;
p rin t("g e tLo c a liz e d M e s sa g e (): " +
e .g etL o ca lized M essa g ef));
p r in t("to S tr in g (): " + e ) ;
p r in t (" p r in t S t a c k T r a c e (): " ) ;
e .p rin tS ta c k T ra c e (S y ste m .o u t);
}
}
}/ * Is p is :
Uhvatio sam izuzetak
getMessage( ) : Evo izuzetka
getLo calized M essag e(): Evo izuzetka
t o S t r in g ( ) : j a v a . 1ang.Exception: Evo izuzetka
p rin tS ta c k T r a c e ():
j a v a .1ang. Exception: Evo izuzetka
at MetodeKlaseException.m ain(M etodeKlaseException.ja v a :8 )
* ///:-
358 Misliti na Javi
//: izuzeci/KoJeZvao.java
// Programski pristup podacima o poloaju nastanka izuzetka
// na steku izvravanja.
p u b lic c la s s KoJeZvao {
s t a t i c void f ( ) {
// G enerii izuzetak da bi na stek iz vr a v a n ja upisao njegov
// poloaj nastanka
try {
throw new E x ce p tio n ();
) catch (Exception e) {
for(StackTraceElem ent ste : e .g e tS ta c k T ra ce O )
System .ou t.p rintln (ste.getM etho dN am e()) ;
)
}
s t a t i c void g () { f ( ) ; }
s t a t ic void h () { g ( ) ; }
p u b lic s t a t ic void main ( S t r i ng[] args) {
f 0;
System.out.printl n ("------------------------------------- " ) ;
g();
S y s te m .o u t.p rin tln ("-------------------------------- " ) ;
h ();
}
} /* Is p is :
f
mai n
f
9
mai n
f
9
Poglavlje 12: Obrada greaka pomou izuzetaka 359
h
mai n
* ///:-
catch (Exception e) (
System.out.println("Generisan je izuzetak");
throw e;
}
/ / : izuzeci/Ponovnogenerisanje.java
// Prikaz metode f i 11In Stack T race()
Red gde se poziva m eto d a fillIn S ta c k T ra c e () p o staje novo m esto p o rek la izuzetka.
M ogue je p o n o v o gen erisati izu zetak koji je razliit o d o n o g koji je uhvaen. To p ro -
uzro k u je isti efekat k ao k o rien je m e to d e fillIn S ta ck T rac e ( ): g u b e se in fo rm acije o
izv o rn o m p o rek lu izuzetka, a p re o sta ju in fo rm a c ije koje p rip a d aju n o v o m generisanju:
Poglavlje 12: Obrada greak<i, oomou izuzetaka 361
//: izuzeci/PonovnogenerisanjeNovog.java
// Ponovno generisanje objekta koji se razlikuje or5 '^ivaenog.
Ulanavanje izuzetaka
esto je p o tre b n o u h v atiti je d a n izu zetak i g en erisati d ru g i, ne izgubivi p o d a tk e o p rv o m
- to se naziva ulanavanje izuzetaka. P re objavljivanja JD K -a 1.4, p ro g ra m e ri su sam i m o -
rali da p iu k o d koji e ouvati p o d a tk e o p rv o b itn o m izu zetk u , ali sada sve p o tk lase o d
Throvvable im aju o p ciju d a u k o n s tru k to ru p rim e o b jek at uzrok (engl. cause). Predvide-
n o je d a uzrok b u d e p rv o b itn i izuzetak, ijim p ro sle iv an jem zadravate poloaj prv o g
izuzetka na steku, iako p rav ite i g en eriete d ru g i izuzetak.
Z anim ljivo je p rim e titi d a jed in e p o tk la se o d Throwable koje u k o n s tru k to ru p rim a ju
a rg u m e n t uzrok jesu tr i o sn o v n e klase izuzetaka: E rror (p o m o u koje JVM prijavljuje si-
stem ske greke), Exception i RuntimeException. A ko h o ete da u lan ite d ru g e tipove
izuzetaka, u ra d ite to m e to d o m in itC au se( ), a n e k o n stru k to ro m .
Evo p rim e ra koji o m o g u av a d in am i k o d o d av an je p o lja o b je k tu tip a Dinamicka-
Polja u v rem e izvravanja:
try {
d p .s e tF ie ld ("d " , "Neka vrednost za d " ) ;
d p .s e t F ie ld (" b r o j" , 47);
d p .s e tF ie ld ("b r o j2 , 48);
p r in t ( d p ) ;
d p .s e tF ie ld ("d " , "Nova vrednost za d " ) ;
d p .s e tF ie ld ("b r o j3 ", 11);
p rin t("d p : " + d p );
p rin tC 'd p .g e tF ie ld (\ ''d \ ") : 11 + d p . g e t F ie ld ( " d " )) ;
Object p o lje = d p .s e t F ie ld (" d " , n u l l ) ; // Izuzetak
( catch(NoSuchFieldException e) {
e .p rin tS ta c k T ra c e (S y s te m .o u t);
} catch(Izuzetak D in am ick ihPolja e) {
e .p rin tS ta c k T ra c e (S y s te m .o u t);
}
}
} /* Is p is :
n u l l : n ull
n u ll: n u ll
n u l l : n ull
d: Neka vrednost za d
b ro j: 47
broj2 : 48
Svaki o b jek at tip a DinamickaPolja sari niz p arova Object-Object. Prvi o b jek at je
id e n tifik a to r p o lja (tip a String), a d ru g i v re d n o st polja koja m oe b iti bilo kojeg tip a sem
p ro sto g (bez o m o ta a ). Kada p rav ite taj objekat, p ravite zasn o v an u p retp o stav k u o to m e
koliko v am p o lja treba. im pozovete setFie!d( ), o n a e p ro n ai p ostojee, tako nazv an o
p olje ili e n a p ra v iti novo, i staviti u njega vau v red n o st. U koliko joj p o n e sta n e p ro sto ra ,
d o d ae ga p rav ljen jem niza d u eg za je d a n i k o p iran jem starih elem en ata u njega. Ako
p o k u ate d a u n u tr a stavite v re d n o st null, generisae IzuzetakDinamickihPolja tako to
e ga n ap rav iti i m e to d o m in itC au se( ) u m e tn u ti NullPointerException kao uzrok.
Kao p o v ra tn u v re d n o st, m e to d a setField( ) pribavlja i sta ru v red n o st na m estu tog
polja m e to d o m getField( ) koja m o e generisati izuzetak NoSuchFieIdException. Ako
Poglavlje 12: Obrada greaka pomou izuzetaka 365
i f ( t == n u l1)
throvv new Nul 1P o in te rE x c e p tio n ();
//: izuzeci/NeHvataSe.java
// Zanemarivanje izuzetaka tipa RuntimeExceptions.
// {ThrowsException}
D akle, odg o vor glasi: ako izuzetak tipa RuntimeException stigne sve d o m eto de m a in ()
a da ne b u d e uhvaen, p rilik o m izlaska iz p ro g ram a poziva se m eto d a printStackTrace( ) za
taj izuzetak.
Im ajte n a u m u da u svom k o d u sm ete d a zan e m a ru jete sam o izuzetke tip a Runtime-
Exception, p o to za o stale izuzetke prevo dilac zahteva o b ra d u . Izuzetak tip a RuntimeEx-
ception z an e m a ru je te zato to p redstavlja greku u p ro g ra m ira n ju :
1 . G reka k o ju n e m o ete da o b ra d ite (p rim e ra rad i, p rim a n je reference null k o ju m e-
to d i p ro sle u je p ro g ra m e r k lijent).
2. G reka k oju bi, kao p ro g ra m er, treb alo da p ro v erite u svom k o d u (np r. izuzetak
tip a ArrayIndexOutOfBoundsException znai d a je treb alo o b ra titi p a n ju n a d u -
in u n iza). Izu zetak koji n astaje na m estu 1, esto p o staje p ro b le m n a m e stu 2.
Sada v am je ja sn o koliko je k o risn o p o sto jan je izuzetaka u o vo m sluaju - olakavaju
p o s tu p a k p ro n a la en ja i o tk la n jan ja greaka.
Z anim ljivo je p rim e titi d a se Javina teh nik a o b rad e izuzetaka ne m oe klasifikovati kao
alatka specifine n am en e . O n a je projek to vana za rad s n ezgo dn im grekam a to k o m izvr-
avanja koje se deavaju usled delovanja inilaca van d om aaja vaeg koda, ali je o d presu d -
n e van o sti i za o d re e n e vrste p ro g ram ersk ih greaka koje prevodilac n e m oe da otkrije.
Veba 12: (3) Izm en ite p ro g ra m unutrasnjeklase/Sekvenca.java tako d a generie od g o -
v araju i izu ze tak ako p o k u a te d a u m e tn e te previe elem enata.
Try {
// uvana o b la s t: Opasne ak tivn o s ti
// koje mogu da generiu A, B i l i C
} catch(A a l ) {
// Procedura za obradu s it u a c ije A
} catch (B b l)
// Procedura za obradu s it u a c ije B
} catch (C c l)
// Procedura za obradu s it u a c ije C
} fin a lly {
// A k tiv n o sti koje se uvek deavaju
}
4 O b r a d a iz u z eta k a u je z ik u C + + n e m a o re b u finally, p o to se o s la n ja n a to d a e o v a k v u v rs tu i-
c n ja o b a v lja ti d e s tr u k to ri.
368 Misliti na Javi
D a biste se uverili d a se o d re d b a fin a lly uvek izvrava, p o k re n ite sledei p rog ram :
5 D estru k to r je funkcija koja se poziva kad god neki objekat prestan e da se koristi. Uvek se zna tano
gde i kada d estru k to r biva pozvan. U jeziku C + + d e stru k to r se poziva autom atski, a i C# (koji je
m no g o sliniji Javi) u m e da au to m atsk i un iti n ep o treb n e objekte.
Poglavlje 12: Obrada greaka pomou izuzetaka 369
gotovo n ik ad nije pro b lem . Uz to, n e m a d e stru k to re koji b i bili pozivani. D akle, k ad a u Javi
treb a k o ristiti o d re d b u finally?
O d re d b a lin a lly je n e o p h o d n a k ad a u p rv o b itn o stan je m o ra te d a v ra tite n eto to nije
m e m o rija . To m oe b iti zatv aran je o tv o ren e d ato tek e ili rask id veze s m reo m , b risan je
neega to ste n acrta li n a e k ra n u , ili ak p ritisk a n je n ek o g prek id aa iz sp o ljn o g sveta, kao
to je m o d e lo v an o u sledeem p rim e ru :
p u b lic c la s s Prekidac {
p riv a te boolean s ta n je = f a ls e ;
p u b lic boolean re a d () { retu rn s ta n je ; }
p u b lic void u k lju c e n () { s ta n je = tru e ; p r i n t ( t h i s ) ;}
p u b lic void is k lju c e n () { s ta n je = f a ls e ; p r i n t ( t h i s ) ; }
p u b lic S trin g to S trin g O { retu rn s ta n je ? "u k lju ce n " : " is k lju c e n " ; }
} III--
/ / : iz u z e c i/ Iz u z e ta k P a liG a s i1.ja va
p u b lic c la s s Iz u z e ta k P a liG a s i1 extends Exception { } / / / :
//: iz u z e c i/ P re k id a c P a liG a s i. ja va
// emu slu i odredba f i n a l l y ?
// : iz u z e c i/ U z F in a lly .ja v a
// F in a lly garantuje i e n je .
pu b lic c la s s U z F in a lly {
s t a t ic Prekidac pr = new P r e k id a c ();
p ub lic s t a t ic void m a in (S trin g [] args) {
try {
pr.u kl ju c e n ( ) ;
// Kod k o ji moe da generie iz u z e tk e ...
P r e k id a c P a liG a s i.f () ;
} c a tc h (Iz u z e ta k P a liG a s i1 e) {
S y s te m .o u t.p rin tln ("Iz u z e ta k P a liG a s i1 ");
} catc h (Iz u z e ta k P a liG a si2 e) {
S y s te m .o u t.p rin tln ("Iz u z e ta k P a liG a s i2 ");
} fin a lly {
p r . is k l ju c e n ( ) ;
;
}
} /* Is p is :
ukl jucen
is k lju c e n
* ///:-
p u b lic c la s s ZagubljenaPoruka {
void f ( ) throws VeomaVazanlzuzetak {
throw new VeomaVazanlzuzetakO;
}
void p o c is t iO throws T riv ija la n lz u z e ta k {
throw new T r iv ija la n lz u z e t a k ( ) ;
}
p u b lic s t a t ic void m a in (S trin g [] args) {
try {
ZagubljenaPoruka lm = new Z agu bljenaPoru ka();
try {
lm .f ( ) ;
} fin a lly {
lm .p o c is ti ( ) ;
}
} catch (Exception e) {
System .out .pri n t l n ( e ) ;
}
}
} /* Is p is :
T r iv ij a l a n izuzetak
* III--
V idite d a n e m a n azn ak a o p risu stv u izuzetka tip a VeomaVazanlzuzetak koji je zam e-
njen izuze tkom tip a Trivijalanlzuzetak u o d red b i finally. To je p rilin o o zb iljan n e d o sta -
tak, je r znai da izuzetak m oe p o tp u n o da se izgubi i to na n ain koji je m n o g o tee
o tk riti nego u g o rn je m p rim e ru . N a su p ro t to m e, u jeziku C + + se situacija, kad a se d ru g i
izuzetak generie pre nego to je prvi o b ra e n , sm a tra velikom grekom u p ro g ra m ira n ju .
M o d a e u b u d u im verzijam a Jave ovaj p ro b lem b iti ispravljen (s d ru g e stra n e , m e to d u
koja generie izuzetak, kao to je p o cisti( ) u g o rn jem p rim e ru , o b i n o ete sm estiti u n u -
ta r o d re d b e try-catch).
374 Misliti na Javi
Jo jed n o sta v n iji n a in d a izgu b ite izu ze tak jeste o b ian p o v ra ta k (p o m o u rezervisa-
ne rei return) iz b lo k a finally:
Ogranienja izuzetaka
Kada redefiniete m e to d u , m o ete da generiete sam o izuzetke koji su zadati u verziji m e-
to d e iz o sn o v n e klase. To je k o risn o o g ran ien je, p o to znai d a e k o d koji ra d i sa osnov-
n o m klaso m a u to m a tsk i ra d iti i sa sv ak om klasom izved en o m iz nje (to je, naravno,
o snov n i k o n c e p t o b jek tn o o rije n tisa n o g p ro g ra m ira n ja ), u k lju u ju i i izuzetke.
O vaj p rim e r ilu stru je v rste o g ra n i e n ja koja se u v rem e p rev o en ja n am e u izuzecim a:
ab s tra ct c la s s Inning {
p u b lic In n in g () throws Basebal1Exception {}
p u b lic void event () throws B asebal1Exception {
// Zapravo ne mora da generie nikakav izuzetak
}
p ub lic a b s tra ct void a t B a t () throws S t r ik e , F o u l;
p ub lic void w alk () { } // Ne generie izuzetke koje prevodilac proverava
Poglavlje 12: Obrada greaka pomou izuzetaka 375
in te rfa c e Storm {
p u b lic void e v e n t() throws RainedOut;
p u b lic void ra in H ard () throws RainedOut;
}
Poslednje to nas z a n im a je m eto d a m a in ( ). U njoj m o ete d a vidite sledee: ako rad ite
sa o b je k to m tip a Storm yInning, p rev o d ilac vas p rim o ra v a d a hvatate sam o izuzetke koji
su specifini za tu klasu, ali ako k o n v ertu jete o b je k at u p ro s t tip , p rev od ilac vas s p ra v o m
p rim o ra v a da hvatate izuzetke o sn o v n o g tip a. Sva ova o g ran ie n ja ine te h n ik u za o b ra d u
izuzetaka m n o g o sn a n ijo m .6
K orisno je u v id eti sledee: iako p rev od ilac to k o m n asle iv an ja p o d r av a specifikacije
izuzetaka, o n e n isu d eo p o tp isa m eto d e koji se sastoji sam o o d im e n a m eto d e i tip o v a ar-
g u m e n a ta. Stoga ne m o ete d a p rek lo p ite m e to d e p re m a s p e fik a ja m a izuzetaka. P ored
toga, sam o zato to specifikacija izuzetka p o sto ji u verziji m e to d e iz o sn o v n e klase, ne
znai d a o n a m o ra d a p o sto ji i u verziji m eto d e u izvedenoj klasi. O vo se p rili n o razlikuje
o d p rav ila nasleivanja, k ad a m e to d a o sn o v n e klase m o ra d a p o sto ji i u izvedenoj klasi.
D ru g im reim a, interfejs specifikacije izuzetka" za o d re d e n u m e to d u m oe d a se suzi to -
k o m nasleivanja i redefin isan ja, ali se nee p ro iriti, to je u p rav o su p ro tn o p ra v ilu za in -
terfejs klase to k o m nasleivanja.
Veba 20: (3) P ro m e n ite Storm yInning.java d o d a v a n je m izu zetk a tip a UmpireArgu-
m ent i m e to d a koji ga gen eriu . T estirajte iz m e n je n u h ijerarh iju .
Konstruktori
P rilikom pisanja koda sa izuzecim a, p o se b n o je v an o d a se uvek pitate: Ako n a sta n e izu-
zetak, hoe li o b jek at biti p ra v iln o poien? U veini sluajeva sve je u red u , ali se u k o n -
stru k to rim a pojavljuje p ro b lem . K o n stru k to r stavlja o b jek at u b e z b e d n o p o e tn o stanje,
ali m oe d a izvodi neke o p eracije, npr. o tv a ran je d ato te k a , koje se n e b riu sve d o k kori-
sn ik ne zavri rad sa o b je k to m i pozove sp ecijaln u m e to d u za ienje. A ko generiete izu-
zetak u n u ta r k o n stru k to ra , ienje se m o d a nee p ra v iln o izvriti. To znai da m o ra te
biti p o seb n o o b azriv i d o k sastavljate k o n stru k to r.
Poto ste u p rav o savladali o d re d b u finally, m o d a m islite d a je o n a pravo reenje. Ipak,
nije toliko jed n o sta v n o , p o to fin ally svaki p u t izvrava k o d za ienje. U koliko k o n -
s tru k to r b u d e p re k in u t to k o m svog izvravanja, to m oe zn aiti da nije usp eo d a n apravi
deo o b jek ta koji e biti poien u b lo k u finally.
U sledeem p rim e ru pravi se klasa U la z n a D a to te k a koja o tv a ra d a to te k u i o m o g u u je
itan je p o je d n o g reda. O n a k oristi klase F ile R ea d er i B u ffe re d R e a d e r iz sta n d a rd n e Ja-
vine U /I b iblioteke. O n jim a e biti rei u poglavlju Javin ula zn o -izla zn i sistem , ali o n e su
toliko jed n o sta v n e da ete bez p ro b lem a ra z u m e ti n jih o v o o sn o v n o korienje:
p u b lic c la s s UlaznaDatoteka {
p riv a te BufferedReader in ;
U ISO sta n d a rd za C + + d o d ata su slina ogranienja kojim a se zahteva d a izuzeci izvedenih m eto da
b u d u isti kao izuzeci koje generie m etoda osnovne klase, ili izvedeni iz njih. To je jed ini sluaj kada
je C + + zaista u stan ju da proverava specifikacije izuzetaka toko m prevoenja.
378 Misliti na Javi
p ub lic c la s s C iscenje (
pu b lic s t a t ic void m a in (S trin g [] args) {
try {
UlaznaDatoteka in = new U la z n a D a to te k a ("C is c e n je .ja v a ");
try {
S trin g s;
in t i = 1;
w h ile ((s = in .g e tl_ in e ()) != n u ll)
; // Ovde obradi red po r e d ...
} catch(Exception e) {
S y ste m .o u t.p rin tln ("U h va tio izuzetak u metodi m ain ");
e .p rin tS ta c k T ra c e (S y ste m .o u t);
380 Misliti na Javi
} finally {
in.ciscenjeO;
}
} catch(Exception e) {
S y s te m .o u t.p rin tln ("N ije uspela k o n stru k cija U lazneD atoteke");
}
}
} /* Ispis:
ciscenje() uspeno
* ///:-
Paljivo ra z m o trite u p o tre b lje n u logiku: k o n stru k cija o b jek ta tip a UlaznaDatoteka
su tin sk i je u so p stv en o m b lo k u try. A ko ta k o n s tru k ja ne u sp e, ulazi se u sp oljni b lo k
catch, a ciscenje( ) se n e poziva. M e u tim , uk o lik o k o n stru k c ija usp e, m o ra te se p o sta ra ti
da o b jek at b u d e poien, p a n e p o sre d n o n ak o n k o n stru k c ije p rav ite n o v b lo k try. O d -
re d b a finally koja obavlja ienje p rid ru e n a je u n u tra n je m b lo k u try; zato se b lo k fi-
nally nee izvriti ako k o n stru k c ija n e u sp e, a izvrava se uvek k ad a k o n stru k c ija uspe.
O vaj o pti n a in ienja treb a p rim e n jiv a ti i k ad a k o n s tru k to r u o p te ne generie izu-
zetke. O sn o v n o pravilo glasi: n e p o sre d n o n a k o n p rav ljen ja o b jek ta koji zahteva ienje,
o tv o rite b lo k try-finally:
p u b lic c la s s N acinCiscenja {
p u b lic s t a t i c void m a in (S trin g [] args) {
// Deo 1:
T r e b a Je P o c is titi ncl = new T r e b a Je P o c is titi ( ) ;
try {
/ /
} fin a lly {
n c l. c i s c e n j e ( ) ;
}
Poglavlje 12: Obrada greaka pomou izuzetaka 381
// Deo 2:
// Ako k o n stru k cija ne moe da ne uspe, objekte moete da grup iete:
T r e b a Je P o c is titi nc2 = new T r e b a Je P o c is t it i( ) ;
T r e b a Je P o c is titi nc3 = new T r e b a Je P o c is t it i( ) ;
try (
//
} fin a lly (
n c 3 .c is c e n je (); // Obrnut redosled u odnosu na konstru kciju
n c 2 .c is c e n je ();
}
// Deo 3:
// Ako k o n stru k cija moe da ne uspe, morate u vati svaku od n jih :
try {
T r e b a Je P o c is titi2 nc4 = new T r e b a J e P o c is t it i2 () ;
try {
T re b a Je P o c is titi2 nc5 = new T r e b a Je P o c is t it i2 ();
tr y {
/ /
} fin a lly {
n c 5 .c is c e n je ();
}
} catch(IzuzetakTokom Konstrukcije e) { // konstruktor nc5
S y s te m .o u t .p r in tln (e );
} fin a lly {
nc4 .ci s c e n j e () ;
}
} catch(IzuzetakTokom Konstrukcije e) { // konstruktor nc4
S y s te m .o u t .p r in tln (e );
}
}
} /* Is p is :
T r e b a Je P o c is titi 1 poiena
T r e b a Je P o c is titi 3 poiena
T r e b a Je P o c is titi 2 poiena
T r e b a Je P o c is titi 5 poiena
T r e b a Je P o c is titi 4 poiena
* ///:-
U m e to d i m a in ( ), d eo 1 je lako razu m eti: iza o b jek ta koji treb a p o istiti sledi b lo k try-
finally. U k o lik o k o n stru k cija o b jek ta ne m o e da ne uspe, b lo k catch nije p o tre b a n .
U d elu 2, v id ite da ob jek ti ija k o n stru k c ija ne m oe da ne u sp e m o g u b iti g ru p isan i i za
k o n stru k c iju i za ienje.
D eo 3 p o k a z u je kako se rad i sa o b jek tim a ija k o n stru k c ija m oe d a n e u sp e i koji zah-
tevaju ienje. P raviln a o b ra d a ove situacije znai pravljenje kra, je r svaku k o n stru k ciju
m o ra te da o b u h v a tite so p stv en im b lo k o m try-catch, a n ak o n njega m o ra da sledi blok
try-finally za zaje m en o ienje.
R unoa k od a za o b ra d u izuzetaka u o v o m sluaju, p redstavlja ja k a rg u m e n t za p ra-
vljenje k o n s tru k to ra koji ne m o g u da ne usp eju , m ad a to nije uvek m ogue.
382 Misliti na Javi
p u b lic c la s s Covek {
p ublic s t a t ic void m a in (S trin g [] args) (
// Uhvati taan tip
try {
throw new K i j a n j e ( ) ;
} c a tc h (K ija n je s) {
S y s te m .o u t.p rin tln ("U h v a tio K i j a n j e " ) ;
} catch(Dosada a) {
System .out. pri n tln ("U h v a ti o Dosadu");
}
}
} /* Is p is :
Caught Sneeze
Caught Annoyance
) III--
Poglavlje 12: Obrada greaka pomou izuzetaka 383
Izu zetak tip a Kijanje uhv atie p rv a o d re d b a catch kojoj odg ov ara, a to je, n arav n o , p r-
va. M e u tim , ako u k lo n ite p rv u o d re d b u catch i ostavite sam o o d re d b u catch za klasu
Dosada, k o d e i dalje rad iti, je r b lo k hvata o sn o v n u klasu klase Kijanje. D ru g im reim a,
catch (Dosada e) u h vatie izu ze tak tip a Dosada i sve klase koje su izvedene iz tog tipa. To
je k o risn o : ako o d lu ite d a m eto d i d o d a te vie izv edenih izuzetaka, k o d p ro g ra m e ra kli-
je n ta nee m o ra ti da se m en ja sve d o k klijen t o b ra u je izuzetke o sno v n e klase.
A ko p o k u a te d a ,,m askirate izuzetke izvedene klase ta k o to n a prvo m esto stavite o d -
re d b u catch za h v atan je o sn o v n e klase, kao ovde:
try {
throw new K i j a n j e ( ) ;
} catch(Dosada a) {
/ /
} c a tc h (K ija n je s) {
/ /
}
p rev o d ilac e p rik a zati greku, p o to vid i d a o d re d b a za h vatanje Kijanje nije d o stu p n a .
Veba 25: (2) N ap rav ite h ije ra rh iju izu zetaka u tr i nivoa. P o to m n ap rav ite o sn o v n u klasu
A s m e to d o m koja g enerie izuzetak u o sn o v i h ijerarhije. Izvedite klasu B iz A i redefini-
ite m e to d u tako d a g enerie izu zetak u d ru g o m n iv o u h ijerarh ije. P ono vite p o stu p a k i iz-
vedite klasu C iz klase B. U m eto d i m a in () n ap rav ite o b jek at klase C i svedite ga navie n a
tip A, a zatim p o zo v ite m e to d u .
Drugi pristupi
Sistem za o b ra d u izuzetaka predstavlja skrivena v rata koja p ro g ra m u o m oguavaju da na-
p u sti izvravanje n o rm a ln e sekvence n ared be. Skrivena v rata se up otrebljavaju kad a n astu -
pi izuzetan uslov, p o p u t o n o g a kada n o rm a ln o izvravanje vie nije m ogue ili poeljno.
Izuzeci predstavljaju uslove koje teku a m eto d a ne m o e d a o b rad i. Sistem i za o b ra d u izu-
zetaka su razvijeni zato to je p ristu p koji je p o d ra z u m e v a o o b ra d u svih m og uih greka
izazvanih svakim p ozivom svake funkcije bio previe teg o ban , pa ga p ro g ram eri n isu sle-
ili. Stoga su greke ignorisali. Vredi p rim etiti da je olakavanje p ro g ram ira n ja o b ra d e
greaka bilo glavna m otivacija za izum izuzetaka.
Jedna o d v anih sm e rn ic a u o b ra d i izuzetaka glasi: ,,Ne hvataj izuzetak s kojim n e zna
ta da u ra d i. U stvari, je d a n o d van ih cilje v a o b ra d e izuzetaka bio je d a s e k o d za o b ra d u
greaka o d m a k n e o d take gde je greka n astala. T im e d o b ijate m o g u n o st da se u je d n o m
delu svog k oda u sred sred ite na o n o to h o ete da u rad ite , a d a se u d ru g o m , zasebn om
d elu bavite p ro b le m im a . Stoga glavni deo vaeg k o d a nee b iti z atrp a n logikom za o b ra d u
greaka, pa e b iti m n o g o razum ljiviji i lake e se odravati. O b ra d a izuzetaka o b in o
sm a n ju je o b im koda za o b ra d u greaka, je r je d a n b lo k za o b ra d u m oe d a o b ra d i greke
nastale na m n o g o m esta.
384 Misliti na Javi
try {
II . . . radi se neto korisno
} catch(0bavezanlzuzetak e) { } // Progutano!
Istorija
O b ra d a izuzetaka je n astala u sistem im a PL/1 i M esa. K asnije se pojavljivala u jezicim a
CLU, Sm alltalk, M o d u la-3 , Ada, Eiffel, C + + , P y th o n , Java, kao i u jezicim a R uby i C # na-
stalim n a k o n Jave. U to m p o g led u Java je slina C ++-U , sem na m e stim a gde su pro jek -
ta n ti Jave sm atra li da p ristu p iz C + + -a p ro u z ro k u je p ro b lem e.
D a bi se p ro g ra m e rim a p ru io sistem za o b ra d u i o p o ra v a k o d greaka koji e im ati
vie izgleda da b u d e u p o treb ljav an , jeziku C + + je o b ra d a izuzetaka d o d a ta relativ n o ka-
sno u p ro cesu stand arizacije. N ju je zagovarao B jarne S tro u stru p , a u to r jezika. M odel
izuzetaka u jezik u C + + p rv en stv en o p o tie iz C LU -a. M e u tim , tad a su posto jali i d ru g i
jezici koji su p o drav ali o b ra d u izuzetaka: A da, Sm alltalk (im ali su izuzetke, ali ne i spe-
cifikacije izuzetaka) i M o d u la-3 (koja je im ala i izuzetke i specifikacije).
Poglavlje 12: Obrada greaka pomou izuzetaka 385
Perspektive
Prvo, vredi primetiti da su tvorci Jave zapravo izumeli proverene izuzetke (oigledno in-
spirisani specifikacijama izuzetaka u C++-u i injenicom da se C++ programeri obino
ne baku s njima). Meutim, taj eksperiment nije ponovljen ni u jednom kasnijem jeziku.
Drugo, provereni izuzeci izgledaju kao oito korisni u uvodnim primerima i malim
programima. Reeno je da se suptilne razlike pojavljuju kada programi postanu veliki.
Naravno, do tolike veliine obino ne dolazi preko noi; ona nastaje neosetno. Jezici koji
nisu podesni za velike projekte, upotrebljavaju se za male. Ti mali rastu i od nekog trenut-
ka shvatamo da su od ,,upravljivih postali teko upravljivi". Smatram da to moe biti
posledica i preteranog proveravanja tipova; konkretno, provere izuzetaka.
Izgleda da je veliina programa znaajna. To je problem, poto se u veini rasprava za
ilustraciju upotrebljavaju mali programi. Jedan od projektanata C#-a kazao je sledee:
Ispitivanje malih programa navodi na zakljuak da zahtevanje specifikacija izuzetaka
moe poveati produktivnostprogramera i kvalitet koda, ali iskustvo s velikim softverskim
projektima namee drugaiji zakljuak - smanjuje se produktivnost a kvalitet koda se
poveava malo ili nimalo.8
Autori CLU-a su kazali sledee o neuhvaenim izuzecima:
Stnatrali smo da tiije realno zahtevati od programera da pie blok za obradu u situaci-
jam a kada se ne m oepreduzeti nita smisleno.9
Kada objanjava zato deklaracija funkcije bez specifikacije znai da ona moe generi-
sati bilo koji izuzetak, a ne da uopte ne moe generisati izuzetak, Stroustrup kae:
,,To bi zahtevalo specifikacije izuzetaka za gotovo sve funkcije, predstavljalo bi znaajan
uzrok ponovnog prevoenja i spreilo bi saradnju sa softverom napisanim na drugitn
jezicima. To bi navclo programere da sabotiraju tnehanizme za obradu izuzetaka i da piu
maskirni kdd koji sakriva izuzetke. Stoga bi Ijudi koji nisu uoili izuzetak stekli lano
oseanje bezbcdnosti w
Vidimo da se ba takvo ponaanje - sabotiranje izuzetaka - deava s proverenim izu-
zecima u Javi.
Martin Fovvler (autor knjiga UML Distilled , Refactoringi Analysis Patterns) napisao mi
je sledee:
,,...sve u svemu, smatram da su izuzeci korisni, ali Javini provereni izuzeci vie kotaju
nego to vrede."
Sada smatram da je vaan doprinos Jave bio to to je objedinila model prijavljivanja
greaka, tako da se sve greke prijavljuju pomou izuzetaka. Toga nije bilo u C++-u, zato to
je, zbog kompatibilnosti sa C-om, jo uvek bio na raspolaganju stari model prostog igno-
risanja greaka. Ali ako imate dosledno prijavljivanje pomou izuzetaka, moete ih koristiti
ako hoete, a ako ne, oni e se popeti na najvii nivo (konzolu ili drugi kontejnerski
saznati u poglavlju Javin u la zno -izla zn i sistem ), m o ra te o tv o riti i zatv o riti Filelnput-
Stream koji generie izuzetke. U je d n o s ta v n o m p ro g ra m u m o ete u ra d iti ovo (isti p ristu p
je u p o treb ljen u m n o g im p rim e rim a u ovoj knjizi):
p u b lic c la s s M ainlzuzetak {
// Proslediemo sve izuzetke na konzolu:
p ub lic s t a t ic void m a in (S trin g [] args) throws Exception {
// O tvaranje datoteke:
Filelnp u tStream datoteka =
new F ile In p u tS tre a m ("M a in Iz u z e ta k .ja v a ");
// Upotreba datoteke . . .
// Z atvo ri datoteku:
d a to te k a .c lo s e ();
}
} lll- ~
tr y {
// __ ra d ite korisne s tv a ri
} catch(NeZnamStaDaRadimSaOvimproverenim Izuzetkom e) {
throw new Runtim eException(e);
}
// : iz u z e c i/ Is k lju c iv a n je P ro v e r e .ja v a
// " I s k lju iv a n je " provere izuzetaka.
import j a v a . io . * ;
import s t a t ic rie t.m ind view .u til . P r i n t . * ;
c la s s Omotajproverenlzuzetak {
void throwRuntim eException(int t i p ) {
try {
swi t c h ( t i p) {
case 0: throw new FileN o tFo u n d Ex cep tio n ();
case 1: throw new I0 E x c e p tio n ();
case 2: throw new RuntimeException("Gde sam?11) ;
d e fa u lt: re tu rn ;
}
} catch(Ex ception e) { // Prilag o e n je za neproverene:
throw new Runtim eException(e);
}
}
pu b lic c la s s Is k lju c iv a n je P r o v e re {
p u b lic s t a t i c void m a in (S trin g [] args) {
Omotajproverenlzuzetak opi = new O m otajproverenlzuzetak();
// Moete pozvati throwRuntimeException() bez bloka t r y
// i o s t a v it i RuntimeException da napusti metodu:
o p i.throw Runtim eException(3);
// A moete o d lu iti i da hvatate izuzetke:
f o r ( i n t i = 0 ; i < 4 ; i++)
tr y {
i f ( i < 3)
o p i.th ro w R u n tim eE x cep tio n (i);
el se
throw new N e k iD ru g iIz u z e ta k ();
} catch(N ekiD rugiIzuzetak e) {
p rin t("N e k iD ru g iIz u z e ta k : " + e );
} catch(Runtim eException re) {
try {
throw re .g e tC a u s e O ;
} catch(FileN otFoundException e) {
p r i n t ( " F i 1eNotFoundException: " + e ) ;
} catch(IO Exception e) {
p rin t("IO E x c e p tio n : " + e ) ;
390 Misliti na Javi
} catch(Throwable e) {
p rin t("T h ro w ab le: 11 + e ) ;
}
}
}
} /* Is p is :
F i 1eNotFoundException: j a v a . i o . F i 1eNotFoundException
IOException: ja v a .io .IO E x c e p tio n
Throwable: j a v a . 1ang.Runtim eException: Gde sam?
NekiDrugiIzuzetak: Neki DrugiIzuzetak
* ///:-
Uputstva za izuzetke
K oristite izuzetke da:
1. O b ra d ite p ro b lem e na o d g o v araju em nivou. (Izbegavajte h v atan je izuzetaka s ko-
jim a ne zn ate ta da rad ite.)
2. Reite p ro b lem i p o n o v o po zo v ete m e to d u koja je p ro u zro k o v ala izuzetak.
Poglav|je 12: Obrada greaka pomou izuzetaka 391
Saetak
Izuzeci su n ezao bilazan d eo p ro g ra m ira n ja n a Javi; ako n e zn ate d a rad ite s n jim a, neete
ba m n o g o postii. Z ato sm o izuzetke p red stav ili n a ovom m estu - im a m n o g o bib lio tek a
(k ao ran ije sp o m e n u ta b ib lio tek a U /I) koje u o p te n e m o ete d a u p o treb ljav ate b ez p o -
znav an ja izuzetaka.
Jed n a o d p re d n o sti o b ra d e izuzetaka jeste sledea: om o g u av a d a se n a je d n o m m estu
u sred sred ite n a p ro b lem koji p o k u av ate d a reite, a d a se n a d ru g o m m e stu bavite gre-
k am a u to m k o du. I m a d a se izuzeci p o p rav ilu sm atraju alatk am a koje om o g u av a ju p ri-
javljiva nje i oporavak od greaka u v re m e izvravanja, p ita m se koliko esto se aspekat
oporavka" realizuje, pa ak i koliko esto je to u o p te m ogue. Po m o m oseaju, to je
m an je o d 10 p osto v rem en a, p a ak i tad a se v ero v atn o svodi na otpetljav an je steka d o
p o z n a to g stab iln o g stan ja, a ne d o stv arn o g nastavljanja rada. Bila to istina ili ne, sm a tra m
da o sn o v n a v re d n o st izuzetaka lei u njih o v o j fu n k ciji ,,prijavljivanja. in jen ica d a u Javi
svegrek e valjap rijav ljiv ati u o b lik u izuzetaka d a je jo j veliku p re d n o st n ad jezicim a p o p u t
C + + -a , koji dozvoljavaju prijavljivanje greaka n a vie razliitih naina, a m o ete i da ih
u o p te ne prijavite. D osledan sistem za prijavljivanje greaka znai da se vie ne m o rate
pitati: Da li su m i negde p ro cu rile greke? n a k o n pisanja svakog pareta k o d a (ukoliko
ne p ro g u ta te izuzetke, narav n o !).
Kao to ete videti u sledeim p oglavljim a, u koliko reite ovo p itan je - ak i ako to u ra-
d ite g en eriui R u n tim e E x c e p tio n svoj tr u d p ri p ro jek to v an ju i realizaciji m oete
u sred sred iti na zanim ljivije i tee p ro b lem e.
R eenja o d a b r a n ih vebi d a ta su u e le k tro n sk o m d o k u m e n tu The Thinking in Java Annotated Solu-
tion Guide , koji se m o e k u p iti n a lokaciji www.BruceEckel.com.
Znakovni nizovi
T vrd i se d a o b ra d a z n a k o v n ih n iz o v a sp ad a m eu n a i e e a k t i v n o s t i u
p ro g ra m ira n ju . To je p o g o to v o ta n o u W eb sistem im a, gde se Java m n o g o k oristi.
U o v o m po g lavlju detaljn ije em o ra z m o triti najee k o rien u klasu to g jezika, String,
k ao i neke n je n e p ratee i p o m o n e m eto d e.
p u b lic c la s s Nepromenljiv {
p u b lic s t a t i c S trin g v e ls lo v a (S t r in g s) {
return s . tollpperCase ( ) ;
}
p u b lic s t a t i c void m a in (S trin g [] args) {
S trin g q = "zd ravo";
p r i n t ( q ) ; // zdravo
S trin g qq = u p case(q );
p ri n t (q q ); // ZDRAVO
p r i n t ( q ) ; // zdravo
}
} /* Is p is :
zdravo
ZDRAVO
zdravo
* ///:-
// : znakovninizovi/N adovezivanje.java
p u b lic c la s s Nadovezivanje {
p u b lic s t a t ic void m a in (S trin g [] args) {
S trin g mango = "mango";
S trin g s = "abc" + mango + "d e f" + 47;
S y s te m .o u t .p r in tln (s );
)
} /* Is p is :
abcmangodef47
* ///:-
javap -c Nadovezivanje
U koliko ste rad ili sa asem b le ro m , ovo b i treb alo da vam izgleda p o zn ato n a re d b e p o -
p u t dup i invokevirtual p rip a d a ju a sem b leru Javine v irtu e ln e m aine (JV M ). Ako prv i
p u t u iv otu v id ite asem bler, ne u p u ta jte se - vano je u oiti d a p revodilac uvodi klasu ja-
va.lang.StringBuilder. U izv o rn o m k o d u se StringBuilder nije sp o m in jao , ali je prevo-
dilac o d lu io d a ga ipak u p o tre b i, zato to je m n o g o efikasniji.
U ovom sluaju, p revodilac pravi o bjek at tip a StringBuiler da bi n apravio znakovni
niz s i etiri p u ta poziva a p p e n d ( ), p o je d n o m za svaki o d delova. N ajzad, poziva
to S tring ( ) da bi nap rav io rezultat, koji sp rem a (asem blerskom n ared b o m astore_2) kao s.
Pre nego to zakljuite d a je d o v o ljno svu da u p o treb ljavati objekte tipa String i p rep u -
stiti p rev o d io cu da se sta ra za efikasnost, p o g led ajm o ta rad i prevodilac. Evo p rim e ra
koji p rav i String na dva n ain a : k oristei objekte tip a String, o d n o sn o ru n im p ro g ram i-
ran je m p o m o u klase StringBuilder:
//: zn ak ov ni ni zo vi/KudaStringBuilder.java
public class Ku da St ri ng Bu il de r {
public String implicitno(String[] polja) {
String rezultat =
for(int i = 0; i < pol j a . 1ength; i++)
rezultat += pol j a [ i ] ;
return rezultat;
1
Poglavlje 13: Znakovni nizovi 395
O b ra tite p an ju na redove 8: i 35: koji zajedno ine petlju. Red 8: sadri n are d b u integer
co m p are g reater th an o r equal to (celobrojnog p o red en ja vee ili jed n ak o ) o p eran a d a na
steku i skae na 38: kada petlja zavri rad. Red 35: (n ared b a goto) je v raanje n a p o eta k
petlje, red 5:. Vano je p rim etiti da se konstrukcija StringBuildera odigrava u n u ta rte petlje,
to znai da ete d o b iti n o v objekat tip a StringBuilder svaki p u t kada p ro ete kroz petlju.
O vo su b ajtk o d m e to d e eksplicitno():
8: iconst_0
9: isto re _3
10: iload_3
11: alo ad _l
12: arraylength
13: if_icm pge 30
16: aload_2
17: alo ad _l
18: iload_3
19: aaload
20: in v o k e virtu a l #5; // S trin g B u ild e r.a p p e n d :()
23: pop
24: iin c 3, 1
27: goto 10
30: aload_2
31: in v o k e virtu a l #6; // S t r in g B u ild e r . t o S t r in g :()
34: areturn
N e sam o d a je p etlja k raa i jed n o stav n ija, n eg o m eto d a p rav i sa m o jed a n o b jek at tip a
StringBuilder. E ksplicitno p rav ljen je StringBuildera o m o g u av a d a u n a p re d zadate nje-
govu veliinu u koliko zn ate koliki treb a d a b u d e, tak o da ne m o ra uvek iznova da pravi
sebi bafer.
D akle, kada pravite m e to d u to S trin g ( ), ako su o p eracije jed n o stav n e pa prevodilac
m o e sam d a ih shvati, p o p ra v ilu p re p u stite n jem u d a rezu ltat izrau n a na razb o rit
nain . Ali ako p ro g ra m o b u h v a ta k ru e n je k ro z p etlju , u m e to d i to S trin g ( ) treb a ekspli-
citn o da n avedete StringBuilder, ovako:
Nenamerna rekurzija
Poto su Javini sta n d a rd n i k o n tejn eri, kao i sve d ru g e klase, nasleeni iz klase Object, oni
sadre m e to d u to S trin g ( ). O n a je redefinisana d a b i k o n tejn eri, kao i o bjekti koje sadre,
m o g li d a se predstav e u oblik u zn akovnog niza, tj. tip a String. U n u ta r klase ArrayList, n a
p rim er, m e to d a to S trin g ( ) prolazi kroz elem en te k o n tejn era i poziva m e to d u toS tring( )
svakog elem en ta.
p u b lic c la s s Is p is iv a n je A rr a y L is te (
p u b lic s t a t i c void m a in (S trin g [] args) {
ArrayList< Coffee> kafe = new A rra y List< C o ffe e > ();
fo r(C o ffe e c : new C o ffe eG en erato r(lO ))
k a fe .a d d (c );
System .out. p r in t l n ( k a f e ) ;
}
} /* Is p is :
[Americano 0, L a tte 1, Americano 2, Mocha 3, Mocha 4, Breve 5,
Americano 6, L a tte 7, Cappuccino 8, Cappuccino 9]
* ///:-
//: znakovni_nizovi/BeskonacnaRekurzija.ja va
// S lu a jn a re k u rz ija .
// {RunByHand}
398 Misliti na Javi
import j a v a . u t i l .* ;
pu b lic c la s s BeskonacnaRekurzija {
p ub lic S trin g to S trin g O {
return " Adresa objekta klase BeskonacnaRekurzija: 11
+ th is + "\ n ";
}
public s t a t ic void m a in (S trin g [] args) {
List<BeskonacnaRekurzija> v = new A rrayList< Beskon acn aRekurzija> ();
f o r ( i n t i = 0; i < 10; i++)
v.add(new B eskon acn aReku rzijaO );
S y s te m .o u t.p rin tln (v );
}
} III-.-
A ko n ap ra v ite objek at klase BeskonacnaRekurzija i zatim ga ispiete, d o b iete bes-
k raja n n iz izuzetaka. To e se d esiti i ako stavite o b jek te klase BeskonacnaRekurzija u
n ek i k o n tejn er klase ArrayList i ispiete taj k o n te jn e r k ao to je o vde p rik a z an o . Z apravo
se deava au to m a tsk a konverzija tip a u String. K ada kaete:
Formatiranje izlaza
Jed n a o d d u g o prieljkivanih m o g u n o sti koja se n ajzad pojavila u Javi SE5 jeste fo rm a-
tira n je izlaza u stilu C -ove n a re d b e p r in tf( ). N e sam o d a to p o jed n o stav lju je izlazni k o d ,
neg o p ro g ra m e rim a u Javi daje m o n u alatk u za o d re iv an je fo rm a tira n ja i p o rav n av an ja
izlaza.2
Metoda printff)
C -o v a fun k cija p rin tf( ) n e sastavlja nizove kao Java, n ego p rim a zn a k o v n i n iz za fo r m a ti-
ranje i u njega um ee v red n o sti, fo rm a tira ju i u h o d u . U m esto d a za n ad o v eziv an je teksta
i p ro m e n ljiv ih u n u ta r n av o d n ik a u p o treb lja v a p rek lo p ljen o p e ra to r + (koji u C -u nije
p re k lo p ljen ), p rin tf ( ) u p o tre b lja v a p o se b n e o znake koje p o k a z u ju g d e tre b a u m e tn u ti
p o d a tk e . Iza n jih sledi lista a rg u m e n a ta koji se u m eu u zn ak o v n i n iz za fo rm a tira n je ,
m e u s o b n o od v ojenih zarezim a.
Na p rim er:
System.out.format()
U Javu SE5 je uv ed en a m eto d a fo rm a t( ), d o stu p n a o b je k tim a tip a P rin tS tre a m ili P rin t-
W riter (o kojim a ete vie saznati u poglavlju Javin ulazno-izlazni sistem ), koja o b u h v ata
sta n d a rd n i izlazni to k System.out. M eto d a fo rm a t( ) je n ap rav ljen a p o u z o ru na C -o v u
fu n k ciju p rin tf( ). Za nostalgiare su n ap rav ili ak i m e to d u p rin tf ( ) koja sam o poziva
m e to d u fo rm a t( ). Evo je d n o sta v n o g p rim era :
/ / : zn ak ovninizovi/JednostavnoForm atiranje.java
// S t a r i nain:
Syste m .o u t.p rin tln ("R e d 1: [" + x + " 11 + y +
// Novi nain:
System .out.form at("Red 1: [%d % f]\ n ", x, y ) ;
// i l i
Sy ste m .o u t.p rin tf("R e d 1: [%d % f]\ n ", x, y ) ;
}
} /* Is p is :
Red 1: [5 5.332542]
Red 1: [5 5.332542]
Red 1: [5 5.332542]
* ///:-
Klasa Formatter
Svu n o v u Javinu fu n k cio n a ln o st za fo rm a tira n je sadri klasa Form atter iz p ak e ta ja-
va.util. Klasu Form atter m o ete sm a tra ti prev o d io cem koji zn ak o v n i n iz za fo rm a tira n je
i p o d a tk e p retv ara u eljeni rezu ltat. Kada p rav ite o b jek at tip a Formatter, n jeg o v o m k o n -
s tru k to r u prosledite p o d a ta k gde da poalje rezultat:
} /* Is p is :
Kornjaa Tom je na (0,0)
Kornjaa Teo je na (4,8)
Kornjaa Tom je na (3,4)
Kornjaa Teo je na (2,5)
Kornjaa Tom je na (3,3)
Kornjaa Teo je na (3,3)
* ///:-
Specifikatori formata
Za o dredivan je razm aka i p o rav n av anja p rilik o m u m e ta n ja p o d a ta k a p o tre b n i su sloe-
niji specifikatori form ata . O vo je n jiho va o p ta sintaksa:
N ajm an ju veliinu polja zadajete p a ra m e tro m irin a. Form atter jem i da e p o lje biti
iroko n ajm an je o re en bro j zn akova tak o to p o p o tre b i d o d a je razm ake. Podaci se
p o d ra zu m ev an o poravnavaju ud esn o, ali to m o ete redefin isati stav ljan jem - u odeljak
indikatora.
P aram e ta r preciznost je su p ro ta n irini, je r zadaje m a k sim u m . Za razliku o d irine koja
je p rim enljiv a na sve tipove konverzije p o d a ta k a i jed n a k o rad i za sve, preciznost im a razna
znaenja za razliite tipove. Za znako vn e nizove, sp ecifik ato r preciznost zadaje najvei
broj znakova objekta tip a String koje treb a ispisati. Z a b rojeve s p o k re tn im zarezom , pre-
ciznost zaaje bro j d ecim aln ih m esta koje treb a ispisati (p o d ra z u m e v a se 6); ako decim ala
im a previe, Java e rezu ltat zao k ru iti, a ako ih im a p rem alo , d o d a e p ratee nule. Poto
celi brojevi n em aju razlom ljen deo, preciznost se n a njih ne m oe p rim e n iti, i ob iete
izuzetak ukoliko u p o tre b ite p recizn o st s k o n v erzijo m c elo b ro jn o g tipa.
U n a re d n o m p rim e ru , specifikatori fo rm a ta su u p o treb lje n i za ispisivanje ra u n a za
kup ov inu :
//: znakovninizovi/Racun.java
import j a v a . u t i l .* ;
f.form at("%-15s %5s %10s\n", " A r t ik a l " , "K o l", "C en a");
f.form at("%-15s %5s %10s\n", " --- " , " " ......... " ) ;
}
pu b lic void p r in t(S tr in g ime, in t k o l, double cena) {
f.form at("%-15.15s %5d % 10.2f\n", ime, k o l, c e n a );
ukupno += cena;
}
p u b lic void p r in tT o ta l() {
f.form at("%-15s %5s %10.2f\n", "P o re z ", ukupno*0.06);
f.fo r m a t( %-15s %5s %10s\n", " ---- " ) ;
f.form at("%-15s %5s % 10.2f\n", "Ukupno",
ukupno * 1.06);
}
p u b lic s t a t ic void m a in (S trin g [] args) {
Racun racun = new R acun();
r a c u n .p r in t T it le ( ) ;
racu n.p rint("D eko v arobni p a s u lj" , 4, 4 .2 5 );
ra c u n .p r in t("P rin c e z in g raak", 3, 5 .1 );
ra c u n .p rin t("K a a t r i medveda", 1, 14.29);
ra c u n .p r in tT o ta l( ) ;
}
} /* Is p is :
A rti kal Koi Cena
Ukupno 25.06
*///:-
Znakovi konverzije
d Celi broj (napisan decimalno)
c Unicode znak
b Logika vrednost (tipa Boolean)
40 4 Misliti na Javi
Znakovi konverzije
s Znakovni niz
f Broj s pokretnim zarezom (napisan decimalno)
e Broj s pokretnim zarezom (napisan u naunoj notaciji)
X Celi broj (napisan heksadecimalno)
h K[ju za heiranje (napisan heksadecimalno)
% Literal %
p u b lic c la s s Konverzija {
p u b lic s t a t i c void m a in (S trin g [] args) {
Form atter f = new Fo rm atter(System .o u t);
in t v = 121;
S y s te m .o u t.p rin tln ("v = 121");
f.fo r m a t("d : %d\n", v ) ;
f.fo r m a t(" c : %c\n", v ) ;
f,fo r m a t("b : %b\n", v ) ;
f .form atC 's: %s\n", v ) ;
// f . f o r m a t ( " f : % f\ n ", v ) ;
// f.fo r m a t("e : %e\n", v ) ;
f.fo r m a t("x : %x\n", v ) ;
f.fo r m a t("h : %h\n", v ) ;
B ig ln te g e r w = new Biglnteger("50000000000000");
S y s te m .o u t.p rin tln (
"w = new B ig In te g e r( \ " 50000000000000\" ) " ) ;
f.fo r m a t("d : %d\n", w );
// f.fo r m a t(" c : %c\n", w );
f.fo r m a t("b : %b\n", w );
f.fo r m a t( s: %s\n", w );
// f .f o r m a t (" f : % f\n ", w );
Poglavlje 13: Znakovni nizovi 405
double x = 179.543;
S y s te m .o u t.p rin tln ("x = 179.543");
// f.fo r m a t("d : %d\n", x );
// f.fo rm a tC 'c : %c\n", x );
f.fo r m a t("b : %b\n", x );
f .fo r m a t (" s : % s\n", x ) ;
f . f o r m a t ( " f : % f\ n ", x ) ;
f.fo r m a t(" e : %e\n", x ) ;
// f.fo r m a t("x : %x\n", x );
f.fo r m a t(" h : %h\n , x );
d: 50000000000000
b: true
s: 50000000000000
x: 2d79883d2000
h: 8842ala7
x = 179.543
b: true
s: 179.543
f : 179.543000
e: 1.795430e+02
h: lef462c
y = nova Konverzija()
b: true
s: Konverzija@9cabl6
h: 9cabl6
z = false
b: false
s: false
h: 4d5
* ///:-
R edovi p retv o ren i u k o m e n ta re n isu valid n i za taj tip pro m en ljiv e; n jih o v im izvra-
v an jem biste izazvali izuzetak.
O b ra tite p a n ju n a ko nverziju b, koja ra d i za sve g o rn je pro m en ljiv e. Iako je validna za
sve tipove a rg u m en a ta, ne p o n a a se k ao to m o d a pretp o stav ljate. Za p ro ste logike
tipove (boolean) i o b jek at tip a Boolean, n jen rezu ltat je true ili false, u zavisnosti o d
v red n o sti. M e u tim , za sve d ru g aije arg u m e n te , rezu ltat je uvek true ukoliko tip argu-
m e n ta nije null. ak i n u m erik a v re d n o st nula, koja je u m n o g im jezicim a (i C -u ) sino-
n im za false, daje true, p a m o ra te b iti o p re zn i kada tu konverziju u p o treb ljav ate s
tip o v im a koji n isu logiki.
Im a jo tipo v a konverzija i d ru g ih o p cija sp ecifik ato ra fo rm a ta . To je o p isa n o u d o k u -
m en taciji razvojnog o k ru en ja JDK za klasu Formatter.
V e b a 5 : (5) Za sve o sn o v n e tip o v e konverzija iz g o rn je tabele, nap iite najsloeniji m o -
gui izraz za fo rm atiran je, tj. u p o tre b ite sve m o g u e specifikatore fo rm a ta d o stu p n e za taj
tip konverzije.
String.format()
Java SE5 se ugledala i n a C -o v u fu n k ciju s p rin tf( ) k ojom se prave znakovni nizovi.
S tring.form at( ) je statin a m eto d a koja p rim a iste arg u m e n te kao Form atterova m etoda
fo rm a t( ), ali vraa ob jek at tip a String. P o d esn a je kada m e to d u fo rm a t( ) treb a da zovete
sam o je d a n p u t:
// : znakovninizovi/IzuzetakBazePodataka.java
S trin g .fo rm at( ) sam o n a p ra v i o b jek at tip a Form atter i p ro sledi m u vae arg u m en te,
ali k o ristei ovu m e to d u d o b ija te jasn iji i razu m ljiv iji k o d nego da sve to rad ite ru n o .
p u b lic c la s s Hex {
p u b lic s t a t ic S trin g fo rm a t(b yte [] podaci) {
S t r in g B u i1der re z u lta t = new S t r in g B u ild e r ();
in t n = 0;
fo r (b y te b : podaci) {
i f ( n % 16 == 0)
re z u lta t.a p p en d (S trin g .fo rm at("% 0 5 X : " , n )) ;
r e z u lt a t . append(String.form at("%02X " , b ) );
n++;
i f ( n % 16 == 0) re z u lta t.a p p e n d ("\ n ");
}
re z u lta t.a p p e n d ("\ n ");
return r e z u lt a t .t o S t r in g O ;
}
p u b lic s t a t ic void mai n (S t r in g [] args) throws Exception {
i f ( a r g s . 1ength == 0)
// T e s tira n je isp isivan jem datoteke ove klase:
S y s te m .o u t.p rin tln (
fo r m a t(B in a r y F ile .r e a d ("H e x .c la s s " )));
el se
Sy stem .o u t.pri n t l n (
fo rm a t(B in a ryF ile .re a d (n e w F i le ( a r g s [ 0 ] ) ) ) ) ;
}
408 Misliti na Javi
} /* Is p is : (prim er)
00000: CA FE BA BE 00 00 00 31 00 52 0A 00 05 00 22 07
00010: 00 23 OA 00 02 00 22 08 00 24 07 00 25 OA 00 26
00020: 00 27 OA 00 28 00 29 OA 00 02 00 2A 08 00 2B OA
00030: 00 2C 00 2D 08 00 2E OA 00 02 00 2F 09 00 30 00
00040: 31 08 00 32 OA 00 33 00 34 OA 00 15 00 35 OA 00
00050: 36 00 37 07 00 38 OA 00 12 00 39 OA 00 33 00 3A
* ///:-
Regulami izrazi
Regularni izrazi su ve d u g o sastavni deo sta n d a rd n ih U nixovih alatki sed i awk, i jezika Py-
th o n i Perl (neki tvrde da su o n i glavni razlog to je Perl tako uspean). U Javi su alatke za
o b ra d u znakovnih nizova ranije bile delegirane u klase String, StringBuffer i StringToke-
nizer. U p o re e n ju s reg u larn im izrazim a, te alatke su im ale relativno sk ro m n e m ogunosti.
R egularni izrazi su m o n e i fleksibilne alatke za o b ra d u teksta. O n e o m o g u av a ju p ro -
gram sk o zadavanje sloenih u zo rak a teksta koji m o g u biti p ro n a e n i u u la z n o m znakov-
n o m n izu. K ada te uzorke p ro n a e te , m o ete da reagujete kako god hoete. Iako je
sin taksa re g u larn ih izraza isp rv a teka, n jih o v saet d in a m i k i jezik m o ete u p o tre b iti za
reavanje svih vrsta zadataka u o b ra d i, p ro n a la en ju , izb o ru , u re iv a n ju i p ro v eri znakov-
n ih nizova, n a p o tp u n o u o p te n nain.
Osnove
R egularan izraz je nain o p isivanja zn ak o v n ih nizova na u o p te n n ain , ta k o d a m oete
rei: ,A ko znakovni niz im a ovo u sebi, o n d a od govara o n o m e to tra im . Na p rim er,
kako b iste saoptili da isp red b ro ja m o e, ali n e m o ra biti znak m in u s, piete m in u s i iza
njega zn ak pitanja:
_?
D a b iste opisali celi broj, kaete d a je to je d n a ili vie cifara. U re g u la rn im izrazim a, ci-
fra (engl. digit) opisuje se sa \d. U k oliko ste im ali posla s re g u larn im izrazim a u d ru g im
jezicim a, o d m a h ete u o iti razlik u u o b ra d i o b rn u tih kosih crta. U d ru g im jezicim a \\
znai: H o u d a u m e tn e m o b i n u (d o slo v n u , literaln u ) kosu c rtu u re g u laran izraz. Ne
tre b a jo j p rid a v ati specijalno znaenje. U Javi, \\ znai: U m eem k osu c rtu u regularan
izraz, p a sledei znak im a sp ecijaln o zn aen je. N a prim er, re g u laran izraz za cifru je \\d.
A ko ho ete da u m e tn e te stv arn u k o su c rtu , piete \\\\. M e u tim , za prelazak u novi red i
ta b u la to r pie se sam o jedna kosa crta: \n \t.
Poglavjje 13: Znakovni nizovi 409
-?\\d+
p u b lic c la s s PodudaranjeCelihBrojeva {
p ub lic s t a t ic void m a in (S trin g [] args) {
Sy ste m .o u t.p rin tln ("- 1 2 3 4 ".m a tc h e s("- ?\\ d + "));
S y ste m .o u t.p rin tln ("5 6 7 8 ".m a tc h e s("- ?\\ d + "));
System .o u t.p rin tln ("+ 9 1 1 ".m atch es( - ?\ \ d + "));
Sy ste m .o u t.p rin tl n("+ 9 11 ".m atches("( - 1\\+)?\\d+")) ;
}
} /* Is p is :
true
tru e
fa l se
true
* ///:-
Prva dva izraza o d go v araju , ali trei p o in je zn ak o m +, k jji e sam p o sebi leg itim an ,
ali ne o d g ovara naem re g u la rn o m izrazu. Z ato n a m treb a n a a ii d a k a e m o : m o e poeti
z n ak o m + ili U reg u larn im izrazim a, zag rad e im a ju efekat g a ip is a n ja izraza, a vertik al-
na crta I znai logiko ili (O R ). D akle izraz
(-|W + )?
p ub lic c la s s Cepanje {
p ub lic s t a t ic Strin g vite z o v i =
"Then, when you have found the shrubbery, you must " +
"cu t down the m ightiest tre e in the f o r e s t . . . " +
" w i t h . . . a h e rrin g !";
pu b lic s t a t ic void s p li t ( S t r in g re g iz ) {
System .out. pri ntl n(
A rra y s .to S tr i ng(vi te z o v i. s p li t ( r e g i z ) ) ) ;
410 Misliti na Javi
//: znakovninizovi/Zamena.java
import s t a t ic n e t.m in d v ie w .u til. P r i n t . * ;
p ub lic c la s s Zamena {
s t a t ic S trin g s = S p li t t in g . v i t e z o v i;
p u b lic s t a t i c void m a in (S trin g [] args) {
p r in t(s .r e p la c e F ir s t (" f\ \ w + ", " l o c a t e d " ) ) ;
p ri n t ( s . re p la c e A l1("s h ru b b e ry |tre e |h e rri n g ", "banana")) ;
}
} /* Is p is :
Then, when you have located the shrubbery, you must cut down the
m ightiest tre e in the f o r e s t . . . w it h ... a herrin g!
Then, when you have found the banana, you must cut down the m ig h tiest banana
in the f o r e s t . . . w it h . . . a banana!
* ///:-
P rv o m izrazu o d g o v ara slovo f i je d a n ili vie zn akova koji m o g u b iti d eo rei (povedite
ra u n a o to m e d a je ovoga p u ta w m alo slovo). Z am en ju je se sam o p rv i p ro n a e n i p o d u -
d a rn i deo, pa re ,,fo u n d biva zam e n jen a reju ,,located.
D ru g o m izrazu od g o v ara bilo koja o d tri rei koje su razdvojene v ertik aln im c rta m a
(logikim O R ), i zam e n ju ju se svi p ro n a e n i p o d u d a rn i delovi.
Poglavlje 13: Znakovni nizovi 411
Znakovi
B Znak B
\xhh Znak iji je heksadecimalni kod oxhh
Nuhhhh Unicode znak iji je heksadecimalni kod oxhhhh
\t Tabulator
\n Prelazak u novi red
V Vraanje na poetak tekueg reda
\f Prelazak na novi list
\e Znak Esc (izlaz)
Snaga reg u la rn ih izraza najbolje se vidi u d efin isan ju klasa znakova. Evo n ek ih tip i n ih
nain a p ravljenja klasa znakova i n ekih u n a p red d efin isan ih klasa:
Znakovi
Bilo koji znak
fabc] Bilo koji od znakova a. b ili c (isto to i alblc)
["abc] Bilo koji znak osim a, b ili c (negacija)
[a-zA-Z] Bilo koji znak od a do z ili od A do Z (opseg)
[abcfhijj] Bilo koji od znakova a,b,c, h,i.j (isto to i alblclhlilj) (unija)
[a-z&&[hij]J Bilo koji od znakova h, i ili j (presek)
\s Bilo koji od znakova za belinu (razmak, tabulator, prelazak u novi red, prelazak
na novi list, vraanje na poetak tekueg reda)
\S Bilo koji znak sem znakova za belinu (fA\s])
412 Misliti na Javi
Znakovi
\d Numerika cifra [0-9J
\D Bilo koji znak sem znakova za cifre [A0-9]
\w Bilo koji znak koji moe biti deo rei [a-zA-Z_0-9]
\W Bilo koji znak sem znakova koji mogu biti deo rei [A\w]
O vde sm o pok azali sam o m ali d eo m o g u ih re g u la rn ih izraza; da b iste lako p ristu p ali
svim m o g u im u zo rc im a re g u la rn ih izraza, stra n ic u JD K d o k u m e n ta c ije za ja -
v a .u til.re g e x .P a tte rn p re tv o rite u obeleiva.
Logiki operatori
XY X, a potom Y
XIY X ili Y
(X) Grupa koju treba pronai. U nastavku izraza, /tu grupu za hvatanje oznaavate sa \i.
Izrazi za granice
A
Poetak reda
$ Kraj reda
\b Granica rei
\B Granica koja ne moe biti deo rei
\G Kraj prethodno pronadene podudarnosti
//: znakovninizovi/Rudolph.java
p ublic c la s s Rudolph {
pu b lic s t a t i c void m a in (S trin g [] args) {
fo r (S tr in g uzorak : new S t r i n g [ ] { "Rudolph",
" [rR ]u d o lp h ", " [ r R ] [ a e i o u ] [ a - z ] o l , "R .* " ))
Syste m .o u t.p rin tln ("R u d o lp h ".m a tc h e s(u z o rak )) ;
}
} /* Is p is :
true
true
true
true
* ///:-
N aravno, n e bi tre b a lo pisati najtee shvatljiv reg u laran izraz, nego najjednostavniji
koji zavrava p o sao . K ada p o n e te d a piete nove reg u larn e izraze, vero v atn o ete esto
u p o treb ljav ati svoj k o d kao referen cu .
Poglavlje 13: Znakovni nizovi 413
Kvantifikatori
K vantifikator o p isu je n a in n a koji u z o ra k a p so rb u je u lazn i tekst:
Pohlepno: ukoliko se d ru g a ije ne n a re d i, k v an tifik ato ri su p o h le p n i (engl. greedy).
P o h le p an izraz p ro n alaz i sve m o g u e p o d u d a rn o s ti sa u zo rk o m . T ip ian u z ro k p ro -
b lem a jeste p re tp o sta v k a d a e se izraz p o d u d a riti sam o s p rv o m p o d u d a rn o m g ru -
p o m znakova, a o n je zap rav o p o h le p a n i nastavie d a tra i sve d o k n e p ro n a e
najvei m o g u i p o d u d a rn i zn ak o v n i niz.
Rezervisano: O vaj k v a n tifik a to r se obeleava z n ak o m p ita n ja, a p ro n a laz i m in im a -
lan b ro j znakova p o tre b a n za p o d u d a ra n je sa u zo rk o m . N aziva se i lenj, tn inim alno
podudarajui, nepohlepan.
Posesivno: tr e n u tn o d o stu p a n sam o u Javi (u d ru g im jezicim a ne) i n a p re d n iji, p a ga
vero v atn o n eete o d m a h u p o treb ljav ati. Kada se re g u laran izraz p rim e n i n a zna-
kovni niz, o n g en erie m n o g o stan ja d a bi m o g ao d a se v ra ti ako n e u sp e d a nae
p o d u d a rn o s t. P osesivni k v an tifik ato ri n e uv aju ta m e u sta n ja i tim e spreavaju
vraanje. M oete ih u p o tre b iti k ako b iste spreili reg u laran izraz da p odivlja, a i d a
bi rad io efikasnije.
Im ajte u v id u d a izraz X esto treb a da zatv o rite u zag rad e d a bi rad io o n a k o kako
hoete. N a p rim e r:
abc+
(abc)+
R eg u larn i izrazi e vas Iako p rev ariti; u p o re en ju s Javom , to je sasvim d ru g aiji jezik.
414 Misliti na Javi
CharSequence
Interfejs CharSequence u tv r u je o p tu defin iciju niza zn ak o v a a p stra h o v a n u iz klasa
CharBufFer, String, StringBuffer ili StringBuilder:
in te rfa c e CharSequence {
c h a rA t(in t i ) ;
le n g th ();
subSequence(int pocetak, in t k r a j ) ;
t o S t r in g O ;
}
O b je k at tip a P attern pred stav lja p re v e d e n u v erziju reg u larn o g izraza. Kao to v id ite u
p re th o d n o m p rim e ru , za pravljenje o b jek ta tip a M atcher o d p rev ed en o g o b jek ta tip a
Pattern m o ete u p o tre b iti m e to d u m a tc h e r( ) i ulazni znak o v n i niz. I klasa Pattern im a
sta ti n u m eto d u :
koja isp itu je da li regiz o d g o v ara celom u la z n o m nizu znakova (o b jek tu tip a CharSe-
quence), i m e to d u s p lit( ) koja p ro izv o d i niz o b jek ata tip a String koji se p o d u d a ra ju s re-
g u la rn im izrazom regiz.
O b je k a t tipa Matcher g en eriete p o ziv o m m eto d e Pattern.m atcher( ) uz ulazni zna-
kovni niz kao arg u m e n t. Z a tim se o b je k a t tip a Matcher u p o treb ljav a za p ristu p a n je re-
z u ltatim a, je r se za u tv r iv an je u sp en o sti ili n eu p e n o sti razliitih vrsta p o d u d a ra n ja
u p o treb ljav aju njegove m eto d e:
boolean matches()
boolean loo k in g A t()
boolean fin d ()
boolean f in d ( in t s t a r t )
Veba 10: (2) Za reenicu Java now has regular expressions odredite da li e sledei iz-
razi pronai neko podudaranje:
''Ja v a
\B reg .*
n.w \s+ h (a|i)s
s?
s*
s+
S {4}
S {1 ).
s{0 ,3 )
na
"A r lin e ate eig ht apples and one orange w hile A nita hadn't any"
Metoda find()
M etoda M atcher.find( ) moe se upotrebiti za pronalaenje p o dudaranja vie uzoraka
u znakovnom nizu na koji je prim enjena. Na prim er:
p u b lic c la s s Pronalazenje {
p u b lic s t a t ic void m a in (S trin g [] args) {
Matcher m = Pattern .com pile("\\w + ")
.m atcher("Evening is f u l l of the lin n e t 's wings" ) ;
whi 1e(m .fi nd ( ) )
printnb(m .group() + 11 " ) ;
p r in t();
in t i = 0;
whi 1e (m .f in d (i) ) {
printnb(m .group() + 11 " ) ;
i++;
}
}
} /* Is p is :
Evening is f u l l of the lin n e t s wings
Evening vening ening ning ing ng g is is s f u l l f u ll u ll 11 1 of o f f the the
he e lin n e t lin n e t innet nnet net et t s s wings wings ings ngs gs s
* ///.-
Poglavlje 13: Znakovni nizovi 417
Uzorak \\w+ cepa ulaz na rei. M etoda fin d () radi kao iterator, poto se kroz ulazni
znakovni niz kree unapred. M eutim , drugoj verziji m etode fin d ( ) moete dati celobroj-
ni argum ent koji joj kazuje redni broj znaka za poetak pretraivanja - ta verzija zadaje
vrednost argum enta kao mesto pretraivanja, kao to se vidi iz rezultata.
Grupe
G rupe su regularni izrazi navedeni u zagradam a koji se naknadno m ogu pozivati preko
broja grupe. G rupa 0 je ceo izraz, grupa 1 je prva grupa u zagradi itd. Stoga u
A (B (C ))D
//: znakovninizovi/Grupe.java
import j a v a . u t i l .re g e x .*;
import s t a t ic n et.m in d vie w .u ti1. P r in t .* ;
p u b lic c la s s Grupe (
s t a t i c p ub lic fin a l S trin g PESMA =
"Twas b r i l l i g , and the s lit h y toves\n" +
"Did gyre and gimble in the wabe.\n" +
"A ll mimsy were the borogoves,\n" +
"And the mome raths outg rabe.\n\n" +
"Beware the Jabberwock, my son,\n" +
"The jaws th at b it e , the claws th at catch .\ n " +
"Beware the Jubjub b ird , and shun\n" +
"The frumious Bandersnatch.";
p u b lic s t a t ic void m a in (S trin g [] args) {
Matcher m =
Pattern.com pi1e("(?m )(\\S+ )\\s+ ((\\S+ )\\s+ (\\S+ ))$ ")
.matcher(PESMA);
418 Misliti na Javi
Ovo je poetak pesme ,,Jabberwocky Luisa Kerola, iz knjige Alisa iza ogledala. Uzorak u
regularnom izrazu im a vie grupa u zagradam a koje se sastoje od proizvoljnog broja znako-
va koji nisu beline (\S+) praenog proizvoljnim brojem znakova koji jesu beline (\s+). Cilj
je uhvatiti tri poslednje rei u svakom redu; kraj reda oznaava $. M eutim, uobiajeno po-
naanje je da se $ poredi s krajem celog ulaznog niza, pa regularnom izrazu m orate ekspli-
citno rei da obrati panju na znakove za prelazak u novi red u ulaznom nizu. To se postie
indikatorom uzorka (?m) na poetku niza (ubrzo emo razm otriti indikatore uzoraka).
Veba 12: (5) Prepravite program Grupe.java tako da broji sve razliite rei koje ne
poinju velikim slovom.
/ / : zn ak o vn in iz o vi/StartE n d .java
import j a v a . u t i 1. regex.*;
import s t a t ic n e t.m in d view .u ti1 .P r in t . *;
p ub lic c la s s StartEnd {
p u b lic s t a t i c S trin g ulaz =
"As long as there is in ju s t ic e , whenever a\n" +
"Targathian baby c rie s out, wherever a d istre ss\ n " +
"sig n al sounds among the s ta rs . . . W e 'll be th e re.\n " +
"This fin e ship, and th is fin e crew . . . \ n " +
"Never g ive up! Never su rre n d e r!";
p riv a te s t a t i c c la s s Is p is i {
p riv a te boolean regizOdstampan = f a ls e ;
p riv a te S trin g re g iz ;
Is p is i( S t r in g reg iz ) { t h is .r e g iz = re g iz ; }
void Is p is i( S t r in g poruka) {
if(!regizO dstam pan) {
p r in t(r e g iz );
regizOdstampan = tru e ;
}
p rin t(p o ru k a );
}
}
s t a t ic void is p it a j ( S t r i n g s, S trin g re g iz ) {
Is p is i d = new I s p i s i ( r e g i z ) ;
Pa ttern p = P a tte rn .c o m p ile (re g iz );
Matcher m = p .m a tc h e r(s );
whi 1e (m .fi n d ())
d .is p is i ("fin d () + m.groupO +
poetak = "+ m .s ta rt() + " k raj = " + m .e n d ());
if(m .lo o k in g A t()) // r e s e t() n ije potrebna
d .is p is i(" lo o k in g A t ( ) poetak = "
+ m .startO + " kraj = " + m .end());
if(m .m atches()) // re se t() n ije potrebna
d .is p is i ("matchesO poetak = 11
+ m .sta rt() + " kraj = " + m .end());
}
p u b lic s t a t ic void m a in (S trin g [] args) {
f o r (S t r in g in : u l a z . s p l i t ( " \ n " ) ) {
p r in t (" u la z : " + in ) ;
f o r (S t r in g regiz : new S t r i n g [ ] { "\\w *ere\\w*",
"\\w *e v e r", "T\\w+", " N e v e r .* ? !" } )
is p it a j ( in , re g iz );
}
}
} /* Is p is :
ulaz : As long as th ere is in ju s t ic e , whenever a
\w*ere\w*
f in d () 'th e r e ' poetak = 11 kraj = 16
\w*ever
fin d () 'whenever' poetak = 31 k raj = 39
ulaz : Targathian baby c rie s out, wherever a d is tre s s
\w*ere\w*
f in d () wherever' poetak = 27 kraj = 35
\w*ever
f in d () w herever poetak = 27 k raj = 35
T\w+
f in d () 'T a rg a th ia n ' poetak = 0 kraj = 10
lo o k in g A t() poetak = 0 kraj = 10
ulaz : signal sounds among the s ta rs . . . W e 'll be th ere.
\w*ere\w*
420 Misliti na Javi
Vodite rauna o tom e da e m etoda fin d ( ) pronai regularan izraz bilo ge u ulazu, ali
lookingA t( ) i m atch es( ) uspevaju sam o ako se regularan izraz p o d udara od samog
poetka ulaza. D ok m etoda m atch es( ) uspeva sam o ukoliko se ceo ulaz p o d u d ara s regu-
larnim izrazom , lookingAt( )4 uspeva ako se pod u dara sam o prvi deo ulaza.
Veba 13: (2) Prepravite program StartEnd.java tako da upotrebljava Grupe.PESMA kao
ulaz, ali da ipak proizvodi pozitivne rezultate za m etode fin d ( ), lookingA t( ) i m atches( ).
p u b lic c la s s O ln d ikatorima {
p u b lic s t a t i c void m a in (S trin g [] args) {
Pa tte rn p = P a tte rn . compi 1e ( " /\ ja v a ",
P a tte r n . CASE _ INSENSIT IVE | Pa tte rn .M U L T IL IN E ).
Matcher m = p.m atcher(
"ja v a ima re g iz\n ja va ima reg iz\n" +
"JAVA ima p r ili n o dobre regularne izraze\n"
"U je z ik u Ja va postoje reg u larn i i z r a z i " ) ;
whi1e (m .fi n d ( ) )
System .out. p ri n t l n(m.group( ) ) ;
}
) /* Is p is :
ja va
Java
JAVA
* ///:-
422 Misliti na Javi
Napravljen je uzorak koji se podudara s redovim a koji poinju reima java, Java, JAVA
itd. Podudaranje se ispituje za svaki red vierednog skupa (podudaranje delova koji
poinju na poetku niza znakova i slede iza graninika svakog reda u nizu znakova).
O bratite panju na to da m etoda g ro u p ( ) daje sam o deo koji se podudario.
Metoda splitf)
M etoda s p lit( ) cepa ulazni znakovni niz na niz String objekata, razgranienih datim re-
gularnim izrazom.
S t r in g [] split(CharSequence ulaz)
S t r in g [] split(CharSequence u la z, in t n ajviePod nizova)
Ovo je podesno za cepanje ulaznog teksta n a delove koji im aju zajedniki graninik:
p ub lic c la s s PrimerZaSpl i t {
p u b lic s t a t ic void m a in (S trin g [] args) {
S trin g ulaz =
"T h is! lunusual use! !o f exclam ation! Ip o in ts '1;
pri n t(A rra y s . to S tr i ng(
P a tte rn .c o m p ile ("! ! " ) . s p l i t ( u l a z ) ) ) ;
// Uradi samo prva t r i :
p rin t(A r ra y s .to S trin g (
Pattern.com pi1e ( " ! ! " ) . s p l i t ( u l a z , 3 ) ) ) ;
}
} /* Is p is :
[T h is, unusual use, of exclam ation, points]
[T h is, unusual use, of e x clam atio n !Ip o in ts]
* ///:-
Operacije zamene
Regularni izrazi su posebno podesni za zam enu teksta. Na raspolaganju su ove metode:
replaceFirst(String zamena) zam enjuje prvi p odudarni deo ulaznog znakovnog niza
zamenom.
replaceAll(String zamena) zam enjuje svaki p odudarni deo ulaznog znakovnog niza
zamenom.
Poglavlje 13: Znakovni nizovi 423
p u b lic c la s s Zamene {
p ublic s t a t ic void m a in (S trin g [] args) throws Exception {
S trin g s = T e x tF ile .re a d (''Z a m e n e .ja v a ");
// Pronai g o rn ji blok te k sta n aro ito pretvoren u komentar:
Matcher ulaztlM =
Pattern.com pi1e ( " / \ \ * ! ( . * ) !\ \ * / ", Pattern.DOTALL)
.m a tc h e r(s );
if(u la z U M .fin d ())
s = u lazU M .g ro u p (l); // Ono to hvataju zagrade
// Dva i v i e razmaka zameni jednim:
s = s .re p la c e A l1 (" { 2 , } " , " " ) ;
// Jedan i l i v i e razmaka na poetku svakog reda
// zameni s nula razmaka. Mora se u k lj u i t i reim MULTILINE:
s = s .re p la c e A ll ("(? m )/' +", " " ) ;
p r in t(s );
s = s .r e p la c e F ir s t ( " [a e io u ] " , " ( V0WEL1)" ) ;
S trin g B u ffe r sbaf = new S t r in g B u f f e r ( ) ;
Pattern p = P a tte r n .c o m p ile ("[a e io u ]" ) ;
Matcher m = p .m a tc h e r(s );
// Obradi podatke metode f in d () dok
// o b avlja zamene:
w h ile (m .fin d ())
m.appendReplacement (s b a f, m.groupO . toUpperC ase()) ;
// Umetni ostatak te k s ta :
m.appendTai1( s b a f ) ;
p r in t ( s b a f ) ;
}
424 Misliti na Javi
} /* Is p is :
H ere's a block of te x t to use as input to the reg u lar
expression matcher. Note th a t w e 'll f i r s t ex tract
the block of te x t by looking fo r the sp ecial d e lim ite rs ,
then process the ex tracted block.
H (VO W ELl)rE's A blOck Of tE x t tO UsE As InpUt tO
thE rEgUlAr ExprEssIOn mAtchEr. NOtE thAt w E 'll
f l r s t ExtrA ct thE blOck Of tE x t by lOOklng fOr
thE spEcIAl d E lIm ltE rs , thEn prOcEss thE
ExtrActEd blOck.
* ///:-
Metoda reset()
Postojei objekat tipa Matcher m etodam a re se t( ) moete prim eniti na nov niz znakova:
p u b lic c la s s Resetovanje {
p u b lic s t a t ic void m a in (S trin g [] args) throws Exception {
Matcher m = Pattern .com pi1e ( " [fr b ] [a iu ] [g x ] )
,m a tc h e r("fix the rug w ith b ag s");
Poglav[je 13: Znakovni nizovi 425
re se t( ) bez argum enata prim enjuje objekat tipa M atcher na poetak tekueg niza.
p u b lic c la s s JGrep {
p u b lic s t a t ic void m a in (S trin g [] args) throws Exception {
i f (a rg s . 1ength < 2) {
S y ste m .o u t.p rin tln ("U p o treb a : ja va JGrep regiz d a to te k e ");
S y s te m .e x it(0 );
}
Pa ttern p = P a tte r n .c o m p ile (a r g s [l]);
// It e r a c ij a kroz redove ulazne datoteke:
in t indeks = 0;
Matcher m = p .m a tc h e r ("");
fo r (S t r in g red : new T e x tF ile ( a r g s [ 0 ] ) ) {
m .re s e t(re d );
whi1e (m .fi nd( ) )
System .out.println(indeks+ + + " : " +
m.groupO + " : " + m .s t a r t ( ) ) ;
}
}
} /* Is p is : (prim er)
0: s trin g s : 4
1: sim ple: 10
2: the: 28
426 Misliti na Javi
3: S s ct: 26
4: c la s s : 7
5: s ta tic : 9
6: S trin g : 26
7: throws: 41
8: System: 6
9: System: 6
10: compile: 24
jll: through: 15
12: the: 23
13: the: 36
14: S trin g : 8
15: System: 8
16: s t a r t : 31
* ///:-
Veba 17: (8) Napiite program koji uitava datoteku Javinog izvornog koda (ije ime
zadajete na kom andnoj liniji) i prikazuje sve njene kom entare.
Veba 18: (8) Napiite program koji uitava datoteku Javinog izvornog koda (ije ime
zadajete na kom andnoj liniji) i prikazuje sve doslovno (Iiteralno) navedene znakovne ni-
zove u kodu.
Veba 19: (8) Na osnovu preth od ne dve vebe, napiite program koji pretrauje Javin iz-
vorni kod i ispisuje im ena svih klasa koje se spom inju u tom program u.
Poglavlje 13: Znakovni nizovi 427
//: znakovninizovi/ProstoCitanje.java
import ja v a .io .* ;
} /* Is p is :
Kako se zove?
Hajduk Veljko
Koliko godina ima? Koji je tvoj omiljeni broj tipa double?
(ulaz: <starost> <double>)
22 1.61803
Zdravo Hajduk Veljko.
Za 5 godina imae 27.
Moj omiljeni broj tipa double je 0.809015.
* ///.-
U polju ulaz koriste se klase iz paketa java.io koji nee biti zvanino predstavljen do
poglavlja Javin ulazno-izlazni sistem. Objekat tipa StringR eader pretvara znakovni niz u
tok podataka (engl. stream) koji se moe itati, i taj objekat se upotrebljava za pravljenje
428 Misliti na Javi
objekta tipa BufferedReader, poto BufferedReader im a m etodu readL ine( ). Zato se ob-
jekat ulaz moe itati red po red, kao da je standardni ulaz s konzole.
readL ine( ) pribavlja String za svaki red ulaza. Jednostavno je ako svaki red podataka
hoete da pretvorite u jedan ulaz, ali ukoliko su dve ulazne vrednosti u istom redu, stvari
se kom plikuju da bism o svaki ulaz mogli da analiziram o zasebno, red se m o ra podeliti
na dva dela. Ovde se podela obavlja kada se pravi num N iz, ali poto je m etoda sp lit( )
uvedena tek u J2SE1.4, pre se to m oralo raditi drugaije.
Klasa Scanner se koristi od Jave SE5. O na obavlja glavni deo posla oko leksikog ana-
liziranja ulaza:
//: znakovninizovi/BoljeCitanje.java
import java.util
K onstruktor klase Scanner prim a gotovo sve vrste ulaznih objekata - m edu njim a su
objekat tipa File (koji e takoe biti objanjen u poglavlju Javin ulazno-izlazni sistem),
objekat tipa InputStream , objekat tipa String ili u ovom sluaju objekat tipa Readable,
Poglavlje 13: Znakovni nizovi 429
p ub lic c la s s GranicnikKlaseScanner {
p u b lic s t a t ic void m a in (S trin g [] args) {
Scanner skener = new Scanner("12, 42, 78, 99, 4 2 ");
s k e n e r.u s e D e lim ite r ("\ \ s * ,\ \ s * ");
w h ile (s k e n e r.h a s N e x tIn t())
S y s te m .o u t .p r in tln (s k e n e r .n e x t In t());
}
} /* Is p is :
12
42
78
99
42
* ///:-
U ovom prim eru, kao graninici prilikom itanja datog znakovnog niza upotrebljeni
sli zarezi (oko kojih moe biti proizvoljna koliina belina). Ista tehnika se m oe upotrebiti
za uitavanje datoteka u kojim a su podaci razgranieni zarezima. Pored m etode
u se D e lim ite r() za zadavanje uzorka graninika, postoji i d e lim ite r() - on vraa tekui
objekat tipa P attern koji se upotrebljava kao graninik.
430 Misliti na Javi
/ / : z n a k o v n in iz o v i/ A n a liz a to rP re tn ji.ja v a
import ja v a .u t il.r e g e x .* ;
import j a v a . u t i l .* ;
p ub lic c la s s A n a liz a to rP r e tn ji {
s t a t ic S trin g p reteciPodaci =
"58.27.82.161@02/10/2005\n" +
"204.45.234.40@02/ll/2005\n" +
"58.27.82.161@02/ll/2005\n" +
"58.27.82.161@02/12/2005\n" +
"58.27.82.161@02/12/2005\n" +
"[S le d e i od eljak zapisnika s drugaijim formatom p o dataka]";
public s t a t ic void m a in (S trin g [] args) {
Scanner skener = new S c a n n e r(p re te ciP o d a ci);
S trin g uzorak = "(\\d + [.]\\d + [.]\\d + [.]\\d + )@ " +
" (\\d{2 }/\\d{2 }/\\d{4 })";
w hile(skener.hasN ex t(u zorak)) {
sk e n e r.n ex t(u zo rak );
MatchResult pronasao = sk en er.m a tch ();
S trin g ip = p ro n a sao .g ro u p (l);
S trin g datum = pronasao.group(2);
Sy stem .o u t.fo rm a t("Pretn ja dana %s od %s\n", datum .ip);
1
)
} /* Is p is :
Pre tn ja dana 02/10/2005 od 58.27.82.161
Pre tn ja dana 02/11/2005 od 204.45.234.40
Pre tn ja dana 02/11/2005 od 58.27.82.161
Pre tn ja dana 02/12/2005 od 58.27.82.161
Pre tn ja dana 02/12/2005 od 58.27.82.161
* ///:-
Klasa StringTokenizer
Pre regularnih izraza (koji su uvedeni u J2SE1.4) ili klase Scanner (koja se koristi od Jave
SE5), znakovni niz se cepao na lekseme p o m o u klase StringTokenizer. Ali sada se to
m nogo lake i saetije obavlja pom ou regularnog izraza ili klase Scanner. Pogledajte jed-
nostavno poreenje ldase StringTokenizer i druge dve tehnike:
p u b lic c la s s UmestoStringTokenizera {
p ub lic s t a t ic void m a in (S trin g [] args) {
S trin g input = "But I'm not dead y e t ! I fe e l happy!";
String Tokenizer stoke = new S trin g T o k e n iz e r(u la z );
w hile(stoke.hasM oreElem ents())
System .o u t.p rin t(sto k e.n ex tT o k en () + " " ) ;
S y s te m .o u t .p r in tln ();
S y s te m .o u t .p r in tln (A r r a y s .to S tr in g (u la z .s p lit (" " ) ) ) ;
Scanner skener = new Sc a n n e r(u la z );
w h ile (s k e n e r.h asN e x t())
S y ste m .o u t.p rin t(s k e n e r.n e x t() + " '') ;
}
} /* Is p is :
But I'm not dead y e t ! I fe e l happy!
[B u t, I'm , not, dead, y e t ! , I , f e e l , happy!]
But I'm not dead y e t ! I fe e l happy!
* ///:-
Pom ou regularnih izraza ili objekata tipa Scanner, znakovni niz m oete podeliti na
delove i korienjem sloenijih uzoraka - to bi bilo teko pom ou klase StringTokenizer.
Izgleda da m oem o bezbedno rei kako je StringTokenizer zastarela.
Saetak
Ranije je Javina podrka za obradu znakovnih nizova bila rudim entarna, ali u novijim iz-
danjim a jezika postoji m nogo sofisticiranija podrka usvojena iz drugih jezika. Sada je
podrka za znakovne nizove prilino potpuna, iako ponekad m orate paziti na efikasnost,
recimo prilikom upotrebe klase StringBuilder.
R eenja o d a b r a n ih vebi d a ta su u e le k tro n sk o m d o k u m e n tu Thinking in Java Annotated Solution
Guide , koji se m o e k u p iti na lo k a ji www.BruceEckel.com.
Podaci o tipu
Prepoznavanje tipa u vreme izvravanja (engl. ru n -tim e type identification, RTTI) omogu-
uje ustanovljavanje i upotrebu tipa objekta dok se progratn izvrava.
Ovo je tipian dijagram hijerarhije klasa u kom e se osnovna klasa nalazi na vrhu, a iz-
vedene klase se ravaju nie. Uobiajeni cilj u objektno orijentisanom program iranju jeste
da kod radi s referencama na osnovni tip (u ovom sluaju Oblik), jer ako kasnije odluite
da proirite program dodavanjem nove klase (kao to je Romboid, izveden iz klase Oblik),
to nee uticati na najvei deo koda. U ovom prim eru, m etoda crtaj() u interfejsu Oblik di-
namiki je povezana, pa program er klijent treba da poziva m etodu crtaj() preko generike
reference na Oblik. Metoda crtaj() se redefinie u svim izvedenim klasama, a poto je re
o dinam iki povezanoj m etodi, ona e se ponaati na odgovarajui nain ak i ako se po-
ziva preko generike reference na objekat klase Oblik. To je polim orfizam.
Stoga obino pravite odreeni objekat (Krug, Kvadrat ili Trougao), pretvarate ga u
optiji tip O blik (zanem arujete specifini tip objekta) i koristite tu referencu tipa Oblik u
ostatku program a.
Poglavlje 14: Podaci o tipu 433
a b s tra c t c la s s O blik {
void c r t a j ( ) { S y s te m .o u t.p rin tln (th is + . c r t a j O " ) ; }
a b s tra c t p ub lic S trin g t o S tr in g O ;
}
public c la s s Obli c i {
p u b lic s t a t ic void m a in (S trin g [] args) {
List<Oblik> lis t a O b lik a = A rr a y s .a s L is t (
new K ru g (), new K v a d ra t(), new Trougao()
);
f o r (0 b lik o b lik : lis t a O b lik a )
obl i k . c r t a j ( ) ;
}
} /* Is p is :
K r u g .c r t a j()
K v a d r a t.c r ta j ()
T ro u g ao .crtaj ()
* ///:-
O snovna klasa sadri m etodu crtaj() koja indirektno koristi m etodu toStringO za
tam panje identifikatora klase pom ou prosleivanja reference this m etodi Sy-
stem .out.println() (obratite panju na to da je m etoda toStringO deklarisana kao
apstraktna, da bi se njeni naslednici prim orali da je redefiniu i da b ise spreilo pravljenje
objekta tipa Oblik). Ukoliko se u izrazu za nadovezivanje znakovnih nizova (u kom e
postoje znak + i objekti tipa String) pojavi neki objekat, autom atski se poziva m etoda to-
StringO prosleenog objekta da bi predstavila njegov sadraj u objektu tipa String. Svaka
izvedena klasa redefinie m etodu toStringO klase Object, pa crtaj() na kraju u svakom
pojedinanom sluaju (polim orfno) tam pa neto razliito.
U ovom p rim eru, do svodenja navie dolazi kada se oblik smesti u List<Oblik>. Pri-
likom svoenja navie gubi se podatak o tom e da su objekti specifini tipovi klase Oblik.
to se tie niza, svi njegovi elem enti su tipa Oblik.
434 Misliti na Javi
U trenutku kada se elem ent ita iz niza, kontejner - za koji su svi njegovi elementi tipa
Object - autom atski pretvara svoj rezultat ponovo u Oblik. To je najosnovniji oblik pre-
poznavanja tipa u vreme izvravanja, poto se u Javi u vrem e izvravanja proverava pra-
vilnost svih konverzija tipova. Upravo to i jeste smisao prepoznavanja tipa u vreme
izvravanja: tokom izvravanja, prepoznaje se tip objekta.
U ovom sluaju, konverzija je sam o delimina: Object se konvertuje u tip Oblik, a ne
do kraja u tipove Krug, Kvadrat ili Trougao. U tom trenutku znate samo da je List<Ob-
Iik> p u n objekata tipa Oblik. Tokom prevoenja to osigurava kontejner i Javin sistem ge-
nerikih tipova, ali tokom izvravanja obezbeuje ih konverzija tipa.
Sada na scenu stupa polim orfizam , pa se kod koji se izvrava za Oblik bira prem a tom e
da li se radi o referenci na Krug, Kvadrat ili Trougao. Tako bi uglavnom trebalo da bude,
jer elite da najvei deo program a zna to m anje o specifinim tipovim a objekata, odnosno
da radi sa optom predstavom o porodici objekata (u ovom sluaju, Oblik). Takav kod e
se lake pisati, itati i odravati, a projekti e se lake prim enjivati, razum eti i menjati. Zbog
toga je polim orfizam jedan od optih principa u objektno orijentisanom program iranju.
M eutim , ta e se desiti ako p ri p rogram iranju im ate poseban problem koji se najlak-
e reava ako znate taan tip generike reference? Na prim er, pretpostavim o da elite
om oguiti korisnicima da posebnom bojom istaknu sve figure odreenog oblika? Tako bi
mogli da pron au sve trouglove na ekranu, jer su posebno obojeni. Ili, recimo, m etoda je
dobila zadatak da rotira sve oblike navedene u nekoj listi, ali krugove nem a smisla rotirati,
pa biste njih hteli da preskoite. To om oguuje prepoznavanje tipa u vreme izvravanja:
moete da zatraite od reference na Oblik da vrati taan tip na koji ukazuje i tako izabere
i izdvoji specijalne sluajeve.
U JVM-u se sve klase uitavaju dinamid, prilikom prve upotre v .To se eava kada program na-
pravi prvu referencu nekog statinog lana te klase. Ispostavlja se da ie i konstruktor statina metoda
klase, iako se za njega ne pie rezervisana re static. Zato se i pravljr >y; novog objekta te klase opera-
torom nevv smatra za referenciranje statinog ana te klase.
Dakle, program napisan na Javi ne uitava se po tp u n o pro ncgo to pone izvravanje,
nego se delovi program a uitavaju po potrebi. Po tom e se java razlikuje od m nogih tra-
dicionalnih jezika. D inam iko uitavanje om oguuje ponaanje koje je teko ili nem o-
gue postii u jezicim a sa statikim uitavanjem , kao to je C-H-,
Uitava klasa prvo proverava da li je uitan objekat tipa Class za taj tip. Ako nije, po-
drazum evani uitava ldasa uitava ga pronalaenjem datoteke .c lass s tim im enom . (Ui
uitava klasa, instaliran kao softverski dodatak, trai odgovarajue bajtkodove u bazi
podataka, na prim er.) Tokom uitavanja bajtkodova klase, JVv.' noverava da li su bajtovi
oteeni i da li sainjavaju lo kod. (To je jedan od naina nak< ' : r;> <i postiebezbedan rad.)
Kada se objekat Class za taj tip uita u m em oriju, k o r i s t i ; iravljenje svih objekata
tog tipa. Evo jednog program a koji e vas u to ubediti:
c la s s Bombona {
s t a t ic { p rin t("U c ita v a in Bombonu"); }
}
class Zvaka {
static { printC'Ucitavam Zvaku'1); }
}
class Kolacic {
static { print("Ucitavam Kolacic"); }
}
Ucitavam Zvaku
Nakon Class.forN am e("Zvaka")
Ucitavam K o lacic
Posle p ra v lje n ja Kolacica
* ///:-
Klase Bombona, Zvaka i Kolacic sadre blok static koji se izvrava p ri njihovom pr-
vom uitavanju. Informacije se ispisuju da biste znali kada se uitava odredena klasa.
O bjekti se u m etodi main() prave izm edu naredaba za tam panje, da bi se lake odredio
tren u tak uitavanja.
Vidite da se svaki objekat klase Class uitava tek kada zatreba, a inicijalizacija bloka
static obavlja se po uitavanju klase.
Posebno je zanimljiv red:
Svi objekti tipa Class pripadaju klasi Class. O bjekat tipa Class je isti kao i svi drugi
objekti, pa m oete da dobijete referencu na njega i da radite s njom (to radi uitava kla-
sa). Jedan od naina za dobijanje reference na objekat tipa Class jeste statina m etoda for-
Name() iji argum ent tipa String sadri tekstualno im e (pazite na pravopis, m ala i velika
slova!) odreene klase iju referencu hoete. Ova m etoda vraa referencu na objekat tipa
Class, koja je ovde bila zanem arena; m etodu forName() pozivam o radi njenog spored-
nog dejstva, a to je uitavanje klase Zvaka ako nije ve uitana. U postu p k u uitavanja
izvrava se statini blok klase Zvaka.
U p rethodnom prim eru, ako m etoda Class.forN am e( ) zakae zato to ne moe da
pronae klasu koju treba da uita, generisae izuzetak ClassNotFoundException. Ovde
sam o prijavljujem o problem i idem o dalje, ali u sofisticiranijim program im a mogli biste
pokuati da reite problem u bloku za o bradu izuzetaka.
Kad god budete hteli da upotrebite podatke o tipu prepoznate u vreme izvravanja, naj-
pre ete m orati da pribavite referencu odgovarajueg objekta Class. Jedan od podesnih
naina za to prua m etoda Class.forN am e( ), zato to vam nije potreban objekat tog tipa
da biste dobili referencu klase Class. M eutim , ukoliko ve im ate objekat tipa koji vas za-
nim a, referencu klase Class m oete pribaviti pozivanjem m etode getC lass( ) koja je deo
korenske klase Object. Ona vraa referencu klase Class koja predstavlja stvarni tip objek-
ta. Class ima m nogo zanimljivih m etoda; evo nekih od njih:
in te rfa c e Im aB aterije {}
in te rfa c e OtpornaNaVodu {}
in te rfa c e Puca {}
c la s s Igracka {
// Sled ei podrazumevani konstruktor p re tv o r ite u komentar
// da b is te v id e li izuzetak NoSuchMethodError od ( * !* )
Poglavlje 14: Podaci o tipu 437
Ig ra c k a () {}
Ig ra c k a (in t i ) {}
}
S y s t e m .e x it (l);
} c a tc h (Ille g a lA c c e ss E x c e p tio n e) {
p rin t("N e mogu da p ris tu p im ");
S y s t e m .e x it (l);
}
p r in t In f o (o b j.g e t C la s s ()) ;
}
} /* Is p is :
Ime k lase: typ e in fo .ig ra c k e .L e p a Ig ra c k a j e in t e r f e j s ? [ f a ls e ]
Prosto ime: Lepalgracka
Kanonsko ime : typ ein fo .ig ra c k e .L e p a lg ra c k a
Ime k lase: ty p e in fo .ig ra c k e .Im a B a te rije je in t e r f e j s ? [tru e ]
Prosto ime: Im aB aterije
Kanonsko ime : ty p e in fo .ig ra c k e .Im a B a te rije
Ime k lase: typeinfo.igracke.OtpornaNaVodu je in t e r f e j s ? [tru e ]
Prosto ime: OtpornaNaVodu
4 38 Misliti na Javi
Veba 5: (3) U program u Oblici.java realizujte m etodu rotiraj(O blik) tako da proverava
da li joj je zadato da rotira Krug (i neka ga u tom sluaju ne rotira).
Veba 6: (4) Prepravite program Oblici.java tako da istie sve oblike odreenog tipa, od-
nosno postavlja indikator u njim a. M etoda to S trin g ( ) svake izvedene potklase klase Ob-
Iik treba da pokae da li je taj O blik ,,istaknut.
Veba 7: (3) Prepravite ProdavnicaSlatkisa.java tako da svaku vrstu pravljenja objekta
odreuje argum ent koji se zadaje na kom andnoj liniji. Dakle, ako na kom andnoj liniji
pie java ProdavnicaSlatkisa Bombon, o nda se pravi sam o objekat tipa Bombon.
O bratite panju na to kako argum entom s kom andne linije odreujete Class objekte koji
e biti uitani.
Veba 8: (5) Napiite m etodu koja prim a objekat i rekurzivno ispisuje sve klase u njegovoj
hijerarhiji.
Veba 9: (5) Prepravite prethodnu vebu tako da se pom ou m etode Class.getDeclared-
F ields( ) prikazuju i podaci o poljim a klase.
Veba 10: (3) Napiite program koji utvruje da li je niz elem enata tipa char p ro st tip ili
pravi objekat.
Literali klase
Java nudi jo jedan nain za dobijanje reference na objekat klase Class, a to je korienje
literala klase (engl. class literal). U prethodno navedenom p rogram u to bi izgledalo ovako:
...ekvivalentno je ...
boolean.class Boolean TYPE
char.class Character.TYPE
byte.class Byte.TYPE
short.class Short.TYPE
int.class lnteger.TYPE
long.class Long.TYPE
float.class Float.TYPE
double.class Double.TYPE
void.class Void.TYPE
440 Misliti na Javi
Preporuujem da koristite verzije class ako je to mogue, poto se tako pristupa i obi-
nim klasama.
Zanimljivo je prim etiti da se pravljenjem reference na objekat tipa Class literalom
class, taj objekat ne inicijalizuje autom atski. Priprem a klase za upotrebu zapravo obu-
hvata tri koraka:
1. Uitavanje, koje obavlja uitava klasa. O na pronalazi bajtkod (obino na disku na-
vedenom u sistemskoj prom enljivoj classpath, ali to ne m o ra biti sluaj) i od njih
pravi objekat tipa Class.
2. Povezivanje. U fazi povezivanja proverava se bajtkod klase, dodeljuje m em orija sta-
tinim poljim a, i ako treba, razreavaju sve reference na druge klase koje ova klasa
pravi.
3 . Inicijalizaciju. Ako postoji natklasa, ona se inicijalizuje. Izvravaju se statini inici-
jalizatori i statini blokovi inicijalizatora.
Inicijalizacija se odgaa do prve reference na neku statinu m etodu (konstruktor je
im plicitno statian) ili na neko nekonstantno statino polje:
c la s s In ita b e la {
s t a t ic f in a l in t s t a t ic F in a l = 47;
s t a t ic fin a l in t s t a t ic F in a l2 =
C la s s ln it ia liz a t io n .s lu c a ja n . n e x t ln t (1000);
s t a t ic {
S y s t e m .o u t .p r in t ln ( " In ic ij a liz a c ija In i t a b e l e " ) ;
1
}
c lass In ita b e la 2 {
s t a t ic in t sta tic n a N e Fin a ln a = 147;
s t a t ic {
S y s t e m .o u t .p r in t ln ( " In ic ij a liz a c ija In it a b e le 2 " ) ;
}
}
c la s s In ita b e la 3 {
s t a t ic in t staticn a N eFin aln a = 74;
s t a t ic {
S y s t e m .o u t .p r in t ln ( " In ic ij a liz a c ija In it a b e le 3 " ) ;
}
}
C lass In ita b e la = In it a b e la .c la s s ;
Sy stem .o u t.p rin tln ("N ak o n p ra v lje n ja re f In it a b e le " ) ;
// Ne pokree i n i c i j a l i z a c i j u :
S y s t e m .o u t .p r in t ln ( In it a b e la .s t a t ic F in a l) ;
// Pokree i n i c i j a l i z a c i j u :
S y s te m .o u t .p r in t ln ( In it a b e la .s t a t ic F in a l2 ) ;
// Pokree i n i c i j a l i z a c i j u :
S y s te m .o u t.p rin tln (In ita b e la 2 .s ta tic n a N e F in a ln a );
Class In ita b e la 3 = C la s s .fo rN a m e ("In ita b e la 3 ");
Sy stem .o u t.p rin tln ("N ak o n p ra v lje n ja r e f In it a b e le 3 " ) ;
S y s te m .o u t.p rin tln (In ita b e la 3 .s ta tic n a N e F in a ln a );
}
} /* Is p is :
Nakon p ra v lje n ja r e f In ita b e le
47
I n i c i j a l i z a c i j a In ita b e le
258
I n i c i j a l i z a c i j a In ita b e le 2
147
I n i c i j a l i z a c i j a In ita b e le 3
Nakon p ra v lje n ja r e f In ita b e le 3
74
* ///:-
Class<Number> genericNumberClass = in t . c la s s ;
Ovo naizgled ima smisla jer se Integer nasleuje od klase Number. Ali to nije ispravno,
zato to Integer Class objekat nije potklasa N um ber Class objekta. (Razlika vam je mo-
da previe tanana; razm otriem o je poblie u poglavlju Generiki tipovi).
Da bih ublaio ogranienja prilikom korienja generikih Class referenci, upotreblja-
vam dokera koji je deo Javinih generikih tipova. Dokerski znak je ? i on naznauje bilo
ta. Stoga obinoj Class referenci u gornjem p rim eru m oem o dodati dokere i dobie-
mo iste rezultate:
U Javi SE5, Class<?> treba da im a prednost nad golim Class iako su ekvivalentni, a
golo Class, kao to ste videli, ne prouzrokuje upozorenje prevodioca. Prednost reference
Class<?> jeste to to pokazuje da nespecifinu referencu klase ne upotrebljavate sluajno
ili zbog neznanja, nego namerno.
Za pravljenje Class reference ograniene na odreeni tip ili bilo koji njegov podtip,
kom binujte dokera i rezervisanu re extends; tim e pravite ogranienje. Dakle, um esto da
kaete sam o Class<Number>, recite:
Poglavlje 14: Podaci o tipu 443
c la s s PrebrojaniC eoBroj {
p riv a te s t a t i c long b ro jac;
p riv a te f in a l long id = brojac++;
p u b lic S trin g to S trin g O { return L o n g .to S tr in g (id ); }
}
Vodite rauna o tom e da ova klasa m ora pretpostaviti kako svaki tip s kojim radi im a
podrazum evani konstruktor (onaj bez argum enata), inae ete dobiti izuzetak. Za ovaj
program prevodilac ne generie nikakvo upozorenje.
Zanimljiva se stvar deava kada za objekte tipa Class upotrebite generiku sintaksu:
m etoda new lnstance( ) vratie taan tip objekta, a ne sam o tip Object kako ste videli u
program u Ispitivanjelgracaka.java. To je donekle ogranieno:
Ako dobijete natklasu, prevodilac e dozvoliti samo da kaete kako je referenca natkla-
se neka klasa koja je natklasa klase Lepalgracka, kao to se vidi iz izraza Class<? super
Lepalgracka>. Nee prihvatiti deklaraciju CIass<Igracka>. To izgleda pom alo udno,
zato to getSuperclass( ) vraa osnovnu klasu (ne interfejs), a prevodilac u vrem e pre-
voenja zna koja je to klasa - u ovom sluaju, Igracka.class, a ne sam o neka natklasa od
Lepalgracka. U svakom sluaju, zbog te neodredenosti, povratna vrednost m etode
nad.new lnstance( ) nije taan tip, nego sam o Object.
c la s s Zgrada { }
c la s s Kuca extends Zgrada { }
p u b lic c la s s KonverzijaClassTipova {
p u b lic s t a t i c void m a in (S trin g [] args) {
Zgrada z = new K u c a ();
Class<Kuca> tipKuce = K u c a.class;
Kuca k = tip K u c e .c a s t(z );
k = (K u ca)z ; // . . . i l i u ra d ite samo ovo.
}
} ///:-
Poglavlje 14: Podaci o tipu 445
M etoda c a st( ) prim a objekat kao argum ent i pretvara ga u tip Class reference. Narav-
no, nakon to pogledate gornji kod, to izgleda kao m nogo vie posla nego u poslednjem
redu m etode m a in ( ) koji radi istu stvar.
N ova sintaksa za konverziju tipova je podesna za situacije u kojim a ne moete da upo-
trebite obinu konverziju tipa. To se najee dogaa kada piete generiki kod (to ete
nauiti u poglavlju Generiki tipovi) i uskladitili ste Class referencu koju kasnije nam e-
ravate da upotrebite za konverziju. Ispostavlja se da je to retko p o treb n o u celoj biblio-
teci Jave SE5 naao sam sam o jedan sluaj gde je m etoda c a st( ) bila koriena (u
com .sun.m irror.util.D eclarationFilter).
Jedna nova m ogunost uopte nije nala p rim enu u biblioteci Jave SE5: Class.asSub-
class( ). O na slui za konverziju objekta tipa Class u specifiniji tip.
G ornja naredba if proverava da li objekat x pripada klasi Pas pre nego to izvri kon-
verziju u tip Pas. Kada nem a drugih inform acija o tipu objekta, vano je da se in stan ceo f
upotrebi pre svoenja nanie; u suprotnom , nastae izuzetak tipa ClassC astException.
446 Misliti na Javi
O bino ete biti usredsreeni na jedan tip (npr. da pretvorite sve trouglove u ruiaste),
ali pom ou rezervisane rei instanceof m oete lako proveriti sve objekte. Pretpostavimo
da im am o porodicu klasa za opisivanje kunih Ljubimaca (i njihovih vlasnika, to e nam
zatrebati kasnije). Svaka Jedinka u hijerarhiji im a id i opciono ime. Iako sledee klase na-
sleuju klasu Jedinka, ona je donekle sloena, pa emo njen kod prikazati i objasniti u
poglavlju Detaljno razmatranje kontejnera. Kao to zapaate, u ovom trenutku i nije neop-
hodno da vidite kod klase Jedinka - treba sam o da znate sledee: moete je napraviti sa
im enom ili bez im ena i svaka Jedinka im a m etodu id ( ) koja vraa jedinstven identifikator
(napravljen brojanjem svakog objekta). Tu je i m etoda toS tring( ); ako napravite prim erak
klase Jedinka, a ne date joj ime, m etoda to S trin g ( ) vratie samo prosto ime tipa.
Ova hijerarhija klasa nasleuje klasu Jedinka:
/ / : podaciotipu/1jubim ci/Mesanac.ja va
package p o d a c io tip u .lju b im c i;
I I : podaciotipu/1jubim ci/Velska.java
package p o d a c io tip u .lju b im c i;
Da bi dobila Listu objekata tipa Class, apstraktna m etoda tip o v i( ) obraa se nekoj izve-
denoj klasi - ovo je varijanta projektnog obrasca Template Method (ablonska metoda).
Poto je zadato da tip klase bude neto izvedeno iz klase Ljubixnac, m etoda new-
Instance( ) pravi objekat tipa Ljubimac bez konverzije tipa. nekiLjubim ac( ) nasumino
indeksira Listu i izabrane objekte tipa Class upotrebljava za generisanje nove instance te
klase pom ou m etode Class.new lnstance( ). M etoda createA rray( ) upotrebljava m etodu
nekiLjubim ac( ) za popunjavanje niza, a arrayL ist( ) upotrebljava createArray( ).
Kada pozovete m etodu new ln stance( ), m oete da prouzrokujete dve vrste izuzetaka
koje su obraene u odredbam a catch iza bloka try. Podsetim o se, im ena izuzetaka su re-
lativno jasna objanjenja onoga to je zakazalo (IllegalAccessException oznaava krenje
pravila Javinog m ehanizm a bezbednosti, u ovom sluaju podrazum evani konstruktor je
privatan).
Kada izvodite potklasu klase PravljenjeLjubimaca, jedino m orate da navedete Listu
tipova ljubim aca koju hoete da napravite m eto dom nekiLjubim ac( ) i drugim m etoda-
ma. M etoda getTypes( ) obino vraa sam o referencu neke statine Liste. Evo jedne rea-
lizacije m etodom forN am e( ):
p u b lic c la s s Ljubimci {
p u b lic s t a t i c fin a l Pravljen jeL ju b im a ca p ra v lje n je =
new R u cn o Pravljen je L ju b im a ca ();
p u b lic s t a t ic Ljubimac nekiLjubim acO {
return p r a v lje n je .n e k iL ju b im a c ();
}
Poglavlje 14: Podaci o tipu 453
// : podaciotipu/PrebrojavanjeLjubim aca2.java
import p o d a c io tip u .lju b im c i.* ;
Dinamiki instanceof
M etoda Class.islnstance nudi nain za dinam iko ispitivanje tipa objekta. Tako se sve do-
sadne naredbe instanceof m ogu ukloniti iz prim era PrebrojavanjeLjubimaca:
p u b lic S trin g t o S t r in g () {
S trin g B u ild e r re z u lta t = new S t r in g B u ild e r C 'C ') ;
for(M ap.Entry<Class<? extends Ljubimac>,Integer> par
: e n t r y S e t ()) {
rez u lta t.a p p e n d (p a r.g e tK e y ().g e tSim p le N a m e ());
rez u ltat.ap p en d ("= ) ;
rez u lta t.a p p en d (p a r.g etV al u e ( ) ) ;
re z u lta t.a p p e n d (", " ) ;
}
r e z u lt a t .d e le t e (r e z u lt a t .le n g t h ()- 2 , r e z u lt a t .le n g t h O );
re z u lta t.a p p e n d C '}");
return r e z u l t a t . t o S t r in g ( ) ;
}
}
p u b lic s t a t ic void m a in (S trin g [] args) {
BrojacLjubim aca brojLjubim aca = new B ro ja cL ju b im a c a ();
for(Ljub im ac ljubim ac : L ju b im c i.c re a te A rra y (2 0 )) {
p rin tn b (l jub im ac.g etC lassO .getSimpleName() + " " ) ;
b ro jLju b im a ca .p reb ro j(1 ju b im a c );
}
p r in t();
p rin t(b ro jL ju b im a c a );
}
} /* Is p is :
Pacov Manska Velska Mesanac Mops Velska Mops Manska Velska Pacov Egipatska
Hrcak Egipatska Mesanac Mesanac Velska Mis Mops Mis Velska
{Ljubimac=20, Pas=6, Macka=9, Glodar=5, Mesanac=3, Mops=3, Egipatska=2, Man-
ska=7, Velska=5, Pacov=2, Mis=2, Hrcak=l}
* ///:-
Da bi se prebrojali svi razliiti tipovi prim eraka klase Ljubimac, Mapa BrojacLjubi-
maca se unapred popunjava tipovim a iz liste RucnoPravIjenjeLjubimaca.sviTipovi. Ta
lista upotrebljava klasu net.mindview.util.M apData koja prim a objekat tipa Iterable (li-
stu sviTipovi) i konstantu (u ovom sluaju, nulu), i popunjava Mapu kljuevima uzetim
iz liste sviTipovi i vrednou nula. Da Mapu nism o popunili unapred, prebrojali bismo
sam o nasum ino generisane tipove, ali ne i osnovne tipove kao to su Ljubimac i Macka.
Vidite da zbog korienja m etode islnstance() nisu potrebni izrazi instanceof. Osim
toga, to znai i da nove tipove kunih ljubim aca m oete da dodajete jednostavnim me-
njanjem niza tipovi; ostatak program a ne m ora da se m enja (to nije bio sluaj pri kori-
enju izraza instanceof).
M etodu to S trin g () preklopili sm o da bi davala itljiviji izlaz koji i dalje odgovara
tipinom izlazu koji se dobija ispisivanjem M ape.
Rekurzivno brojanje
Mapa u PrebrojavanjeLjubimaca3.BrojacLjubimaca bila je unapred popunjena svim
razliitim klasama Ljubimac. Umesto da m apu popunjavam o unapred, m oem o upotre-
biti m etodu Class.isAssignableFrom ( ) i napraviti alatku opte nam ene koja um e da bro-
ji sve, a ne samo prim erke klase Ljubimci:
Poglavlje 14: Podaci o tipu 455
// : podaciotipu/PrebrojavanjeLjubim aca4.ja va
import p o d a c io tip u .lju b im c i.* ;
import n e t.m in d v ie w .u til.* ;
import s t a t ic n e t.m in d v ie w .u til. P r i n t . * ;
456 Misliti na Javi
Generiki p aram etar T znai da m etoda create( ) m oe da vraa razliit tip rezultata za
razne realizacije interfejsa Proizvodjac.
U ovom prim eru, osnovna klasa Deo sadri listu objekata tipa Proizvodjac. D oda-
vanjem u listu proizvodjaciDelova, u osnovnoj klasi se ,,registruju proizvodni interfejsi
za tipove koje e praviti m etoda createR andom ( ):
c la s s Oeo (
pu b lic S trin g to S tr in g () {
return g etC lass().g etSim p le N am e();
}
s t a t ic List< Proizvodjac< ? extends D e o pro izvo djaciD elo va =
new A rrayList< Proizvodjac< ? extends D e o ( ) ;
s t a t ic {
// C o lle c tio n s .a d d A ll() daje upozorenje "unchecked generic
// a rra y cre atio n . . . fo r varargs parameter"
/'/ ("neprovereno p ra v lje n je generikog niza . . .
// za parametar prom enljive d u in e ").
proizvodjaciD elova.add(new P r e c is t a c G o r iv a .P r o iz v o d ja c O );
proizvodjaciD elova.add(new P re c is ta c V a z d u h a .P ro iz v o d ja c O );
proizvodjaciD elova.add(new PrecistacVazduhaZaKabinu. P ro iz v o d ja c ( ) ) ;
proizvodjaciD elova.add(new P r e c is t a c U lja .P r o iz v o d ja c ()) ;
proizvodjaciD elova.add(new K a is V e n tila to r a .P r o iz v o d ja c O );
proizvodjaciD elova.add(new K a is S e rv o V o la n a .P ro iz v o d ja c O );
proizvodjaciD elova.add(new K a is G e n e ra to ra .P ro iz v o d ja c ()) ;
}
p riv a te s t a t ic Random slu ca ja n = new Random(47);
p ub lic s t a t ic Deo createRandom() {
in t n = s lu c a ja n . n e x tIn t(p r o iz v o d ja c iD e lo v a .s iz e ()) ;
return p ro iz v o d ja c iD e lo v a .g e t (n ).c r e a t e ();
}
}
c la s s F i l t a r extends Deo {}
c la s s P r e c is ta c U lja extends F i l t a r {
p ub lic s t a t i c c la s s Proizvodjac
implements p o d a cio tip u .p ro izvo d jac.P ro izvo d jac< P recistacU lja> {
p u b lic P r e c is ta c U lja c re a te () { return new P r e c i s t a c U lj a ( ) ; }
}
}
Neke klase iz hijerarhije nisu u listi: Filtar i Kais su sam o klasifikatori, pa nikad ne pra-
vim o objekte tih klasa, nego sam o njihovih potklasa. Klase koje m etoda createRandom(
) treba da uzm e u obzir sadre un utranju klasu Proizvodjac. Kao to vidite, osnovni in-
terfejs Proizvodjac koristi se tako to se navede p o tp u n o ime podaciotipu.proizvod-
jac.Proizvodjac i tako se izbegava dvosmislenost.
Prilikom pravljenja liste objekata nism o koristili m etodu CoIIections.addAll( ), zato
to bi to izazvalo greku generic array creation (pravljenje generikog niza, to e biti
objanjeno u poglavlju Generiki tipovi). Umesto nje, koristio sam m etodu a d d ( ). Meto-
da createR andom ( ) nasum ino bira objekat iz liste proizvodjaciDelova i poziva njegovu
m etodu create( ) da napravi nov Deo.
Veba 14: (4) I konstruktor je svojevrsna proizvodna m etoda. Prepravite program Regi-
strovaniProizvodjaci.java tako da se um esto eksplicitnog navoenja im ena proizvoaa,
objekat klase smeta u listu, i svaki se objekat pravi m etodom new lnstance( ).
Veba 15: (4) Realizujte novu kiasu PravIjenjeLjubimaca koristei Registrovane Proiz-
vodiace i prepravite Fasadu Ljubimci tako da upotrebljava nju, a ne druge dve. Postarajte
se da ostali prim eri u kojima se upotrebljava program Ljubimci.java i dalje rade ispravno.
Veba 16: (4) Izmenite hijerarhiju Kafa u poglavlju Generiki tipovi tako da se koriste Re-
gistrovani Proizvodjaci.
//: podaciotipu/SrodnostProtivTacnogTipa.java
// R azlik a izmeu in stan ceof i e k v iv a le n c ije
package podaciotipu;
import s t a t ic n e t.m in d v ie w .u til. P r in t . * ;
460 Misllti na Javi
c lass Osnovna { }
c la s s Izveena extends Osnovna {}
p ub lic c la s s SrodnostProtivTacnogTipa {
s t a t ic void te s t(O b je c t x) {
p r in t (" T e s t ir a n je x tip a " + x .g e t C la s s ( )) ;
p r in t (" x in stan ceo f Osnovna " + (x in stan ceo f Osnovna));
p r in t (" x in stan ceo f Izvedena " + (x in stan ceo f Iz ved en a));
p rin t("O s n o v n a .is In s ta n c e (x ) " + O s n o v n a .c la s s .is ln s ta n c e (x ));
p r in t("lz v e d e n a .is ln s t a n c e (x ) " + Iz v e d e n a .c la s s .is ln s ta n c e (x ));
p r in t (" x .g e t C la s s () == O snovna.class " +
(x .g e tC la s s () == O s n o v n a .c la s s ));
p r in t (" x .g e t C la s s () == Iz ved en a.class " +
(x .g e tC la s s () == Iz v e d e n a .c la s s ));
p r in t("x .g e tC la s s (),e q u a ls (O s n o v n a .c la s s )) " +
(x .g e tC la s s ().e q u a ls (O s n o v n a .c la s s )));
p r in t("x .g e t C la s s ().e q u a ls (Iz v e d e n a .c la s s )) " +
(x .g e t C la s s ().e q u a ls (Iz v e d e n a .c la s s )));
}
p ub lic s t a t i c void m a in (S trin g [ ] args) {
test(new O sno vn aO );
test(new Iz v e d e n a ());
}
} /* Is p is :
T e s tira n je x tip a c la s s Osnovna
x in stan ce o f Osnovna tru e
x in stan ce o f Izvedena fa ls e
O sn o vn a.isln stan ce(x ) tru e
Iz v e d e n a .isln sta n ce (x ) fa ls e
x .g e tC la s s () == Osnovna.class tru e
x .g e tC la s s () == Iz ved en a.class fa ls e
x .g e tC la s s (),e q u a ls (O s n o v n a .c la s s )) true
x .g e tC la s s (),e q u a ls (Iz v e d e n a .c la s s )) fa ls e
T e s tira n je x tip a c la s s Izvedena
x in stan ce o f Osnovna tru e
x in stan ce o f Izvedena tru e
O sn o vn a.isIn stan ce(x ) tru e
Iz v e d e n a .is ln s ta n c e (x ) tru e
x .g e tC la s s () == Osnovna.class fa ls e
x .g e tC la s s () == Iz ve d e n a.class true
x .g e tC la s s ().e q u a ls (O s n o v n a .c la s s )) fa ls e
x .g e tC la s s (),e q u a ls (Iz v e d e n a .c la s s ) true
* ///:-
M etoda test() proverava tip, pri em u njen argum ent koristi oba oblika instanceof.
Potom ita referencu na Class i koristi = = i equals() za ispitivanje jednakosti objekata
tipa Class. Kao to je i oekivano, instanceof i islnstance() daju istovetne rezultate, isto
kao i equals() i ==. M edutim , sami testovi dovoe do razliitih zakljuaka. Saglasno s
pojm om tipa, instanceof pita: ,,Da li je ovo tvoja klasa, ili klasa izvedena iz nje? S druge
strane, ako stvarne objekte tipa Class uporedite pom ou operatora = =, tu nasteivanje
ne igra nikakvu ulogu: objekti su ili istovetnog tipa ili nisu.
Poglavlje 14: Podaci o tipu 461
Klasa Class, opisana ranije u poglavlju, podrava pojam refleksije, a postoji i dodatna
biblioteka java.lang.reflect s klasam a Field, M ethod i C onstructor (pri em u svaka rea-
lizuje interfejs Member). O bjekte tih tipova pravi Javina virtuelna m aina tokom izvra-
vanja, da bi predstavila odgovarajueg lana nepoznate klase. Zatim m oete koristiti
konstruktore da biste pravili nove objekte, m etode get() i set() za itanje i m enjanje polja
povezanih sa objektim a tipa Field i m etodu invoke() za pozivanje m etode povezane
s objektom tipa M ethod. Pored toga, m oete da pozovete m etode getFields(), getMet-
hods(), getConstructors() itd. da biste dobili nizove objekata koji predstavljaju polja,
m etode i konstruktore. (Vie o ovom e nai ete u dokum entaciji o klasi Class u Javinom
razvojnom okruenju, JDK.) Znai, inform acije o klasi an onim nih objekata m ogu se u
p otpunosti otkriti tokom izvravanja, a nita ne m ora da se zna tokom prevoenja.
Vano je shvatiti da refleksija nije nita posebno. Kada koristite refleksiju za rad sa
objektim a nepoznatog tipa, Javina virtuelna m aina e proveriti da li neki objekat pripada
odreenoj klasi (kao p ri obinom p ostu p ku prepoznavanja tipa u vreme izvravanja), ali
zatim , pre nego to uradi bilo ta drugo, m ora da uita objekat tipa Class. Stoga datoteka
.class za taj tip i dalje m ora da bude d o stu pna Javinoj virtuelnoj m aini, bilo na lokalnom
sistem u ili u mrei. Prem a tom e, prava razlika izm eu prepoznavanja tipa u vreme izvr-
avanja i refleksije lei u tom e to u prvom nainu prevodilac otvara i ispituje datoteku
.class tokom prevoenja. D rugim reima, m oete da pozovete sve m etode objekta na
uobiajen nain. Pri refleksiji, datoteka .class nije dostupna tokom prevoenja; nju otva-
ra i ispituje izvrno okruenje.
M etode getMethods() i getC onstructors() klase Class vraaju niz objekata tipa Met-
hod odnosno Constructor. Svaka od ovih klasa im a dalje m etode za izdvajanje im ena, ar-
gum enata i povratnih vrednosti m etoda koje predstavljaju. M eutim , za dobijanje
znakovnog niza s potpunim potpisom m etode moete da koristite sam o m etodu to-
StringO, kao to je ovde uinjeno. O statak koda slui samo za izdvajanje inform acija s ko-
m andne linije, za utvrivanje da li odreeni potpis odgovara ciljnom znakovnom nizu
(korienjem funkcije indexOf()) i za odbacivanje kvalifikatora im ena p om ou regular-
nih izraza (koji su predstavljeni u poglavlju Znakovni nizovi).
Poto rezultat koji daje Class.forName() ne m oe da bude poznat u vrem e prevoenja,
sve inform acije o potpisu m etode izdvajaju se tokom izvravanja. Ako potraite objanje-
nje refleksije u dokum entaciji na Webu, videete da im a dovoljno podrke za stvarno po-
deavanje i pozivanje m etode za objekat koji je p o tp u n o nepoznat tokom prevoenja
(prim era za ovo bie u nastavku knjige). lako ovo m oda nikada neete m orati da radite
sami, vrednost pune refleksije um e da iznenadi.
G ornje rezultate je proizvela kom andna linija:
Ovo daje listing koji sadri podrazum evani javni konstruktor, m ada se u kodu vidi da
nije definisan nikakav konstruktor. K onstruktor koji vidite autom atski pravi prevodilac.
Ako potom klasu PrikaziMetode pretvorite u nejavnu (dakle, s paketnim p ristupom ),
napravljen podrazum evani konstruktor se vie nee pojavljivati u rezultatu program a.
N apravljenom podrazum evanom konstruktoru se autom atski dodeljuje isti nivo pristu-
pa kao klasi.
Bilo bi zanimljivo pozvati i java P rikaziM etodc java.lan g .S trin g uz dodatni argum ent
tipa char, in t, S trin g itd.
Ova alatka zaista moe da utedi vrem e prilikom program iranja, kada ne m oete da se
setite da li klasa ima neku m etodu, a ne elite da pregledate hijerarhiju klasa u dokum en-
taciji na Webu, ili ne znate da li ta klasa, prim era radi, moe da radi neto sa objektiina
tipa Color.
Poglavlje Grafika koristiika okruenja sadri grafiku verziju ovog program a (prila-
goenu za izdvajanje inform acija za Swing kom ponente), pa m oete da je izvravate dok
piete kod da biste brzo pronali ono to vam treba.
Veba 17: (2) Izm enite regularan izraz u program u PokaziMetode.java tako da se
uklanjaju i rezervisane rei native i final. Uputstvo: upotrebite o perator I (OR).
Veba 18: (1) Izm enite klasu PokaziMetode tako da ne bude javna i dokaite da se napra-
vljen podrazum evani konstruktor vie ne pojavljuje u rezultatu program a.
Poglavlje 14: Podaci o tipu 465
Dinamiki posrednici
Projektni obrazac Proxy (Posrednik) jedan je od osnovnih projektnih obrazaca. To je ob-
jekat koji umeete um esto ,,pravog objekta da biste obavili neke dopunske ili razliite
operacije m eu njim a je obino i kom unikacija sa odreenim pravim " objektom .
S truk turu projektnog obrasca Proxy pokazaem o n a jed n o m trivijalnom prim eru:
in te rfa c e In t e r fe js {
void u ra d iN e s to ();
void nestoDrugo(String a r g );
1
c la s s ProstPrim erZaPosrednika {
p u b lic s t a t ic void p o tr o s a c (In te r fe js i f e j s ) {
if e js .u r a d iN e s t o ( ) ;
i f e j s . nestoDrugo("bonobo");
466 Misliti na Javi
c la s s ProstDinam ickiPosrednik {
p ub lic s t a t ic void p o tr o s a c (In te r fe js i f e j s ) {
if e js .u r a d iN e s t o ( ) ;
ifejs.n e sto D ru g o ("b o n o b o ");
}
p ub lic s t a t ic void m a in (S trin g [] args) {
PraviO bjekat pravi = new P r a v iO b je k a t();
p o tro s a c (p ra v i) ;
// Umetni posrednika i pozovi ponovo:
In t e r f e js posrednik = (In te rfe js )P ro x y.n e w P ro x yIn sta n c e (
In t e r fe js .c la s s .g e t C la s s L o a d e r (),
new C la s s [ ]{ In t e r f e js .c la s s } ,
new B1okDi nami ckogPosredni k a (p ra v i) ) ;
p o tro sac(p o sre d n ik );
}
} /* Is p is : (95% podudaranja)
uradiNesto
nestoDrugo bonobo
** ** posrednik: c la s s $ProxyO, metoda: pu b lic a b s tra ct void
In t e r f e js .u r a d iN e s t o (), argumenti: null
uradiNesto
**** posrednik: c la s s $ProxyO, metoda: pu b lic a b s tra ct void
In te rfe js .n e s to D ru g o (ja v a .la n g .S trin g ), argumenti:
[ Ljava.lang.0bject;@ 42e816
bonobo
nestoDrugo bonobo
* ///:-
in te rfa c e NekeMetode {
void d o sad n alO ;
void dosadna2();
void z a n im ljiv a (S tr in g a r g );
void z a n im ljiv a 3 ( ) ;
}
c lass IzborMetoda {
p ub lic s t a t ic void m a in (S trin g [] args) {
NekeMetode posrednik= (NekeMetode)Proxy.newProxyInstance(
NekeMetode.class. g e tC la s s L o a d e r(),
n e w C la s s []{ NekeMetode.class } ,
new IzborMetoda(new R e a li z a c i j a ( ) ) ) ;
posrednik.dosadnal( ) ;
posredni k.dosadna2 ();
posrednik.zanim lj i va ("b o n o b o ");
posredni k.dosadna3 ();
}
} /* Is p is :
dosadnal
dosadna2
Posrednik je o tk rio za n im ljivu metodu
za n im ljiva bonobo
dosadna3
* ///:-
Poglavlje 14: Podaci o tipu 469
Ovde su nas zanim ala sam o im ena m etoda, ali vi moete traiti i druge delove potpisa
m etoda, pa ak i vrednosti odreenih argum enata.
D inam iki posrednik nije alatka koju ete upotrebljavati svakog dana, ali neke vrste
problem a njom e m oete veoma lepo da reite. O projektnom obrascu Proxy i drugim pro-
jektnim obrascim a vie ete saznati u knjigam a Thitiking in Patterns (posetite www.Min-
dView.net) i Design Patterns, autor je Erich G am m a i dr. (Addison-Wesley, 1995).
Veba 21: (3) Prepravite program ProstPrim erZaPosrednik.java tako da m eri vrem ena
poziva m etoda.
Veba 22: (3) Prepravite program ProstDinam ickiPosrednik.java tako da m eri vrem ena
poziva m etoda.
Veba23: (3) U nutar m etode invoke( ) u program u ProstDinamickiPosrednik.java, po-
kuajte da ispiete argum ent posrednik i objasnite ta se deava.
Projekat:2 Napiite sistem u kojem dinam iki posrednici realizuju transakcije, gde po-
srednik obavlja potvrivanje ako je posredovani poziv bio uspean (nije generisao izuzet-
ke), o dno sno ponitavanje ako je poziv zakazao. Potvrivanje i ponitavanje se obavljaju
na spoljnoj tekstualnoj datoteci koja je izvan kontrole Javinih izuzetaka. M oraete da pa-
zite na atomizovanost (usitnjenost) operacija.
Null objekti
Kada ugraenu null referencu upotrebljavate da biste naznaili kako odreeni objekat ne
postoji, svaki p u t kada dobijete neku referencu, m orate proveriti da li je jednaka null. To
um e da postane veom a zam orno i da proizvede zam oran kod. Problem je to to null re-
ferenca nem a svoje ponaanje, sem to proizvodi NullPointerException ako ita pokua-
te s njom da uradite. Katkada je korisno uvesti Null objekat* koji prim a poruke za objekat
koji ,,zam enjuje, ali vraa vrednosti koje pokazuju da nem a ,,pravog objekta. O nda biste
smeli pretpostaviti da su svi objekti validni pa ne biste gubili program sko vrem e prove-
ravajui reference na n u ll (i na itanje rezultujueg koda).
Iako bi bilo zabavno zamiljati program ski jezik koji autom atski pravi Null objekte za
vas, u praksi nem a smisla upotrebljavati ih posvuda ponekad ba treba proveriti da li re-
ferenca ukazuje na null, katkada se m oe razborito pretpostaviti da null referenca nee
naii, dok im a i sluajeva kada je prihvatljivo otkrivanje greaka preko izuzetka NullPo-
interException. Izgleda da su NuII objekti najkorisniji kada su blie podacim a, sa ob-
jektim a koji predstavljaju entitete u prostoru problem a. Jednostavan prim er je to to
m nogi sistemi imaju klasu Osoba, a u kodu ima situacija kada stvarna osoba ne postoji
(ili postoji, ali vi jo niste dobili sve podatke o njoj), pa bi se tada tradicionalno koristila
null referenca i odgovarajua provera. Umesto toga, m oem o napraviti Null objekat. lako
2 P ro je k ti su p re d lo z i z a s e m e s tra ln e ra d o v e (n a p r im e r ) . Solution g u id e n e s a d r i re e n ja p ro je k a ta .
Iz u m ili su ga B o b b y W o o lf i B ru c e A n d e rs o n . To se m o e s m a tr a ti s p e c ija ln im s lu a je m p ro je k tn o g
o b ra s c a Strategy (S tra te g ija ). V a rija n ta N u ll objekta je o b ra z a c N u ll iterator k o ji ite rir a n je v o ro v a u
k o m p o z itn o j h ije ra rh iji in i n e v id ljiv im za k lije n ta (k lije n t is tu lo g ik u m o e d a u p o tr e b i za ite rira n je
k o m p o z itn ih i z a v rn ih v o ro v a ).
470 Misliti na Javi
Null objekat odgovara na sve poruke na koje bi odgovorio i pravi objekat, i alje je po-
treban nain ispitivanja jednakosti s null. Najjednostavniji nain da se to uradi je isto-
im eni interfejs:
//: podaciotipu/Osoba.java
// Klasa koja ima Null objekat.
import n e t.m in d v ie w .u til.* ;
c la s s Osoba {
p u b lic fin a l S trin g ime;
p ublic fin a l S trin g prezime;
p ublic fin a l S trin g adresa;
// e tc .
p ublic O soba(String ime, S trin g prezime, S trin g ad re sa ){
th is.im e = ime;
this.prezim e = prezime;
th is.a d re sa = adresa;
}
p ub lic S trin g to S trin g O {
return "Osoba: " + ime + " " + prezime + " " + adresa;
}
p ublic s t a t ic c lass NullOsoba
extends Osoba implements Null {
p riv a te NullOsoba() { super("Nem a", "Nema", "Nema"); }
p ublic S trin g to S trin g O { retu rn "N ullOsoba"; }
}
p ublic s t a t ic fin a l Osoba NULL = new N u llO so ba();
} ///:-
//: podaciotipu/RadnoMesto.java
c la s s RadnoMesto {
p riv a te S trin g zvanje;
p riv a te Osoba osoba;
p u b lic RadnoMesto(Stririg Fu n k cija , Osoba zaposleni) {
zvanje = Fu n k cija;
osoba = zap o sleni;
if(o so b a == n u ll)
osoba = Osoba.NULL;
}
p u b lic RadnoMesto(String Fu n k cija ) {
zvanje = Fu n k cija ;
osoba = Osoba.NULL;
}
p u b lic S trin g d ajZ van jeO { return zvanje; }
p u b lic void z a d a jZ v a n je (Strin g novoZvanje) {
zvanje = novoZvanje
}
p u b lic Osoba dajOsobu() { retu rn osoba; }
p ub lic void zadaj0sobu(0soba novaOsoba) {
osoba = novaOsoba;
if(o s o b a == n u ll)
osoba = Osoba.NULL;
}
p u b lic S trin g to S trin g O {
return "RadnoMesto: " + zvanje + " " + osoba;
}
} ///= -
Vodite rauna o tom e da na nekim m estim a ipak m orate proveravati postoje li Null
objekti, to se ne razlikuje ba m nogo od provere null vrednosti. Na drugim m estim a
- kao to su to S trin g ( ) konverzije, u ovom sluaju - ne m orate da obavljate dodatne pro-
vere; sm ete da pretpostavite kako su sve reference objekata validne.
Ako um esto s konkretnim klasama radite sa interfejsim a, m oete u potrebiti Dyna-
micProxy za autom atsko pravljenje Null objekata. Pretpostavim o da im am o interfejs Ro-
bot koji definie ime, m odel i List<Operacija> koji opisuju ta Robot um e da radi.
O peracija sadri opis i kom andu - to je jedna vrsta obrasca Comtnand (Kom anda):
//: podaciotipu/Robot.java
import j a v a . u t i l . * ;
import n e t.m in d v ie w .u til.* ;
Pretpostavljamo da e biti m nogo razliitih tipova Robota i hteli bismo da svaki Null
objekat radi neto posebno za svaki tip Robota - u ovom sluaju, sadri podatke o tanom
tipu Robota koji Null objekat zamenjuje. Te podatke e hvatati dinamiki posrednik:
Poglavjje ) Podaci o tipu 475
p u b lic c la s s NullRobot {
p ub lic s t a t ic Robot
novNullRobot(Class<? extends Robot> t ip ) {
return (Robot)Proxy.newProxyInstance(
Nul1R o b o t.c la s s .g e tC la s s L o a d e r(),
new C la s s [ ]{ N u ll.c la s s , Robot.class } ,
new B lo kZaO bradu N u llR o bo ta(tip));
}
p u b lic s t a t ic void m a in (S trin g [] args) {
Robot[] botovi = {
new RobotKoji Ci s tiS n e g ("S n e z a n a "),
novNul1R o b o t(R o b o tK o jiC istiSn e g .class)
};
for(Robot bot : botovi)
R o b o t.T e s t.te s t(b o t);
}
} /* Is p is :
Robot ime: Snezana
Robot model: SnegoBot S e r ij a 11
Snezana moe da i s t i sneg
Snezana i s t i sneg
Snezana moe da i s t i led
Snezana i s t i led
Snezana moe da p o is ti krov
Snezana p o is ti krov
4 76 Misliti na Javi
[Null Robot]
Robot ime: RobotKojiCistiSneg NullRobot
Robot model: RobotKojiC istiSneg NullRobot
* ///:-
Kad god vam zatreba prazan (null) objekat tipa Robot, sam o pozovete m etodu
novN ullR obot( ) prosleujui joj tip Robota za koji hoete posrednika. Posrednik ispu-
njava zahteve interfejsa Robot i Null i daje specifino im e tipa za koji posreduje.
p ub lic in te rfa c e A {
void f ( ) ;
} ///:-
Kada se ovaj interfejs realizuje, videete kako se ipak moe saznati stvarni realizovani tip:
c la s s B implements A {
p u b lic void f ( ) {}
p ub lic void g () {}
}
Poglavlje 14: Podaci o tipu 477
//: po da ci ot ip u/ paketnipristup/SkrivenaC.java
package podacioti pu.paketni pristup;
import po da ci ot ip u.interfejsa.*;
import static net.mi nd vi ew .u t i1 .P r i n t .*;
class C implements A {
public void f() { print("javna C . f ( ) ); }
public void g() { print("javna C .g ()"); }
void u() { print("paketni C .u ()"); }
protected void v() { print("zatiena C .v ()) ; }
private void w() { print("privatna C . w ( ) ); }
}
//: podaciotipu/SkrivenaRealizacija.java
// Zaobilaenje paketnog pristupa.
import podaciotipu.interfejsa.*;
import podaciotipu.paketnipristup.*;
import java.lang.reflect.*;
M oda m islite da ete to spreiti tako to ete d is trib u ira ti sam o ve p rev ed en k o d , ali
varate se. D ov oljn o je takav k o d p ro p u s titi k ro z javap, p rev o d ilac u n a z a d k o ji se ispo-
ru u je uz JDK. Evo kako izgleda o d g o v araju a k o m a n d n a linija:
javap -private C
In d ik ato r -private kazuje d a treb a p rik azati sve lanove, ak i o n e privatne. Evo rezultata:
N a taj n a in , svi m o g u sazn ati im en a i p o tp ise svih vaih (i n ajp riv atn ijih ) m e to d a i
pozvati ih.
ta e biti ako interfejs realizujete kao p riv a tn u u n u tra n ju ldasu? Evo kako to izgleda:
//: podaciotipu/UnutranjaRealizacija.java
// Privatne unutranje klase ne mogu se sakriti od refleksije.
import podaciotipu.interfejsa.*;
import static net.mind vi ew .u ti l.Print.*;
class UnutrasnjaA {
private static class C implements A {
public void f() { print("javna C .f ()"); }
public void g() { print("javna C.g()"); }
void u() { print("paketna C .u ()"); }
protected void v() { print("zatiena C.v()"); }
private void w() { print("privatna C.w()"); }
I
public static A napraviA() { return new C(); }
} /* Ispis:
javna C.f()
UnutrasnjaA$C
javna C.g()
paketna C.u()
zatiena C.v()
privatna C.w()
* ///:-
//: podaciotipu/AnonimnaRealizacija.java
// Anonimne unutranje klase ne mogu se sakriti od refleksije.
import podaciotipu.interfejsa.*;
import static ne t. mi nd vi ew .u ti l.Print.*;
class AnonimnaA {
public static A napraviA() {
return new A() {
public void f() { print("javna C.f()"); }
public void g() { p r in t(javna C.g()''); }
void u() { print("paketna C.u()"); }
protected void v() { print("zatiena C.v()"); }
private void w() { print("privatna C.w()"); }
};
}
}
public class AnonimnaRealizacija {
public static void main(String[] args) throws Exception {
A a = A n on im na A. na pr av iA ();
a.f 0 ;
System.out.println ( a . ge tC la ss(),getName());
// Refleksija i dalje hvata anonimne klase:
SkrivenaRealizacija.pozivSkriveneMetode(a, "g");
SkrivenaRealizacija.pozivSkriveneMetode(a, "u");
SkrivenaReal izacija.pozi vSkri veneMetode(a, "v");
Skri venaReal izacija . p o z i vSkri veneMetode(a, "w");
}
} /* Ispis:
javna C.f()
AnonimnaA$l
javna C.g()
paketna C.u()
zatiena C.v()
privatna C.w()
Poglavlje 14: Podaci o tipu 481
//: podaciotipu/ModifikovanjePrivatnihPolja.java
import java.lang.reflect.*;
class UzPrivatnoFinalnoPolje {
private int i = 1;
private final String s = "Potpuno sam bezbedan";
private String s2 = Jesam li bezbedan?";
public String t o S t r i n g O {
return "i = " + i + ", " + s + ", " + s2;
}
}
Po pravilu, sva ta krenja prava p ristu p a n isu n ajgora stvar n a svetu. U koliko neko u p o -
trebi takvu teh n ik u za pozivanje m e to d a koje ste oznaili kao p riv a te ili kao m eto d e s pa-
ketn im p ristu p o m (im e ste svim a jasn o stavili d o zn an ja kako ne bi trebalo da ih pozivaju),
o n d a teko m oe da se ali k ad a izm enite neki aspekt tih m etoda. S d ru g e stran e, injenica
da uvek im ate m ala v rata u klasu, m oe o m o g u iti da reite o d re en e vrste p ro b lem a koji bi
inae bili teki ili nem ogui, a p red n o sti refleksije su, u o p te n o govorei, neosporne.
Veba 25: (2) N apravite klasu koja sadri p riv a tn e m eto d e , zatiene m eto d e i m eto d e
s p a k etn im p ristu p o m . N ap iite k o d za p ristu p a n je tim m e to d a m a spolja, tj. izvan pak eta
te klase.
Saetak
P rep o zn av an je tip a to k o m izvravanja o m o g u u je o tk riv a n je in fo rm ac ija o tip u p o m o u
a n o n im n e reference n a klasu. P o etn ici ga esto z lo u p o treb ljav aju je r im izgleda p o g o d -
nije o d poziva p o lim o rfn ih m eto d a. M n o g i lju d i, navikli n a p ro c e d u ra ln o p ro g ram ira n je ,
teko se o d v ikavaju o d o rg an izo v an ja p ro g ra m a u o b lik u sk u p a n a re d a b a sw itch . Takva
s tru k tu ra bi se m o gla p o stii o d re iv a n je m tip a u v re m e izvravanja, ali b i se izgubila va-
na o so b in a p o lim o rfizm a to k o m razvoja i o d rav an ja koda. S u tin a o'bjektno o rijen tisa-
n o g p ro g ra m ira n ja je d a se u k o d u k o riste pozivi p o lim o rfn ih m eto d a, a da se
p rep o zn av an je tip a u v rem e izvravanja k o risti sam o kada je n eo p h o d n o .
Da b i se p ozivi p o lim o rfn ih m e to d a ko ristili na p ro p isan i n ain , m o ra se k o n tro lisati
definicija o sn o v n e klase, zato to bi se m o g lo desiti d a u o d re e n o m tre n u tk u , kada p ro -
irujete p ro g ra m , u stan o v ite k ako o sn o v n a klasa ne sadri p o tre b n u m eto d u . Ako osnov-
na klasa p o tie iz biblioteke ili je k o n tro lie n eko d ru g i, reenje p ro b le m a lei u
p rep o zn av an ju tipa to k o m izvravanja, je r tak o m o ete izvesti n o v tip i d o d a ti eljenu
m eto d u . N a n ek o m d ru g o m m e stu u k o d u m o ete d a o tk rijete pravi tip i pozovete speci-
jaln u m e to d u . P olim orfizam i m o g u n o st p ro iriv an ja p ro g ra m a nee b iti u p ro p aen i,
jer se p ri d o d av a n ju novog tip a ne m o ra trag ati za n a re d b a m a sw itc h u p ro g ra m u . M e-
u tim , u k o d u za koji je n e o p h o d n a n o v a m eto d a, m o ra te p rim e n iti p rep o zn av an je tip a
u v rem e izvravanja da b iste o tk rili o d re e n i tip.
Z bog sm etan ja nove funkcije u o sn o v n u klasu m o g lo bi se desiti d a zarad jed n e klase
svim ostalim klasam a izvedenim iz iste o sn o v n e klase treb a d o d a ti n ek u b esm islen u m e-
to d u . T im e se gubi p reg led n o st in terfejsa i n e rv iraju se p ro g ra m eri, koji m o raju da rede-
finiu a p stra k tn e m e to d e k ad a izvode d ru g e klase iz te o sn o v n e klase. Na p rim er,
p o sm a tra jin o h ije ra rh iju klasa koja pred stav lja m u zike in stru m e n te . P retp o sta v im o da
elite d a p ro istite piskove svih d u v ak ih in s tru m e n a ta u o rk estru . Jedna m o g u n o st je da
stavite m e to d u procistiPisak() u o sn o v n u klasu Instruinent, ali to z b u n ju je zato to p o d -
razum eva da i u d arak i i iani in s tru m e n ti im aju pisak. P rep o zn av an je tip a u v rem e iz-
vravanja o bezb e u je m n o g o p o g o d n ije reenje u ovom sluaju zato to m e to d u m oete
staviti u o re e n u klasu (u o v o m sluaju, u klasu d u v ak ih in stru m e n a ta ) gde joj je i m e-
sto. M e u tim , m n o g o bolje reenje je d a se m e to d a priprem ilnstrum ent() stavi u osnov-
n u klasu. Ipak, to m o d a n eete p red v id eti kada se p rv i p u t sretn ete s p ro b le m o m , pa ete
p ogreno zakljuiti d a m o ra te k o ristiti p re p o z n a v an je tip a u v rem e izvravanja.
Poglavlje 14: Podaci o tipu 483
1 Angelika L anger pie Java Generics FAQ (O dg ov ori na najea pitanja o Javinim generikiin tipovi-
m a, videti www.langer.camelot.de). Ti i d ru g i njeni tekstovi (napisani zajedno s K lausom K rettom )
bili su m i o d neprocenjive vred n o sti tokom p rip re m e ovog poglavlja.
2 Ili klasa koja im a sam o privatne k o n stru k to re.
Poglavlje 15: Generiki tipovi 485
Poreenje sa C++-om
P ro je k ta n ti Jave kau d a je d o b a r d eo tog jezika b io reakcija n a C + + . U p rk os to m e , Javu
je m o g u e p re d av ati u g la v n o m b ez sp o m in ja n ja C + + -a , i ja sam se tru d io d a ra d im tako,
sem k ad a p o re e n je daje d u b lji uvid.
G en erik i tip o v i z ah te v aju vie p o re en ja s C + + -o m iz dva razloga. P rvo, kad a shvatite
o d re e n e asp ek te C + + -o v ih ablona (engl. tem plate) - ko ji su bili glavno n a d a h n u e za
generike tip o ve, ak i za n jih o v u o sn o v n u sin ta k su - b o lje ete shvatiti tem elje to g k o n -
cepta, k ao i - a to je v e o m a v an o - o g ra n i en ja p rilik o m u p o tre b e Javinih g en erik ih
tip o v a i razloge za njih . K rajnji cilj je d a stek n ete ja sn u p red stav u o to m e gde su granice,
p o to z n a m iz so p stv en o g iskustva: k ad a shv atite gde su granice, p o stajete bolji p ro g ra -
m er. K ada zn ate ta n e m o e d a se u ra d i, bo lje ete isk o ristiti o n o to m oe (d elo m i zato
to ne g u b ite v re m e su d a ra ju i se sa z ido vim a).
D ru g i razlog je znaajan n e sp o ra z u m koji u n u ta r Javine zajednice vlada kad a je re o
C + + a b lo n im a . Taj n e sp o ra z u m m o e jo vie d a vas zb u n i u p o g led u p re d v i en e u p o -
treb e g e n erik ih tipova.
Stoga u u ovo m po glavlju d a ti tek m in im a la n broj p rim e ra s C + + ab lo nim a.
//: ge ne ri cki/Skladistel.java
class Automobil (}
Pre Jave SE5, je d n o sta v n o b ism o joj dali d a uva jed a n Object:
//: genericki/Skladiste2.java
Sada Skladiste2 m oe da p rim i b ilo ta - a u ovom p rim e ru isto Skladiste2 uva tri
razliita tip a objekata.
Im a sluajeva kada hoete da k o n tejn er sldaditi vie tipova objekata, ali se u k o n tejn er
o b in o stavlja je d a n tip objekata. Jedna o d o sn o v n ih m otivacija za generike tipove bilo je
zadavanje tipa objekta koji k o n tejner sadri, i da tu specifikaciju pod ri i proveri prevodilac.
Z ato b ism o u m esto tip a Object hteli d a u p o tre b im o nespecificiran tip, koji m oe biti
o d re e n k asnije. To se rad i tako to n ak on im ena klase u n u ta r znakova m anje od i vee o d
n ap iete p a ra m eta r tipa, i zam e n ite ga stv arn im tip o m kada tu klasu u p o tre b ite. Za klasu
Skladiste to bi izgledalo ovako (T je p a ra m e ta r tipa):
//: genericki/Skladiste3.java
K ada sada n aprav ite neko Skladiste3, istom sintak so m sa znakov im a m an je od i vee od
m o rate zadati tip koji ho ete da uvate u n jem u , kao to vidite u m eto di m a in ( ).
U Skladiste je dozvoljeno stavljati sam o objekte tog tip a (ili po d tip a, poto p rin cip zam ene
Poglavlje 15: Generiki tipovi 487
Biblioteka n-torki
esto bi b ilo p o eljno v ra titi vie objekata iz je d n o g poziva m etod e. N ared b a retu rn do z-
voljava zadavanje sam o je d n o g objekta, p a je reenje n a p ra v iti o bjekat koji sad ri vie o b -
jek a ta koje h o ete da v ratite. N arav n o , m o ete da piete p o seb n u k lasu svaki p u t kada
n ai e te na tak v u situaciju , ali p o m o u g en erik ih tipova p ro b le m m o ete reiti je d n o m
zauvek i tak o sebi uted eti tru d u b u d u e. Isto v rem en o , u vrem e p rev o en ja svi generiki
tipo vi e biti provereni.
O vaj k o n c e p t se naziva n-torka (engl. tuple), a rad i se o g ru p i objek ata o m o ta n ih za-
je d n o u je d a n objekat. P rim alac objekta m oe d a ita njegove elem en te, ali ne i d a stavlja
nove u njega. (O vaj k o n cep t nazivaju i D ata Transfer Object ili Messenger, O b jek at za p re-
nos p o d a ta k a ili D ostavlja p o ru k a.)
n -to rk e m o g u biti p roizvoljne du in e i svaki n jih o v o b jek at m o e b iti razliitog tipa.
M ed u tim , m i h o em o da z ad am o tip svakog o bjek ta i o bezb ed im o da p rim a la c - kada
p ro ita njegovu v re d n o st-d o b ije ispravan tip. P rob lem zbog razliitih d u in a reiem o
prav ljen jem razliitih n -to rk i. Evo jed n e koja uva dva objekta:
K o n stru k to r hvata ob jek at koji treba sauvati, a to S trin g ( ) je p rig o d n a funkcija za p ri-
kazivanje v red n o sti iz liste. O b ra tite p a n ju na to da n -to rk a svoje elem ente im p lic itn o
uva u p o re tk u .
488 Misliti na Javi
//: net/mindview/util/Trojka.java
package net.mindview.util;
//: ne t/ mi nd vi ew /u ti1/Cetvorka.java
package net.mindview.util;
//: net/mindview/util/Petorka.java
package net.mindview.util;
//: ge ne ri cki/IspitivanjeEntorki.java
import net.mindview.util.*;
class Amfibija {}
class Vozilo {}
Klasa steka
P ogledajm o neto to je m alo kom pliko vanije: klasini stek s kojeg se p rv o u zim a o n o to
je n a njega p o sled n je stavljeno. U p o glavlju uvatije objekata realizovali sm o stek p o m o u
u lan a n e liste (LinkedList) kao klasu net.m indview.util.Stack (n a stra n a m a 320-323). U
to m p rim e ru v id ite d a u lan a n a lista ve im a m e to d e p o tre b n e za prav ljen je steka. Klasu
Stack n ap ravili sm o slaganjem je d n e gen erik e klase (Stack<T>) s d ru g o m g enerikom
klasom (LinkedList<T>). N a to m p rim e ru vid ite da je generiki tip kao i svaki d ru g i, (uz
nekoliko izuzetaka koje em o ra z m o triti k asnije).
U m esto d a u p o tre b im o LinkedList, m o e m o d a realizu jem o so p stv en i u n u tra n ji
u lan a n i m eh a n iz a m za skladitenje.
public T skinisa() {
T rezultat = vrh.stavka;
if(!vrh.kraj())
vrh = vrh.sledeca;
return rezultat;
}
public static void main(String[] args) {
Ul ancaniStek<String> uss = new U l a n c a ni St ek <S tr in g>( );
for(String s : "Phasers on stun!".split(" "))
u s s . st av in a( s);
String s;
while((s = uss.skinisa()) != null)
System.o ut .p ri nt ln (s);
}
} /* Ispis:
stun!
on
Phasers
* ///:-
NasumicnaLista
Kao d ru g i p rim e r za skladiste, p re tp o sta v im o da h o ete p o se b n u v rstu liste koja n asu m i-
no bira je d a n o d svojih elem en ata k ad a se pozove iz a b e ri( ). Poto hoete alatk u koja radi
sa svim o b jek tim a, k o ristite g enerike tipove:
//: ge ne ricki/NasumicnaLista.java
import j a v a . u t i l .*;
Generiki interfejsi
G eneriki tip o v i su p rik la d n i i za interfejse. N a p rim er, generator je klasa koja p rav i o b -
jekte. Z apravo, ra d i se o specijalizaciji p ro je k tn o g o b rasca Factory M eth o d (P roizvo dn a
m e to d a ), ali k a d a o d g e n e ra to ra zatra ite n o v objekat, n e p ro sle u jete m u arg u m en te,
d o k ih P ro izv o d n a m e to d a o b i n o p ro sle u jete. G e n e ra to r zna kako da pravi nove o bjek-
te b ez ikakvih d o d a tn ih in fo rm ac ija.
G e n e ra to r o b i n o definie sam o je d n u m e to d u , o n u koja prav i nove objekte. O vde
em o je nazvati sledeci( ) i u k lju iti m e u sta n d a rd n e uslun e klase:
//: n e t/ mi nd vi ew /u ti1/Generator.java
// Generiki interfejs.
package net.mindview.util;
public interface Genera to r< T> { T s l e d e c i (); } ///:-
//: ge ne ri ck i/kafa/Kafa.java
package g e n e r i c k i .kafa;
//: ge ne ri ck i/ ka fa /S Ml eko m. ja va
package genericki.kafa;
public class SMlekom extends Kafa {} ///:-
Poglavlje 15: Generiki tipovi 493
//: ge nericki/kafa/Moka.java
package genericki.kafa;
public class Moka extends Kafa {} ///:-
//: genericki/kafa/Cappuccino.java
package genericki.kafa;
public class Cappuccino extends Kafa {} ///:-
//: genericki/kafa/Kratka.java
package genericki.kafa;
public class Kratka extends Kafa {} ///:-
Saa m o em o da realizu jem o G e n e ra to r< K a fa > koji p rav i razliite tipove K afa ob je-
kata:
//: genericki/kafa/GeneratorKafe.java
// Generie razliite tipove Kafa:
package g e n e r i c k i .kafa;
import ja v a . u t i 1.*;
import net.mindview.util.*;
//: g e n e r i c k i/ Fi bo na cc i.java
// Pravljenje Fibonaccijevog niza.
import net.mindview.util.*;
} /* Ispis:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584
* ///:-
U fo reach n ared b i, klasu Ite ra b iln iF ib o n a c c i upotreb ljav ate tako to n je n o m kon
s tru k to ru zadajete g ran ic u , da bi m eto d a h a s N e x t( ) znala kada treb a da v ra ti false.
496 Misliti na Javi
Generike metode
D o sad sm o p a ram etrizo v ali cele klase. M oete p ara m e triz o v a ti i p o je d in e m e to d e u n u ta r
klase. S am a klasa m oe, ali n e m o ra b iti gen erik a - to ne zavisi o d g en e ri n o sti m eto d e.
G en erin o st m eto d e znai da o n a m o e da se m en ja n ezav isn o o d klase. Po p rav ilu , ge-
nerike m e to d e bi treb alo d a u p o treb ljav ate ,,kad g o d m o e te . D ru g im reim a, ako se
u m e sto cele klase sam o m eto d a m o e n a p ra v iti d a b u d e g en erik a, v e ro v a tn o e tak o i
k o d b iti jasniji. Pored toga, ako je m e to d a statin a, o n a n e m a p ristu p a g e n erik im p a ra -
m e trim a tip a (svoje generike) klase, p a u koliko tre b a d a k o risti g en e ri n o st, m o ra sam a
da b u d e generika.
G enerika m e to d a se definie stavljanjem liste g en erik ih p a ra m e ta ra isp red p o v ra tn e
v red n o sti, ovako:
//: genericki/GenerickeMetode.java
//: net/mindview/util/Nova.java
// Uslune metode koje pravljenje generikih kontejnera
// pojednostavljuju tako to same zakljuuju o tipu argumenta.
package net.mindview.util;
import j a v a . u t i l .*;
//: ge ne ricki/JednostavnijiLjubimci.java
import podaciotipu.ljubimci.*;
import ja v a . u t i l .*;
import net.mindview.util.*;
M ada je ovo zanim ljiv p rim e r zakljuivanja o tip u arg u m e n ta , teko je rei koliko je to
zapravo korisno. O soba koja ita ko d m o ra da analizira i shvati o v u d o d a tn u b ib lio tek u i
njen e posledice, pa je m o d a jed n ak o p ro d u k tiv n o ostaviti p rv o b itn u d efin iciju (m ad a
im a m n o g o ponav ljanja) - d a ironija b u d e vea, jed n o sta v n o sti rad i. M e u tim , k ad a bi u
s ta n d a rd n u Javinu b ib lio tek u bila d o d ata u slu n a klasa p o p u t g o rn je N o v a.jav a, bilo bi
p a m e tn o koristiti je.
Z akljuivanje o tip u arg u m e n ta fun k cio nie iskljuivo za d odeljivanje. U koliko rezul-
tat poziva m e to d e kao to je N o v a .m a p () prosled ite kao a rg u m e n t d ru g o j m eto d i, prevo-
dilac neep o k u ati da zakljui koji je tip a rg u m e n ta. Poziv te m e to d e o n e tre tira ti kao da
je n jena p o v ra tn a v red n o st dod eljen a p ro m en ljiv o j tip a O b je c t. Evo je d n o g takvog
(n eu speno g ) p rim era :
//: genericki/GraniceZakljucivanja.java
import po da ci otipu.ljubimci.*;
import ja v a . u t i l .*;
public class GraniceZakljucivanja {
Poglavlje 15: Generiki tipovi 499
static voi
f(Map<Osoba, List<? extends L j u b i m c i 1judiSLjubimcima) {}
public static void main(String[] args) {
// f ( N o v a . m a p O ) ; // Nee biti prevedeno
}
} ///:-
Veba 11: ( 1) Ispitajte klasu Nova.java p rav ljen jem so p stv en ih klasa. D o kaite d a Nova s
njim a rad i ispravno.
//: genericki/IzricitoZadavanjeTipa.java
import po da ci ot ip u. lj ub im ci.*;
import ja v a . u t i l .*;
import net.mindview.util.*;
N aravno, tim e se gubi p re n o st korienja klase Nova koja sm an ju je k o liin u pisan ja,
ali je d o d a tn a sintaksa p o tre b n a sam o kada ne piete n are d b e dodeljivan ja.
V eba 12: (1) P onovite p re th o d n u vebu uz eksp licitn o zadavanje tipova.
//: genericki/Generatori.java
// Usluna metoda za korienje s Generatorima.
import genericki.kafa.*;
import java.util.*;
import net.mindview.util.*;
Am ericano 2
Moka 3
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,
* ///:-
//: ne t/ mi nd vi ew/util/E1ementarniGenerator.java
// Automatski pravi Ge nerator date klase
// koja ima podrazumevani konstruktor (bez argumenata).
package net.mindview.util;
O va klasa p red stavlja e le m e n ta rn u realizaciju koja pravi objekte klase koja je (1) javna
(p o to je E lem entarniG enerator u zaseb n o m p ak etu , klasa o kojoj se rad i m o ra im ati jav-
ni, a ne sa m o p ak e tn i p ristu p ), i (2) im a p o d ra zu m e v an i k o n s tru k to r (onaj koji ne p rim a
a rg u m e n te ). Da biste na p rav ili jed an o d o b jek ata tip a ElementarniGenerator, pozivate
m e to d u n a p ra v i( ) i p ro sle u jete joj leksem u (engl. token) tip a koji h o ete d a generiete.
G enerika m e to d a n a p ra v i( ) o m o g u u je d a kaete Elem entarniG enerator.napra-
vi(MojTip.cIass) u m esto nevv ElementarniGenerator<M ojTip>(M ojTip.cIass), to bi
bilo runije.
Na p rim e r, ova je d n o sta v n a klasa im a p o d raz u m e v an i k o n stru k to r:
502 Misliti na Javi
//: genericki/PrebrojaniObjekat.java
//: ge nericki/PrimerElementarnogGeneratora.java
import net.mindview.util.*;
Iz ovoga v idite koliko generika m eto d a sm an ju je koliinu pisanja kada se pravi objekat
Generator. Javin generiki m eh an izam vas p rim o ra v a da ipak pro sled ite objekat tipa Class,
pa ga o n d a m oete u p o treb iti i za zakljuivanje o tip u arg u m en ta u m eto d i napravi( ).
Veba 14: ( 1) Izm en ite PrimerElem entarnogGeneratora.java tako da se Generator pravi
eksplicitno (tj. u m esto generike m eto d e n a p ra v i( ) u p o tre b ite eksplicitan k o n stru k to r).
//: net/mindview/util/N_torka.java
// Biblioteka n-torki u kojoj se upotrebljava
// zakljuivanje o tipu argumenta.
package net.mindview.util;
Poglavlje 15: Generikl tipovi 503
//; genericki/IspitivanjeEntorki2.java
import net.mindview.util.*;
import static n e t. mi nd vi ew .u ti 1.N_torka.*;
//: genericki/vodeneboje/Vodeneboje.java
package genericki.vodeneboje;
/ / : genericki/SkupoviVodenihBoja.java
import genericki.vodeneboje.*;
import j a v a . u t i l .*;
import static net.mind vi ew .u ti l.Print.*;
import static net.mind vi ew .u ti l.Sku po vi.*;
import static genericki.vodeneboje.Vodeneboje.*;
/ / : net/mindview/util/RazlikeKontejnerskihMetoda.java
package net.mindview.util;
import java.lang.reflect.*;
import j a v a . u t i l .*;
class Klijent {
private static long brojac = 1;
private final long id = brojac++;
private Klijent() {}
public String t o S t r i n g O { return "Klijent " + id; }
// Metoda za pravljenje objekata tipa Generator:
public static Ge ne ra to r< Kl ij en t> generator() {
return new Generator<Klijent>() {
public Klijent sledeci() { return new Klijent(); }
};
}
}
class Sluzbenik {
private static long brojac = 1;
private final long id = brojac++;
private Sluzbenik() {}
public String t o S t r i n g O { return "Sluzbenik " + id; }
// Samo jedan objekat tipa Generator:
public static Ge ne ra to r< Sl uz be ni k> ge nerator =
new Generator<Sluzbenik>() {
public Sluzbenik sledeci() { return new Sluzbenik(); }
};
}
) /* Ispis:
Sluzbenik 3 usluuje kl ijenta K1ijent 1
Sluzbenik 2 usluuje kl ijenta K1 ijent 2
Sluzbenik 3 usluuje kl ijenta K1 ijent 3
Sluzbenik 1 usluuje kl ijenta K1 ijent 4
Sluzbenik 1 usl uuje kl ijenta K1 ijent 5
Sluzbenik 3 usluuje kl ijenta K1 ijent 6
Sluzbenik 1 usluuje kl ijenta K1 ijent 7
Sluzbenik 2 usluuje kl ijenta K1ijent 8
S1uzbeni k 3 usluuje kl i jenta K1 ijent 9
Sluzbenik 3 usluuje kl ijenta K1ijent 10
Sluzbenik 2 usluuje kl ijenta Klijent 11
Sluzbenik 4 usluuje kl ijenta K1 ijent 12
Sluzbenik 2 usluuje kl ijenta K1ijent 13
Sluzbenik 1 usluuje kl ijenta K1 ijent 14
Sluzbenik 1 usluuje klijenta Klijent 15
*///:-
//: ge ne ri ck i / L i s t a N _ t o r k i .java
// Kombinovanje generikih tipova da bi se dobili
// sloeni generiki tipovi.
import j a v a . u t i l .*;
import net.mindview.util.*;
for(Cetvorka<Vozilo,Amfibija,String,Integer> i: tl)
Sy st em .o ut .p ri nt ln (i);
}
} /* Ispis: (75% podudaranja)
(Vozilo@llb86e7, Amfibija@35ce36, zdravo, 47)
(Vozilo@757aef, Amfibija@d9f9c3, zdravo, 47)
* ///:-
//: genericki/Prodavnica.java
// Pravljenje sloenog modela pomou generikih kontejnera.
import ja v a . u t i l .*;
import net.mindview.util.*;
class Proizvod {
private final int id;
private String opis;
private double cena;
public Proizvod(int IDbroj, String ops, double cena){
id = IDbroj;
opis = ops;
this.cena = cena;
S y st em .o ut .println(toString());
}
public String t o S t r i n g O {
return id + " + opis + ", cena: $" + cena;
}
public void promenaCene(double change) {
cena += change;
}
public static Generator<Proizvod> ge nerator =
new Generator<Proizvod>() {
private Random slucajan = new Random(47);
public Proizvod sledeci() {
return new Pr oi zv od (s l u c a j a n , n e x t I n t (1000), "Test",
Math.round(slucajan.nextDouble() * 1000.0) + 0.99);
}
};
}
class Blagajna {}
class Kancelarija {}
* ///:-
Tajanstveno brisanje
K ako b u d e te sve tem eljnije u p o zn av ali generike tipove, nailaziete na stvari koje v am
sp oetk a nee biti logine. N a p rim er, iako se m oe rei ArrayList.class, n e m o e se rei
ArrayList<Integer>.class. I p o g led ajte ovo:
//: genericki/EkvivalentnostTipovaZbogBrisanja.java
import j a v a . u t i l .*;
//: ge ne ricki/Izgubljenelnformacije.java
import j a v a . u t i l .*;
class Frob {}
class Fnorkle {}
class Kvark<Q> {}
class Ce st ica<P0L0ZAJ,M0MENAT> {}
} /* Ispis:
[E]
[K, V]
[Q]
[POL OZ AJ, MOMENAT]
* ///:-
Pristup u C++-u
P o gledajm o p rim e r iz C + + -a u kojem su u p o tre b lje n i abloni (engl. tem plates). V ideete
da je sin tak sa za p a ra m e trizo v a n e tip o v e p o tp u n o jed n ak a, p o to je Java n ap ra v ljen a na
o sn o v u C + + -a :
//: g e n e ri ck i/ Sa bl on i.cpp
#include <iostream>
using namespace std;
class ImaF {
publi c :
void f() { cout "ImaF::f()" endl; }
514 Misliti na Javi
int main() (
ImaF imaf;
Manipulator<ImaF> m a ni pu la to r( im af );
ma ni pu la to r. ma ni pu lis i();
} /* Ispis:
ImaF: :f ()
III--
K lasa M anipulator sadri o b jek at tip a T. Z an im ljiva je m e to d a m an ip u lisi( ) koja p o -
ziva m e to d u f ( ) za obj. Kako o n a m oe zn ati d a m eto d a f ( ) p o sto ji za p a ra m e ta r tip a T?
P revodilac C + + -a p roverava tipove k ad a p rav ite p rim e ra k ab lo n a, p a u tre n u tk u p ra -
vljenja klase M anipulator<Im aF> vidi d a ImaF im a m e to d u f ( ). D a je n em a, do b ili biste
g rek u u v rem e p rev o en ja, i b e z b ed n o st tip o v a bi bila ouvana.
Pisan je ovakvog k o d a u C + + -U je jed n o stav n o , zato to k o d a b lo n a zn a tip p a ra m e ta -
ra svog ab lo n a u tre n u tk u k ad a treb a d a ga n ap ravi. Javini generiki tip o v i su drugaiji.
N apisali sm o ImaF u Javi:
//: genericki/ImaF.java
//: ge nericki/Manipulacija.java
// {Compi1eTimeError} (Ne moe da se prevede)
class Manipulator<T> {
private T obj;
public Manipulator(T x) { obj = x; }
// Greka: cannot find s y m b o l : method f():
public void mani pul i si () { obj.f(); }
}
//: genericki/Manipulator2.java
//: genericki/Manipulator3.java
class Manipulator3 {
private ImaF obj;
public Ma ni pu la to r3 (I ma F x) { obj = x; }
public void manipulisi() { obj.f(); }
} ///:-
/ / : genericki/VracanjeGenerickogTipa.java
Migracijska kompatibilnost
D a b ism o spreili m og u e z a b u n e u vezi s b risa n je m , m o ra te n ed vo sm isleno shvatiti da
b risan je n/j'eobeleje jezika. R adi se o k o m p ro m isu u realizaciji Javinih g enerikih tipova,
p o tre b n o m zato to je jezik n a p o e tk u b io nap rav ljen bez n jih . Taj k o m p ro m is e vam
sm etati, p a se m o ra te navii n a njega i sh vatiti zato je u in jen.
D a su generiki tip o v i b ili d eo Jave o d verzije 1.0, n e b i bili realizovani p o m o u b ri-
sanja - koristila b i se konkretizacija za p a m e n je p a ra m e ta ra tip a k ao p rv o ra z re d n ih en -
titeta, p a biste s n jim a m o g li d a o b avljate jezike i refleksivne o p eracije zasno van e na
tip o v im a. V ideete u n astav k u poglavlja d a b risan je sm a n ju je ,,op tost generik ih tipova.
O n i u Javi jesu korisni, ali n e toliko koliko bi m o gli b iti, a razlog je u p rav o brisanje.
U realizaciji zasnovanoj n a b risan ju , g en eriki tip o v i se tre tira ju kao d ru g o ra z re d n i
tip o v i koji se n e m o g u u p o tre b lja v ati u n ek im v a n im k o n tek stim a . G en eriki tip ov i
p o stoje sam o to k o m statike pro v ere tip o v a. N ak o n toga, svi generiki tip ov i u p ro g ra m u
bivaju o b risa n i i zam enjen i n e k o m n eg en e rik o m g o rn jo m g ra n ico m . N a p rim er, a n o ta -
cije tip a k ao to je L ist< T > b iv aju b risa n je m sved en e n a L ist, a p ro m en ljiv e o b in o g tipa
svedene na O b je c t, ukoliko neka g ran ica n ije zadata.
O sn o v n a m o tivacija za b risa n je jeste to to o m o g u u je ko rienje g enerik ih klijenata
s n eg en erik im b ib lio tek am a i o b rn u to . To se esto naziva migracijska kom patibilnost. U
id e a ln o m svetu, sav kod b i u isto m tre n u tk u p o stao generiki. U stv arn o sti, ak i da p ro -
g ra m e ri p iu sam o generiki k o d , m o rali bi da vode ra u n a o n eg en erik im b ib lio te k a m a
n a p isa n im pre Jave SE5. A u to ri tih b ib lio tek a m o d a n ik ad a nee p rep rav iti svoj k o d tako
da p o sta n e generiki, ili e to m o d a u ra d iti polako.
Z ato Javina realizacija g en erik ih tip o v a m o ra da p o d rav a n e sam o vertikalnu kom pa-
tibilnost - postojei ko d i d ato tek e klasa m o ra ju o stati legalne i znaiti isto to su znaile
pre - nego i m igracijsku k o m p a tib iln o st, d a bi b ib lio tek e m ogle p o stati generike kada to
n jim a b u d e odgovaralo, i d a ta d a n e bi sru ile k o d i aplikacije koje o d njih zavise. Kada su
to sebi zadali k ao cilj, p ro je k ta n ti Jave i raz n e g ru p e koje su rad ile na to m p ro b le m u o d -
luili su d a je b risan je je d in o ostvarivo reenje. B risanje o m o g u u je m igraciju ka generi-
kim tip o v im a tako to dozvoljava p o sto ja n je n eg en eriko g k o da zaje dn o s generikim .
Na p rim e r, recim o da o d re e n a aplikacija koristi dve biblioteke, X i Y, i da Y koristi bi-
b lio te k u Z. Poto je u m e u v re m e n u o bjavljena Java SE5, tvorci te aplikacije i tih biblio -
teka vero vatn o e, je d n o g d an a , o d lu iti da p re u n a generiki kod. M e u tim , svaki od
njih e im ati d ru g aiju m o tiv aciju i o g ra n ien ja u p o g led u v re m e n a tog prelaska. D a bi se
postigla m igracijska k o m p a tib iln o st, svaka b iblio teka i ap likacija m o ra biti nezavisna od
svih o stalih u o d n o su na to d a li k o risti g en erik i kod. Stoga n e sm eju im ati m o g u n o st da
o tk riju da li d ru g e biblioteke koriste ili n e k o riste generiki kod. Z ato do k az da o d re en a
bib lio tek a k o risti generiki k o d m o ra biti obrisan".
Bez neke vrste p u tanje za m igraciju, sve biblioteke n apisan e tok om vrem ena bile su u
o p asn o sti da b u d u odseene o d p ro g ram era koji su odluili da p red u na Javin generiki
kod. T vrdi se d a su biblioteke deo jezika koji najvie u tie na p ro d u k tiv n o st, pa toliki rizik
nije bio prihvatljiv. Da li je brisan je bilo jed in i ili n ajbolji p u t za m igraciju, pokazae vrem e.
Poglavlje 15: Generiki tipovi 517
Problem s brisanjem
D akle, o sn o v n i razlog za b risa n je jeste prelazak s n eg en eriko g n a generiki k o d i n a m e ra
da se gen eriki k o d u kljui u jezik b ez ru e n ja p o sto jeih b ib liotek a. B risanje o m o g u u je
p o sto jeem n eg en erik o m k lijen tsk o m k o d u d a n astav i d a rad i bez ikakve izm en e, sve
d o k klijen ti ne b u d u sp re m n i d a p re ra d e k o d n a generiki. Ta m otiv acija je p lem en ita,
zato to ne rui o d je d n o m sav p o sto jei kod.
C ena b risan ja je zn a tn a . G en e rik i tip o v i se n e m o g u u p o treb ljav ati u o p eracijam a
koje u v rem e izvravanja izriito u p u u ju n a tipove, k ao to su eksplicitne konverzije
tipova, o p eracije instanceof i izrazi new. P oto se g u b e sve inform acije o tip u p a ra m e ta ra ,
kad a piete generiki k o d m o ra te se staln o p o d seati d a sam o izgleda kao da im ate in fo r-
m acije o tip u p a ra m e ta ra . D akle, k ad a piete ovakvo p are koda:
class Nesto<T> {
T promenljiva;
1
ini se d a k od u klasi Nesto treb a da zn a kako sada radi sa o b jek to m tip a Macka.
Sintaksa vas jak o navodi na p o m isa o d a tip T biva zam e n jen u celoj klasi. Ali to nije istina,
i kad god piete ko d za tu klasu, m o rate sebi rei: ,,Ne, to je sam o objekat.
Pored toga, b risa n je i m ig racijsk a k o m p a tib iln o st znae d a se generiki kod ne koristi
ni ta m o gde biste to m o d a eleli:
/ / : ge nericki/BrisanjelNasledjivanje.java
class GenerickaOsnovna<T> {
private T element;
public void set(T arg) { arg = element; }
public T get() { return element; }
}
Object obj = d 2 . g e t ( ) ;
d2.set(obj); // Ovde biste dobili upozorenje!
}
} ///= -
Izvedena2 nasleuje k lasu GenerickaOsnovna b ez gen erik ih p a ra m e ta ra i prev o d i-
lac ne daje u p o zo renje. U p o zo ren ja n e m a d o poziva m eto d e s e t( ).
Za iskljuivanje u p o zo re n ja Java im a an o tac iju , o n u ko ju v id ite u listin g u (ta an otac ija
nije bila p o d r a n a u ran ijim v erzijam a Jave SE5):
@SuppressWarnings("unchecked")
ta se zbiva na granicama
Z bog b risanja, sm a tra m d a asp ek t generikog k o d a koji najvie z b u n ju je jeste injenica da
m oete nap isati o n o to n em a sm isla. N a p rim er:
/ / : genericki/TvoracNizova.java
import j a v a .1a n g .r e f l e c t .*;
import j a v a . u t i l .*;
Iako je klasa vrsta n a p isa n a kao Class<T>, b risan je znai d a e o n a b iti usklad iten a
sam o kao Class, b ez p a ra m e tra . Z ato, k ad a s n jo m n eto n ap rav ite, recim o n ek i niz, m e-
to d a A rray.new lnstance( ) ne d o b ija in fo rm ac ije o tip u koje vrsta im p licira; zbog to g a ta
m e to d a n e m oe d ati rezu ltat specifinog p o d tip a , te ga m o ra te e k sp licitn o k o nvertovati,
to proizvo di u p o zo ren je koje n e m o ete d a o tk lo n ite.
Im ajte u v idu d a je m e to d a A rray.new lnstance( ) p re p o ru e n a za p ravljenje nizova u
g en erik o m kodu.
U koliko u m esto n iza n a p ra v im o k o n tejn er, stv ari izgledaju d rugaije:
//: genericki/TvoracListi.java
import j a v a . u t i l .*;
//: genericki/TvoracPopunjeneListe.java
import j a va .u ti1 .*;
u sk la e n o sa A rra y L is t< T > . D akle, iako b risan je u k lan ja in fo rm a c ije o stv a rn o m tip u
u n u ta r m e to d e ili klase, p rev o d ilac ip a k m oe da o b ezb ed i u n u tra n ju d o sle d n o st u
n a in u n a koji je taj tip u p o tre b lje n u n u ta r m eto de, o d n o s n o klase.
P oto b risan je u k lan ja in fo rm ac ije o tip u iz tela m eto d e , u v re m e izvravanja vane su
granice. take gd e o b jek ti ulaze u m e to d u i izlaze iz nje. U tim ta k a m a p rev o d ilac u v rem e
p rev o e n ja p ro v erav a tip o v e i u m e e k o d za njihove konverzije. P ogledajm o sledei n e-
g eneriki p rim e r:
//: ge ne ri ck i/ Je dnostavnoSkladiste.java
//: genericki/GenerickoSkladiste.java
Kompenzacija za brisanje
Kao to sm o videli, b risa n jem se g u b i m o g u n o s t ob avljanja o d re e n ih operacija u gene-
rik o m k odu . Sve o n o za ta je p o tre b n o p o zn av an je stv a rn ih tip o v a u v rem e izvravanja,
nee raditi:
//: genericki/Obrisana.java
// {CompileTimeError} (Nee biti prevedena)
//: genericki/HvatanjeTipaKlase.java
class Zgrada {}
class Kuca extends Zgrada {}
/ / : genericki/PravljenjelnstanceGenerickogTipa.cpp
// C++, ne Java!
int main() {
Nesto<Bar> nb;
Nesto<int> ni; // ... radi i s prostim tipovima
} III--
524 Misliti na Javi
//: genericki/PravljenjelnstanceGenerickogTipa.java
import static net.mind vi ew .u ti l.Print.*;
class K1asaKaoProizvodjac<T> {
T x;
public KlasaKaoProizvodjac(Class<T> vrsta) {
try {
x = vrsta.ne wl ns ta nc e( );
} catch(Exception e) {
throw new RuntimeE xc ep ti on (e );
}
}
}
class Zaposleni {}
//: genericki/OgranicenjeProizvodjaca.java
interface ProizvodjacI<T> {
T n a p r a v i ();
}
class Nesto2<T> {
private T x;
Poglavlje 15: Generiki tipovi 525
class Spravica {
public static class Proizvodjac implements ProizvodjacI<Spravica> {
public Spravica napravi() {
return new Spravica();
}
}
}
class X {}
Veba 22: (6) U p o treb ite o zn ak u tip a i refleksiju za pravljen je m e to d e koja k o risti verziju
sa a rg u m e n to m m e to d e new lnstance( ) koja tre b a da p rav i o b jek te klase iji k o n stru k to r
p rim a arg u m en te.
Veba 23: (1) P rep rav ite p ro g ram OgranicenjeProizvodjaca.java tako d a m e to d a
n a p ra v i( ) p rim a jed an arg u m en t.
Veba 24: (3) Izm en ite vebu 21 tako da se p ro iz v o d n i ob jek ti d re u Mapi u m esto u
Class<?>.
//: genericki/ListaGenerickih.java
import j a v a . u t i l .*;
O vako ste dob ili p o n aan je niza, ali i p ro v eru tipova u v rem e p re v o en ja koju do n o si
generiki kod.
K atkada e v am ipak zatreb ati niz g enerikih tipova (na p rim e r, A rra y L ist u p o treb lja-
va nizove in te rn o ). Da stv ar b u d e zanim ljivija, m oete definisati referencu tak o da prevo-
dilac b u d e zadovoljan. Na p rim er:
//: genericki/NizGenerickihReferenci.java
class Generic<T> {}
//: genericki/GenerickiNiz.java
1 warning
//: genericki/GenerickiNiz2.java
Isprv a ovo ne izgleda b itn o drugaije, sa m o to je konverzija p rem ete n a. Bez an o tacija
@SuppressWarnings, d o b ijaete u p o z o ren ja u n ch eck ed " (n ep ro v eren o ). M e u tim , in -
te rn o je niz sad a pred stav ljen kao Object[], a ne kao T [|. Kada se pozove m eto d a g e t( ),
o n a k o n v e rtu je o b jek at u tip T, to u stv ari i jeste taan tip, pa je to b ezb ed n o . M e u tim ,
ako pozovete re p ( ), o n a e p o n o v o p o k u ati da Object[] k o n v ertu je u T [], to je i dalje
n eta n o , i p ro izv o di u p o zo ren je u v rem e p rev o en ja i izuzetak u v rem e izvravanja. D ak-
le, n e m a n ain a da se o b o ri tip p rip a d n o g in te rn o g niza koji m oe biti sa m o Object[].
P re d n o st in te rn o g tre tira n ja niza kao tip a Object[] u m esto T [] jeste u to m e to je m an je
v ero v a tn o da ete u v rem e izvravanja zab o rav iti koji je tip niza i zato slu ajn o n a p rav iti
g reku (iako se veina tak v ih greaka, a m o d a i sve, b rzo o tk rije u v rem e izvravanja).
U n o v o m k o d u , tre b a lo bi d a p ro sled ite leksem u tipa. U to m sluaju, GenerickiNiz bi
izgledao ovako:
//: ge ne ri ck i/ Ge nerickiNizSLeksemomTipa.java
import java.lang.reflect.*;
public ArrayList(Collection c) {
velicina = c . si ze ();
elementPodataka = (E[])new O b j e c t [ v e l i c i n a ] ;
c . to Ar ra y(elementPodataka);
}
' http://gafter.blogspot.com/2004/U9/puzzling-through-erasurc-cinswcr.html
Poglavlje 15: Generiki tipovi 531
sru i postojei interfejs. D akle, ak i ako se u izv o rn o m k o d u Javinih b ib lio tek a pojav lju ju
n ek i id io m i p ro jek to v an ja, n e znai d a je to p rav i n ain rad a. D o k itate k o d b ib lio tek a,
ne sm ete u zim ati zdravo za g otovo d a je to u z o r koji treb a d a sledite u svom k o d u .
Granice
Granice su u k ra tk o p red stav ljen e u p re th o d n o m elu poglavlja (v id eti stran ice 514 i 515).
G ran ice o m o g u u ju d a n am e ete o g ran ien ja p a ra m e ta rsk im tip o v im a koje m o ete
u p o treb ljav ati u g en erik o m k o d u . Iako tim e d o b ijate m o g u n o st da n am eete p ravila o
tip o v im a n a koje m oete p rim e n iti svoj gen eriki k od , p o ten cijaln o vaniji efekat je d a
m o ete p ozivati m e to d e d efin isan e u vaim o g ra n i e n im tip o v im a.
P oto b risan je u k lan ja in fo rm a c ije o tip o v im a, jed in e m e to d e koje m o ete poziv ati za
n eo g ra n i e n generiki p a ra m e ta r jesu o n e o stu p n e za O b je c t. M e u tim , ukoliko taj p a-
ra m e ta r m o ete o g ran i iti tak o da b u d e p o d sk u p tipova, o n d a m o ete poziv ati m e to d e
to g p o d sk u p a . D a b i sproveo to o g ran ien je, Javin gen erik i k o d p o n o v o u p o treb ljav a re-
zerv isan u re e x te n d s . N e sm ete s m e tn u ti s u m a d a u k o n te k stu generik ih g ran ica, ex-
te n d s im a sasvim d ru g aije zn aen je n ego o b in o . U n a re d n o m p rim e ru p rik azaem o
o sn o v n o o g ran icam a:
// Ovo nee raditi -- prve moraju biti klase, a tek onda interfejsi:
// class Ob oj enaDimenzija<T extends ImaBoju & imenzija> {
// Vie granica:
class ObojenaDimenzija<T extends Dimenzija & ImaBoju> {
T stavka;
Ob oj enaDimenzija(T stavka) { this.stavka = stavka; }
T getltemO { return stavka; }
ja va.awt.Color boja() { return s t av ka .g et Co lo r( ); }
int getX() { return stavka.x; }
int g e t Y () { return stavka.y; }
int getZ() { return stavka.z; }
532 Misliti na Javi
class Ogranicen
extends Dimenzija implements ImaBoju, Tezinu {
public java.awt.Color getColor() { return null; }
public int tezina() { return 0; }
}
//: ge nericki/NasledjivanjeGranica.java
class DrziStavku<T> {
T stavka;
DrziStavku(T stavka) { this.stavka = stavka; }
T getltemO { return stavka; }
}
//: genericki/EpskaBitka.java
// Primer granica u Javinom generikom kodu.
import ja v a . u t i 1 .*;
interface SuperSila {}
interface RentgenskiVid extends SuperSila {
void vidi Kr oz Zi do ve ();
}
interface SuperSluh extends SuperSila {
void cuje Tih e Z v u k o v e O ;
}
interface SuperNjuh extends SuperSila {
void pr at iPoMiris u ( ) ;
}
Dokerski argumenti
Ve ste videli neke jed n o sta v n e u p o treb e dokerskih argum enata -z n a k o v a p ita n ja u izra-
zim a generikih a rg u m en a ta - u poglavlju uvanje objekata, a jo vie u poglavlju Podaci
o tipu. U ovom odeljk u ra z m o tri em o ih detaljnije.
Poeem o od p rim e ra koji po k azuje o d re e n o p o n a a n je nizova: n iz izvedenog tip a
m oete da d o d elite referenci niza o sn o v n o g tipa:
//: ge ne ricki/KovarijantniNizovi.java
class Voce {}
class Jabuka extends Voce {}
class Jonathan extends Jabuka {}
class Naranda extends Voce {}
Prvi red u m eto d i m a in ( ) pravi niz Jabuka i d o elju je ga referenci na niz tip a Voce. To
im a sm isla - Jabuka je v rsta voa, pa niz Jabuka treb a isto vrem eno da b u d e i niz tip a Voce.
M e u tim ,d a je pravi tip niza Jabuka[], u njega b iste m ogli da stavite sam o o b jek at tip a
Jabuka ili p o d tip a o d Jabuka, to bi zaista delovalo i u v rem e p rev o en ja i u v re m e izvra
vanja. Ali o b ra tite p a n ju na to da p revodilac dozvoljava stavljanje ob jek ta tip a Voce u niz.
P revo dio cu to im a sm isla, poto o n im a referencu n a Voce[] - zato da ne dozv oli d a se u
niz stavi o bjek at tip a Voce ili bilo ta izvedeno iz tip a Voce, kao to je Naranda? Stoga je
u v rem e prev o enja to dozvoljeno. M e u tim , u v rem e izvravanja, m e h an izam nizova
zna da radi s nizom Jabuka[] i generie izuzetak kada se stra n i tip stavi u taj niz.
Svoenje navie ovde nije p rav a re. Vi zaprav o je d an niz do d elju jete d ru g o m . Svaki
niz se p o n aa kao d a sadri d ru g e objekte, ali p o to m o em o d a svedem o navie, jasn o je
da objekti niza m o g u da p o tu ju p ravila o tip u o b jek ata koje niz sadri. To je kao d a nizovi
zn aju ta sadre, pa ne m oete da ih p revarite zbog pro v era u v rem e p re v o en ja i u v rem e
izvravanja.
536 Misliti na Javi
T ip o b jek ta listav sad a je List<? extends Voce>, to m o ete itati kao lista bilo kojeg
tip a koji n asled u je Voce. M e u tim , to ne znai da ova Lista p rim a sve p o d tip o v e klase Vo-
ce. D ok ersk i a rg u m e n t o znaava o d re e n tip , p a g o rn ji izraz znai o d re en tip koji
referenca listav ne specificira Stoga d o d eljen a Lista m o ra d a uva sp e c ifk ira n tip k ao to
su Voce ili Jabuka. D a bi svoenje navie n a listavbilo m og u e, taj tip je n ije v an o koji.
U koliko je je d in o o g ran ien je da ta L ista sadri o d re e n o Voce ili p o d tip klase Voce, ali
zapravo v am nije v ano koji, ta m o ete d a u ra d ite s tak vo m L istom ? A ko ne zn ate koji tip
ta L ista sadri, kako d a joj b ezb ed n o d o d ate neki objekat? N e m oete, kao to ni u p ro -
g ra m u KovarijantniNizovi.java niste m ogli da niz svedete navie, sem to u o v o m slua-
ju to spreava prevodilac, a ta m o sistem za izvravanje. Sada p ro b le m otk riv ate ranije.
M od a ste po m islili d a je ovo o tilo p redaleko, je r sada Listi za koju ste u p rav o rekli da
sad ri o b jek te tip a Jabuka, n e m o ete d a d o d a te o b jek at tip a Jabuka. U p ra v u ste, ali p re-
vodilac to ne zna. O b je k a t tip a List<? extends Voce> m o e legalno da u k azuje n a o b jek at
tip a List<Naranda>. N ak o n to u ra d ite ovu v rstu svoenja navie, g u b ite m o g u n o st
d a bilo ta p ro sled ite u listu, ak i Object.
S d ru g e stra n e, ako po zo v ete m e to d u koja v raa Voce, to je b ezb ed n o je r z n a te da
sadraj L iste m o ra u n a jm a n ju ru k u b iti tip a Voce, p a e p rev o d ilac to dozvoliti.
Veba 26: (2) P okaite k o v arijan su nizova p o m o u klasa N um ber i Integer.
Veba 27: (2) P okaite d a k o v arijan sa ne rad i s Listama i klasam a Number i Integer, a za-
tim uvedite d okerske arg u m e n te .
//: ge nericki/PametPrevodioca.java
import j a v a . u t i 1 .*;
Pozvali sm o m e to d e c o n tain s( ) i ind ex O f( ) koje p rim a ju objekte tip a Jabuka kao ar-
g u m e n te , i sve d o b ro radi. Z nai li to d a prevo dilac isp itu je k o d i proverava da li o d re e n a
m e to d a m o d ifik u je svoj objekat?
Iz d o k u m e n ta c ije za ArrayList viclim o da p rev o d ilac nije toliko p a m e ta n . D o k m e to d a
a d d ( ) p rim a a rg u m e n t tip a g enerikog p a ra m e tra , m eto d e c o n tain s( ) i indexO f( ) p ri-
m a ju a rg u m e n te tip a Object. Stoga k ad a zad ate ArrayList<? extends Voce>, a rg u m e n t za
a d d ( ) p o staje ? extends Voce. Iz to g o pisa p rev od ilac n e m o e znati koji bi p o d tip klase
Voce tre b a lo da d o e na to m esto, te stoga ne p rih v ata n ijed an od tih p o d tip o v a. Nije
538 Misliti na Javi
vano da li ste na jp re tip Jabuka sveli navie n a Voce - prev o d ilac p ro s to o d b ija da pozove
m e to d u (kao to je a d d ( )) uk o liko je u listi a rg u m e n a ta do kersk i a rg u m en t.
A rg u m en ti m eto d a co n tain s( ) i ind ex O f( ) tip a jesu Object, n e m a nikak vih d o-
kerskih arg u m en a ta, i prev o d ilac dozvoljava poziv. To zn ai d a je na p ro je k ta n tu generi-
ke klase d a o d lu i koji p ozivi su b ez b e d n i i d a za njih ov e arg u m e n te u p o tre b i tip Object.
U koliko hoete d a o n e m o g u ite o d re e n i p oziv k ad a se u tip u u p o treb lja v a dokerski
arg u m en t, u listu a rg u m e n a ta stavite p a ra m e ta r tip a.
To m o ete vid eti u ovoj v eom a je d n o sta v n o j klasi Skladiste:
//: genericki/Skladiste.java
Kontravarijansa
M oe se o tii i s u p ro tn im p u te m i u p o tre b iti dokerski argum ent nadtipa. Tada kaete da
je do kersk i a rg u m e n t o g ran ien bilo k o jo m n a tk laso m o d re e n e klase, tako to zad ate <?
super MojaKlasa> ili ak u p o tre b ite p a ra m e ta r tipa: <? super T> (iako g eneriki p ara-
m e ta r ne m o ete zad ati kao g ra n ic u n a d tip a , tj. n e m o ete rei <T super MojaKlasa>).
O vo o m o g u u je d a b ezb ed n o p ro sled ite o b jek at n ek o g tip a u generiki tip. D akle, sa do-
kerskim a rg u m e n tim a n a d tip o v a m o ete u p isiv ati u k o n te jn e re (objekte tip a Collection):
//: genericki/DzokeriNadtipova.java
import java.util.*;
A rg u m e n t jabuke je L ista n ekog tip a koji je n a d tip klase Jabuka; zato zn ate d a je toj li-
sti b ezb e d n o d o d a ti ob jek at tip a Jabuka ili p o d tip a klase Jabuka. M e u tim , p o to je Ja-
buka donja granica, ne zn ate da li je takvoj L isti b ezb ed n o d o d a ti Voce, p o to biste na taj
nain dozvolili da se L ista o tv a ra za d o d av an je tip o v a koji n isu Jabuka, to bi ugrozilo
b e z b e d n o st statin ih tipova.
D akle, g ranice p o d tip o v a i n ad tip o v a m o ete sm a tra ti n a in im a upisivanja" (p ro -
sleivanja u m e to d u ) u generiki tip, o d n o sn o ,,uitavanja (vraanja iz m eto d e) iz gene-
rikog tipa.
G ran ice n a d tip o v a u b lau ju o g ran ien ja o n o g a to m o ete da p ro sled ite u m eto d u :
//: genericki/GenerickoCitanje.java
import java.util.*;
//: genericki/NeograniceniDzokeri1.java
import java.util
//: genericki/NeograniceniDzokeri'2.java
import java.util
//: genericki/Dzokeri.java
// Istraivanje znaenja dokerskih argumenata.
// skladiste.set(arg); // Upozorenje:
// Unchecked call to set(T) as a
// member of the raw type Skladiste
// (Neproveren poziv metode set(T) kao
// lana sirovog tipa Skladiste)
// skladiste.set(new DzokeriO); // Isto upozorenje
siroviArgumenti(sirovo, lng);
siroviArgumenti(potpunoZadato, lng);
siroviArgumenti(neograniceno, lng);
siroviArgumenti(ograniceno, Ing);
neogArg(sirovo, lng);
neogArg(potpunoZadato, lng);
neogArg(neograniceno, lng);
neogArg(ograniceno, Ing);
divljiNadtip(potpunoZadato, lng);
// divljiNadtip(neograniceno, lng); // Greska:
// divljiNadtip(Skladiste<? super T>,T) ne mo e biti
// primenjena na (Sk1adiste<(rezultat od) ?>,Long)
// divljiNadtip(ograniceno, lng); // Greska:
// divljiNadtip(Skladiste<? super T>,T) ne moe biti
// primenjena na (Skladiste<(rezultat od) ? extends Long>,Long)
}
} III--
U m eto d i siroviA rgum enti( ), p revodilac zn a d a je Skladiste gen erik i tip, pa iako je
o vde izraen k ao sirov tip, p revodilac zna d a p ro sled iv an je o b jek ta tip a Object m etodi
s e t( ) nije b ezbedno . Poto je to sirov tip , m eto d i s e t( ) m o ete p ro sled iti o b jek at bilo ko-
jeg tip a koji e biti sveden navie na Object. D akle, k ad g o d im a te sirov tip, n em ate p ro-
v eru u v rem e prevoenja. Isto po k azu je poziv m eto d e g e t( ): n em a tip a T, pa rezultat
m o e biti sam o Object.
Lako je pom isliti da su sirovo Skladiste i Skladiste<?> p rib lin o ista stvar. M etoda
neogA rg( ) istie njihovu razliitost - o n a otkriva istu vrstu p ro b lem a, ali ih prijavljuje kao
greke, a ne kao upozorenja, p o to sirovo Skladiste p rim a sve kom b in acije svih tipova, d o k
Skladiste<?> p rim a h o m o g en u kolekciju odreenog tipa, i ne m oete m u proslediti Object.
Poglav|je 15: Generiki tipovi 547
Konverzija hvatanjem
Jedna k o n k re tn a situacija zahteva da u p o tre b ite do k erski a rg u m e n t < ?> , a ne sirov tip.
Ako sirov tip p ro sledite m e to d i koja u p o treb ljav a < ?> , p revo dilac m o e da zakljui koji je
stvarn i p a ra m e ta r tipa, tako da i ta m eto d a m o e da pozove d ru g u m e to d u koja p rim a
548 Misliti na Javi
//: genericki/KonverzijaHvatanjem.java
Nedostaci
U o v o m o d eljk u g o v o rim o o n ek im ned o stacim a korienja gen erik ih tip o v a u Javi.
//: genericki/Listalnt.java
// Automatsko pakovanje nadoknauje nemogunost
// upotrebe prostih tipova u generikom kodu.
import java.util
//: genericki/SkupBajtova.java
import java.util.*;
/ / : genericki/TestProstihGenerickih.java
import net.mindview.util.*;
3909
5202
2209
5458
* ///:-
//: genericki/ViseVarijanatalnterfejsa.java
// {CompileTimeError} (Ne moe se prevesti)
interface PlacaSe<T> {}
class StekNepromenljiveVelicine<T> {
private int indeks = 0;
private Object[] skladiste;
public StekNepromenljiveVelicine(int velicina) {
skladiste = new 0bject[vel icina];
552 Misliti na Javi
//: genericki/PotrebnaKonverzija.java
import java.io.*;
import java.util.*;
/ / : genericki/ClassKonverzija.java
import java.io.*;
import java.util.*;
List<Spravica>.class.cast(ulaz.readObject())
Pa ak i kada o a te jo je d n u konverziju:
(List<Spravica>)List.class.cast(ulaz.readObject())
Preklapanje
O vo se nee prevesti, iako bi se reklo da valja p o k u ati:
//: genericki/ListaZaUpotrebu2.java
import java.util
//: genericki/UporedivLjubimac.java
V redelo b i suziti tip s kojim se po tk lasa o d UporedivLjubimac m oe p o red iti. P rim era
ra d i, Macka bi treb alo d a je u p o red iv a (engl. cottiparable) sam o s d ru g im o b jek tim a tip a
Macka:
//: genericki/OtetiInterfejs.java
// {CompileTimeError} (Ne moe se prevesti)
/ / : genericki/Ogranicenillporedi vi Ljubimci.java
// IIi samo:
Samoogranieni tipovi
U Javino m g enerik o m k o d u p e rio d i n o se p o n av lja je d a n z b u n ju ju i id io m p ro -
jek to van ja. Evo kako izgleda:
//: genericki/GenerickiTipKojiSamSebePonavlja.java
class GenerickiTip<T> {}
O vo b ism o m ogli nazvati generiki tip koji se neobino ponavlja ( Curiously Recurring
Generics, CRG), p o C o p lien o v o m ablonskom obrascu koji se neobinoponavlja u C + + -u .
O n o n eo b i n o ponavlja o d n o si se n a in jen icu d a se klasa, p rili n o n eo b in o , pojavljuje
u so pstvenoj o snov n o j klasi.
D a biste shvatili ta to znai, naglas izgovorite: P ravim n o v u klasu koja nasleuje generi-
ki tip koji im e m oje klase u zim a za svoj p a ra m e ta r. Sta generiki osnovni tip m oe da u ra-
di s d a tim im e n o m izvedene klase? Pa, u Javi se generiki m e h a n iza m o d n o si n a arg u m en te
i p o v ra tn e tipove; o n m oe d a n ap rav i o sn o v n u klasu koja za svoje arg u m en te i p o v ratn e
tipove up otrebljava izvedenu klasu. Isto tako, izvedenu klasu o n m oe da upo treb i za tipove
polja, iako e o n i brisan jem b iti svedeni n a Object. To izraava sledea generika klasa:
D obili sm o o b i an generiki tip ije m eto d e i p rim a ju i d a ju objekte istog p aram e tar-
skog tip a , k ao i m e to d u koja o b ra u je to u sk lad iten o polje (iako n ad njim obavlja sam o
op eracije tip a Object).
OsnovnoSkladiste m o em o d a u p o tre b im o u g en erik o m tip u koji se n eo b in o p o -
navlja (CRG):
klasa, ali se za sve a rg u m e n te i p o v ra tn e v red n o sti te fu n k cio n aln o sti, u p o trebljava izvede-
ni tip. D ru g im reim a, u rezultujuoj klasi se u p o treb ljav a taan, a n e o sn o v n i tip. Z ato su
u klasi Podtip i a rg u m e n t m e to d e s e t( ) i p o v ra tn i tip m eto d e g e t( ) ta n o tipa Podtip.
Samoogranienje
OsnovnoSkladiste m o e d a upotrebi bilo koji tip k a o svoj generiki parametar, k a o ovde:
class Drugo {}
class DrugoOsnovno extends OsnovnoSkladiste<Drugo> {}
//: genericki/SamoOgranicavajuci.java
class D {}
// Ovo ne moete:
// class E extends SamoOgraniceni<D> {}
// Greka u vreme prevoenja: parametar tipa D nije unutar svojih granica
558 Misliti na Javi
/ / : generi cki/NijeSamoOgranicena.java
class D2 {}
// Ovo je sada ispravno:
class E2 extends NijeSamo0granicena<D2> {} ///:-
//: genericki/SamoOgranicavajuceMetode.java
Kovarijansa argumenata
V red n o st sa m o o g ran i av aju ih tip o v a jeste to to proizv od e kovarijantne tipove argu-
m enata - t i p o v i a rg u m e n a ta m e to d a v a rira ju k ao n jihove potklase.
lako sa m o o g ran iav aju i tip o v i p ro izv o e i p o v ra tn e tipove koji su isti kao tip p o tk la-
se, to nije toliko van o, p o to je Java SE5 uvela kovarijantne povratne tipove.
//: genericki/KovarijantniPovratniTipovi.java
class Osnovna {}
class Izvedena extends Osnovna {}
interface ObicnaDajOb {
Osnovna dajob();
}
//: genericki/GenerickeMetodelPovratniTipovi.java
//: genericki/ObicniArgumenti.java
class ObicnaZadajOb {
void set(Osnovna osnovna) {
System.out.println("ObicnaZadajOb.zadajOb(Osnovna)");
}
}
}
} /* Ispis:
IzvedenaZadajOb.zadajOb(Izvedena)
ObicnaZadajOb.zadajOb(Osnovna)
* ///:-
//: genericki/SamoOgranicavanjelKovarijantniArgumenti.java
/ / : genericki/ObicnoGenerickoNasledjivanje.java
//: genericki/ProveravanaLista.java
// Koristimo metodu Collection.checkedList().
import podaciotipu.ljubimci.*;
import java.util.*;
Izuzeci
U gen erik o m kod u se, zbog brisan ja, izuzeci veom a m alo u p o treb ljav aju . B lok c a tc h ne
m oe da hvata izuzetke generikog tipa, zato to taa n tip izuzetka m o ra b iti p o z n a t i u
v rem e p rev o en ja i u v rem e izvravanja. Takoe, generika klasa ne m o e ni p o sre d n o n i
n ep o sre d n o da nasledi klasu T h ro w a b le (i tim e o p e t spreava d a definiete generiki izu-
zetak koji se ne m oe uh vatiti).
564 Misliti na Javi
/ / : genericki/GenerisanjeGenerickoglzuzetka.java
import java.util.*;
Pokretac0brada<Integer,Greska2> pokretac2 =
new Pokretac0brada<Integer,Greska2>();
for(int i = 0 ; i < 3 ; i++)
pokretac2.add(new Preradjivac2());
try {
System.out.println(pokretac2.obradiSve());
} catch(Greska2 e) {
System.out.println(e);
}
}
} ///:-
Preradjivac poziva m e to d u o b ra d a ( ) i m o e generisati izuzetak tip a E. R ezultat m e-
to d e o b ra d a ( ) sm eta se u List<T> kontejnerRezultata (to nazivam o param etar kolekci-
je). Klasa PokretacO brada im a m e to d u obradiSve( ) koja izvrava sve o bjek te tipa
O brada koje klasa sadri i vraa kontejnerRezultata.
Da ne m o ete p a ra m e triz o v a ti g en erisan e izuzetke, ne b iste m ogli napisati ovaj k o d
generiki, i to zbog prov erav an ih izuzetaka.
Veba 36: (2) D o d ajte d ru g i p a ra m e triz o v a n i izuzetak kJasi Preradjivac i pok aite da izu-
zeci m o g u da se m en jaju nezavisno.
Miksini
T erm in miksin (engl. m ixin) s v re m e n o m je d o b io razn a znaenja, ali o sn o v n o je: m eanje
m o g u n o sti vie klasa da bi se d o b ila rezu ltu ju a klasa koja prestavlja sve um ean e tip o -
ve, tj. o n a se naziva m eavina ili m iksin. To se o b in o radi u zadnji as, to je ini p rig o d -
n o m alatk o m za lako sastavljanje klasa.
Jedna o d p re d n o sti m ik sin a jeste to to o n i k arak teristik e i p o n aan ja d o sled n o p ri-
m e n ju ju na razn e klase. Uz to, k ad a neto p ro m e n ite u m iksin klasi, te p ro m e n e se pre-
nose na sve klase na koje se m ik sin p rim e n i. Z ato su m iksini zn aajan d eo aspektno
orijentisanogprogram iranja (A O P), a za reavanje p ro b le m a s m eav in am a esto se p red -
lau razni aspekti.
566 Misliti na Javi
//: genericki/Miksini.cpp
#include <string>
#include <ctime>
#include <iostream>
using namespace std;
class Osnovni {
string vrednost;
publi c:
void postavi(string vre) { vrednost = vre; }
string daj() { return vrednost; }
t;
int main() {
SVremenskomOznakom<SaSerijskimBrojem<Osnovni> > miksinl, miksin2;
miksinl.postavi("ispitni znakovni niz 1");
miksin2.postavi("ispitni znakovni niz 2");
cout miksinl.daj() " " miksinl.dajOznaku()
" " miksinl.dajSerijskiBrojO endl;
cout miksin2.daj() " " miksin2.daj0znaku()
" " miksin2.dajSerijskiBroj() endl;
Poglavlje 15: Generiki tipovi 567
} /* Ispis: (primer)
ispitni znakovni niz 1 1129840250 1
ispitni znakovni niz 2 1129840250 2
* ///:-
U m eto d i m a in ( ), rez u ltu ju i tip o b jekata m iksinl i m iksin2 im a sve m eto d e u m ea-
n ih tipova. S m atrajte m ik sin fu n k c ijo m koja preslikava p o sto jee klase na nove potklase.
O b ra tite p an ju na to kako se p o m o u ove teh n ik e lako prave m iksini; u sutini, vi sam o
kaete: Evo ta h o u , i to se izvri:
//: genericki/Miksini.java
import java.util.*;
interface Osnovni {
public void postavi(String vre);
public String d aj();
}
//: genericki/dekorator/Dekorisanje.java
package genericki.dekorator;
import java.util.*;
class Osnovni {
private String vrednost;
public void set(String vre) { vrednost = vre; }
public String daj() { return vrednost; }
}
Z a razlik u o d statin o g tip a, sam o d in am ik i tip sadri sve u m ean e tipove, p a ovo i
dalje nije o n a k o lepo kao C + + -o v p ristu p , jer m o ra te da svedete n an ie n a o d g o v araju i
tip pre n eg o to pozovete m eto d e za njega. M e u tim , z n a tn o je blie p rav o m m ik sin u .
U p o d r k u m ik sin a u Javi u lo en o je p rilin o m n o g o rad a. E ksplicitno za tu sv rh u n a-
p rav ljen je i n ajm an je je d a n softverski d o d atak , jezik Jam.
Veba 39: (1) U p ro g ra m M iksinDinamickimPosrednikom.java d o d a jte n o v u m iksin
klasu Obojen, um eajte je u m iksin i d okaite da radi.
572 Misliti na Javi
Latentni tipovi
N a p o e tk u ovog poglavlja p red stav ili sm o id eju p isan ja k o d a koji se m o e p rim e n iti
u o p te n o u najveoj m o g u o j m eri. D a b ism o to p o stig li, m o ra m o u blaiti o g ran ien ja
tip ov a s ko jim a na k o d rad i, a d a n e iz g u b im o p re d n o s ti stati n e p rovere (b ezb ed n o sti)
tipova. Tada em o m o i d a p iem o k o d koji se bez iz m e n a m o e u p o treb ljav ati u vie si-
tuacija - tj. optiji kod.
Izgleda d a Javin generiki k o d p rav i jo je d a n k o ra k u to m sm eru . Kada piete ili k o ri-
stite generik i k o d koji sa m o uva o b jekte, o n ra d i sa svim tip o v im a (sem p ro stih , iako
sm o videli da au to m a tsk o p ak o v an je to izglauje). Ili, d ru g im reim a, g eneriko skladite
m oe da kae: M eni je svejedno koji si tip . K od k ojem nije vano s ko jim tip o v im a radi,
zaista se m oe p rim e n iti sv u d a i stoga je p o tp u n o o p ti (g eneriki).
Kao to ste tako e videli, p ro b le m n astaje k ad a h o e te d a o b ra u je te generike tipove
(ukoliko se to n e m oe o baviti p o ziv an jem m eto d a klase O b je c t), je r b risan je zahteva da
zadate granice generikih tip o v a koji se m o g u u p o tre b iti, d a b i bilo m o g u e b ezb ed n o p o -
zivati k o n k re tn e m eto d e za generike o b jek te u vaem k o d u . To je zn aajno ogranienje
p o jm a optosti, p o to svoje generike tipove m o ra te o g ran iiti tako da n asle u ju o d re en e
klase ili realizuju o d re en e interfejse. U n ek im sluajevim a, m o d a ete u m esto generikih
klasa i interfejsa u p o tre b iti o b in e klase ili interfejse, p o to se o g ran ien i generiki tip ne
m o ra razlikovati od specificiranja klase ili interfejsa.
N eki p ro g ra m sk i jezici to reavaju tak o to k o riste latentne ili strukturirane tipove.
M alo neobavezniji te rm in je duck typing, kao u izreci ,,lf it w alks like a d u c k a n d talks like
a d u ck , you m ig h t as vvell tre a t it like a d u c k . (A ko h o d a k ao p a tk a i zvui kao patka, o n d a
sm atra jte da je to p atk a.) D u ck ty p in g je p o sta o p rili n o p o p u la ra n te rm in , m o d a zato
to za so b o m ne vue istorijski p rtljag kao p re th o d n a dva te rm in a.
G eneriki k o d o b in o poziva tek n ekoliko m eto d a za o d re e n generiki tip, a jezik s la-
te n tn im tip o v im a ublau je to o g ra n i e n je (i daje o ptiji k o d ) tako to zahteva realizo-
vanje sam o nekog p o d sk u p a m e to d a , a ne o d re e n e klase ili interfejsa. L aten tn i tipovi
o m o g u u ju rad s razn im h ije ra rh ija m a klasa je r se poziv aju m e to d e koje n isu deo zajed-
n ikog interfejsa. Stoga pare k o d a m o e zap ravo rei: ,A ko m oe g o v o r i ti ( ) i se d eti( ),
m e n i je svejedno koji si tip . U koliko ne zahteva o d re e n tip , kod je optiji.
L atentni tipov i su m e h a n iz a m za rasp o re iv an je i p o n o v n o korienje koda. V iekrat-
n o u p o treb ljiv k o d je lake p isati s n jim a nego bez njih . R asporeivanje i p o n o v n o ko-
rienje koda jesu o sn o v n i p rin c ip i sveg p ro g ra m ira n ja : napii k o d je d a n p u t, koristi ga
vie p u ta i uvaj n a je d n o m m estu . Poto n e m o ra m da n avedem o d re e n i interfejs koji
m oj k o d o b ra u je , la te n tn i tip o v i m i o m o g u u ju d a piem m an je k oda i d a ga lake p ri-
m en ju jem na vie m esta.
O d jezika koji p o d rav aju la te n tn e tip o v e, dva su P y th o n (m o ete ga b esp latn o p re u -
zeti n a adresi w ww .Python.org) i C + + .6 P y th o n tipove proverava d in am ik i (gotovo sve
p ro veravanje tipov a obavlja se u v rem e izvravanja), a C + + statiki (u v rem e prev o en ja).
D akle, late n tn i tip ovi ne zah te v aju n i statiko ni d in am i k o p ro vcravanje tipova.
A ko u z m e m o g o rn ji o p is i izrazim o ga n a P y th o n u , d o b i em o ovo:
#: genericki/PsiIRoboti.py
class Pas:
def govoriti (self):
print Av!"
def sedeti(self):
print "Sedim"
def reprodukovatise(self):
pass
class Robot:
def govoriti(self):
print "Klik!"
def sedeti(self):
print "Klank!"
def promenaUlja(self):
pass
def obavi(bilosta):
bi1osta.govori t i ()
bi1osta.sedeti()
a = Pas()
b = Robot()
obavi(a)
o bavi(b)
#:~
//: genericki/PsiIRoboti.cpp
class Pas {
publi c:
void govoriti() {}
574 Misliti na Javi
void sedeti() {}
void reprodukovatiseO {}
};
class Robot {
public:
void govoriti() {}
void sedeti () {}
void promenalllja() {
};
int main() {
Pas d;
Robot r;
obavi(d);
obavi(r);
} III--
I u P y th o n u i u C + + -u , P as i R o b o t n em aju n ita zajedniko, sem to im aju dve m e-
to d e sa id e n ti n im p o tp isim a . Sa sta n o v ita tipova, to su sasvim razliiti tipovi. M e u tim ,
funkciji o b a v i ( ) nije vano koji je tip n jen o g a rg u m en ta, a la ten tn o st tip o v a jo j o m o -
guuje da p rih v ati objekte o b a tip a.
C + + p ro verava m o e li zaista d a poalje te p oruk e. A ko p o ku ate d a prosled ite p o -
grean tip , p rev o dilac e v am ispisati p o ru k u o greci (te p o ru k e o grekam a su o d uv ek
bile uasne i o p irn e, i o sn o v n i su razlog to C + + -o v i ab lo ni im aju iou rep u taciju ). Iako
to rad e u razliita v re m en a - C + + u v rem e p revo en ja, a P y th o n u vrem e izvravanja -
o b a jezika p roveravaju u p o tre b u tip o v a, pa ih sm a tra ju strogo tipiziratiim jezicim a.7 La-
te n tn i tip o v i ne u groavaju stro g u tip iziran o st.
Poto su g eneriki tip o v i u Javu d o d a ti n ak n a d n o , nije bilo anse da se realizuje bilo
koja v rsta la te n tn ih tipova, pa Java n e m a tu m o g u n o st. Z ato isprva izglea kao da je Ja-
vin generiki m eh a n iza m m an je generik i" o d jezika koji p o drav aju la te n tn e tip ov e.8
N a p rim er, ako g o rn ji p rim e r p o k u a m o da realizujem o u Javi, m o raem o da u p o tre b im o
klasu ili interfejs koje e m o sp ecificirati u izrazu za granice:
//: genericki/Obavlja.java
//: genericki/PsiIRoboti.java
// U Javi nema latentnih tipova
import podaciotipu.ljubimci.*;
import static net.mindview.util.Print.*;
class Komuniciraj {
public static <T extends Obavlja>
void obavi(T izvodjac) {
izvodjac.govoriti();
izvodjac.sedeti();
}
}
//: genericki/ProstiPsiIRoboti.java
// Uklanjamo generiki kod; prograin i dalje radi.
class KomunicirajJednostavno {
static void obavi(Obavlja izvodjac) {
izvodjac.govorit i ();
izvodjac.sedeti();
576 Misliti na Javi
)
}
Refleksija
Jedan p ristu p je u p o treb a refleksije. Evo m e to d e o b a v i ( ) koja u p o treb ljav a laten tn e tipove:
//: genericki/LatentnaRefleksija.java
// Pravljenje latentnih tipova pomou refleksije.
import java.lang.reflect.*;
import static net.mindview.util.Print.*;
class KomunicirajRefleksivno
public static void obavi(Object zvucnik) {
Class<?> zvck = zvucnik.getClass();
try {
try {
Method govoriti = zvck.getMethod("govoriti");
govoriti.invoke(zvucnik);
} catch(NoSuchMethodException e) {
print(zvucnik + " ne moe govoriti");
}
try {
Method sedeti = zvck.getMethod(sedeti");
sedeti.invoke(zvucnik);
} catch(NoSuchMethodException e) {
print(zvucnik + 11 ne moe sedeti");
}
} catch(Exception e) {
throw new RuntimeException(zvucnik.toString(), e ) ;
}
}
}
P ogledajm o p rim e r koji istrau je taj p ro b lem . P retp o sta v im o d a h o e te da n ap rav ite
m e to d u p r i m e n i ( ) koja bilo koju m e to d u p rim e n ju je n a sve o b jek te u nekoj sekvenci. U
ovoj situaciji interfejsi kao da ne o d g o v araju . H o ete d a p rim e n ite b ilo k o ju m e to d u na
kolekciju objekata, a interfejsi n a m e u o g ran ien je koje ne dozvoljava d a o piete bilo
koju m e to d u . Kako da to u rad ite u Javi?
P ro b lem m o e m o n ajp re da reim o refleksijom , i to isp ad a p rili n o eleg a n tn o zbog ar-
g u m e n a ta prom enljive d u in e koji se k o riste o d Jave SE5:
//: genericki/Primeni.java
// (main: TestZaPrimeni}
import java.lang.reflect.*;
import java.util.*;
import static net.mindview.util.Print.*;
class Oblik {
public void rotirati() { print(this + " rotirati"); }
public void promvelicine(int novaVelicina) {
print(this + " promvelicine " + novaVelicina);
}
}
class TestZaPrimeni {
public static void main(String[] args) throws Exception {
List<Oblik> oblici = new ArrayList<0blik>();
for(int i = 0; i < 10; i++)
obl ici.add(new Oblik()) ;
Primeni.primeni(oblici, Obl ik.class.getMethod("rotirati));
Primeni .primeni (obl ici,
Oblik.class.getMethodC'promvelicine", int.class), 5);
List<Kvadrat> kvadrati = new ArrayList<Kvadrat>();
for(int i = 0; i < 10; i++)
kvadrati.add(new Kvadrat());
Primeni.primeni(kvadrati, Oblik.class.getMethod("rotirati));
Primeni.primeni(kvadrati,
Oblik.class.getMethod("promvelicine", int.class), 5);
//: genericki/JednostavanRedZaCekanje.java
// Drugaija vrsta kontejnera koji je iterabilan
import java.uti1 .*;
class Ugovor {
private static long brojac = 0;
private final long id = brojac++;
public String toStringO {
return getClass().getName() + " " + id;
}
}
class PrenosVlasnistva extends Ugovor {}
class PopuniTest {
public static void main(String[] args) {
List<Ugovor> ugovori = new ArrayList<Ugovor>();
Popuni.popuni(ugovori, Ugovor.class, 3);
Popuni.popuni(ugovori, PrenosVlasnistva.class, 2);
for(Ugovor c: ugovori)
System.out.println(c);
JednostavanRedZaCekanje<Ugovor> redUgovora =
new JednostavanRedZaCekanje<Ugovor>();
// Nee raditi. popuni() nije dovoljno opta:
// Popuni.popuni(redUgovora, Ugovor.class, 3);
582 Misliti na Javi
} /* Ispis:
Ugovor 0
Ugovor 1
Ugovor 2
PrenosVlasnistva 3
PrenosVlasnistva 4
* ///:-
//: genericki/Popuni2.java
// Upotreba adaptera za simuliranje latentnih tipova.
// (main: Popuni2Test}
import genericki.kafa.*;
import java.util.*;
import net.mindview.util.*;
import static net.mindview.uti1.Print.*;
imaadd.add(classLeksema.newInstance());
) catch(Exception e) {
throw new RuntimeException(e);
}
}
// Generatorska verzija:
public static <T> void popuni(ImaAdd<T> imaadd,
Generator<T> generator, int velicina) {
for(int i = 0; i < velicina; i++)
imaadd.add(generator.sledeci());
}
class Popuni2Test {
public static void main(String[] args) {
// Prilagodi kontejner (objekat tipa Collection):
List<Kafa> nosilac = new ArrayList<Kafa>();
Popuni2.popuni(
new ImaAddCol1ectionAdapter<Kafa>(nosi 1ac),
Kafa.class, 3);
// Pomagaka metoda tip hvata:
Popuni2.popuni(Adapter.adapterKolekcije(nosilac),
SMlekom.class, 2);
584 Misliti na Javi
for(Kafa c: nosilac)
print(c);
print("................. ...... ");
// Upotreba prilagoene klase:
ImaAddJednostavanRedZaCekanje<Kafa> redKafa =
new ImaAddJednostavanRedZaCekanje<Kafa>();
Popuni2.popuni(redKafa, Moka.class, 4);
Popuni2.popuni(redKafa, SMlekom.class, 1);
for(Kafa c: redKafa)
print(c);
}
} /* Ispis:
Kafa 0
Kafa 1
Kafa 2
SMlekom 3
SMlekom 4
Moka 5
Moka 6
Moka 7
Moka 8
SMlekom 9
* ///:-
" Za njih se upotreb ljava i im e funktori la u koristiti te rm in funkcijski objekat, p oto funktor" ima
specifino i d ru g o znaenje u inatem atici.
586 Misliti na Javi
import java.util.*;
import static net.mindview.util .Print.*;
for(T t : sekv)
if(pred.test(t))
rezultat.add(t);
return rezultat;
}
// Da bismo mogli da koristimo gornje generike metode,
// moramo napraviti funkcijske objekte za prilagoavanje metoda
// naim specifinim potrebama:
static class SabiracCelih implements Kombinator<Integer> {
public Integer objedini(Integer x, Integer y) {
return x + y;
}
}
static class
OduzimacCelih implements Kombinator<Integer> {
public Integer objedini(Integer x, Integer y) {
return x - y;
}
}
static class
SabiracVelikihDecimalnih implements Kombinator<BigDecimal> {
public BigDecimal objedini(BigDecimal x, BigDecimal y) {
return x.add(y);
}
}
static class
SabiracVelikihCelih implements Kombinator<BigInteger> {
public Biglnteger objedini(Biglnteger x, Biglnteger y) {
return x.add(y);
}
}
static class
SabiracAtomicLong implements Kombinator<AtomicLong> {
public AtomicLong objedini(AtomicLong x, AtomicLong y) {
// Nisam siguran da ovo ima smisla:
return new AtomicLong(x.addAndGet(y.get()));
}
}
// Moemo napraviti ak i UnarnuFunkciju s metodom "ulp
// (Units in the last place, jedinica na poslednjem mestu):
static class VelikiDecimalniUlp
implements UnarnaFunkcija<BigDecimal,BigDecimal> {
public BigDecimal funkcija(BigDecimal x) {
return x.ulp();
}
}
static class VeceOd<T extends Comparable<T
implements UnarniPredikat<T> {
private T granica;
public VeceOd(T granica) { this.granica = granica; }
588 Misliti na Javi
print(forEach(li,
new KolektorMnoziCele()).rezultat());
print(filtar(lvd,
new VeceOd<BigDecimal>(new BigDecimal(3))));
P o injem defin isanjem interfejsa za razliite tipove fu nkcijskih objek ata. N jih sam
prav io p o p o treb i, kako sam razvijao razliite m eto d e i u v i ao p o tre b u za svakim . Klasu
K om binator je p red lo io a n o n im n i k o m e n ta to r jedn og o d lanaka ob jav ljenih n a m ojoj
W eb lokaciji. Kombinator a p stra h u je k o n k retn e detalje sa b iran ja dva o b je k ta i k azuje
sam o da o n i bivaju nekako o b jed injen i. Kao rezultat, m oete videti da SabiracCelih i
OduzimacCelih m o g u biti tipovi n ad tip a Kombinator.
UnarnaFunkcija p rim a sam o jedan a rg u m e n t i daje rezultat; a rg u m e n t i rez u lta t ne
m o ra ju biti istog tipa. Kolektor se upotreb ljav a kao p a ra m e ta r kolekcije", a rezu ltat
m oete da izdvojite kada zavrite. U narniPredikat daje rezu ltat tip a boolean. M o g u se
d efinisati funkcijski o bjekti i d ru g ih tipova, ali ovo je bilo d o v o ljn o za p o u k u .
Klasa Funkcional sadri vie g enerikih m eto d a koje funkcijske o b jekte p rim e n ju ju na
sekvence. red u k u j( ) p rim e n ju je funkciju u o b je k tu tipa Kom binator n a svaki elem en t
sekvence da bi proizvela sam o jed a n rezultat.
fo rE ach ( ) p rim a Kolektor i p rim en ju je svoju fun kciju na svaki elem en t, z a n e m a ru -
ju i re z u lta t svakog poziva funkcije. N ju m oete p ozivati sam o zbog sp o re d n o g efekta (to
ne bi bio fu n k cio n a ln i stil p ro g ram iran ja, ali ipak m oe da po slui), ili Kolektor m oe da
o d rava in te rn o stan je d a bi p o stao p a ra m e ta r kolekcije, kao to je sluaj u ov o m p rim e ru .
tran sfo rm isi( ) pravi listu pozivanjem funkcijskog o bjekta U narnaFunkcija za svaki
o b jek at u sekvenci i h v atan jem rezultata.
590 Misliti naJavi
Proitajte i ovo
U vodni d o k u m e n t za g enerike tip o v e je Gcnerics in thc java Progratnming Langttage, iji
je a u to r G ilad B racha, a nalazi se na lokaciji h ttp://iava.fuii.coni/j2se/l.5/pdf/gcucrics-tti-
torial.pdf
Jara Gerterics FAQs A ngelike L anger veo m a je k o ristan resurs, na lokaciji www.lan-
ger.camelot.dc/GenericsFAQ/JavaGencricsFAQ.htnil.
Vie o d o k ersk im a rg u m e n tim a saznaete iz teksta A dding VVildcards to thc Java Pro-
gram tning Language, iji su a u to ri T orgerson, E rnst, H ansen, Von d e r A he, B racha i Gaf-
ter. lan ak je d o stu p a n na lokaciji w ww.iot.lin/issucs/isstie_2004_12/articlc5.
Reenja odabranih vebi data su u elektronskom dokum entu l'lic Thiitking in lciva Annotatctl Soltt-
tion Guidekoji se moe kupiti na lokaciji wmv.MiiidVicw.coiu.
Nizovi
N a kraju poglavlja Inicijalizacija i ienje objanjeno j e kako :,c definie i in icija lizu je niz.
/ / : nizovi/PoredjenjeSKontejnerima.java
import java.uti1 .
import static n e t ,mindview.uti1 .Print.*;
594 Misliti na Javi
class SferaOdBeri1ijuma {
private static long brojac;
private final long id = brojac++;
public String toStringO { return "Sfera " + id; }
}
List<SferaOdBerilijuma> listaSfera =
new ArrayList<SferaOdBerilijuma>();
for(int i = 0 ; i < 5 ; i++)
listaSfera.add(new SferaOdBerilijumaO);
print(li staSfera);
print(listaSfera.get(4));
int[] celiBrojevi = { 0, 1, 2, 3, 4, 5 };
print(Arrays.toString(celiBrojevi));
print(cel iBrojevi [4]);
U Javi se granice p roveravaju bez o b zira na to da li ko ristite niz ili k o n tejn er; p riv id n o
je jed in a razlika m e u n jim a to to nizovi im aju o p e ra to r [ ] za p ristu p a n je e lem en tim a,
a liste im aju m eto de kao to su a d d () i g et(). S linost i/m e d u nizova i klase A rra y L ist na-
m ern a je, da bi bilo lako k o ristiti i je d n e i d ru g e. Ali kao to ste videii u pogiavlju uvanje
objekata, k o n te jn e ri su m n o g o fu n k cio n aln iji o d nizova.
Poglavlje 16: Nizovi 595
sakrij(d);
a=d;
Kao p rim er, po g led ajm o kako se v raa niz e lem en ata tip a S trin g :
//: nizovi/Sladoled.java
// Vraanje nizova iz metoda.
import java.uti1
M etoda skupUkusa() pravi niz elem en a ta tipa String nazvan rezultati. D uin a niza je
od re en a a rg u m e n to m koji se p ro sle u je m eto d i. N akon toga, n asu m in o se biraju ukusi
iz niza UKUSI i stavljaju u niz rezultati koji se vraa kao rezultat m eto d e. V raanje niza
je isto kao vraanje bilo kog o b jek ta - rad i se o referenci. Nije v ano da li je niz napravljen
u n u ta r m eto d e skupUkusa() ili na bilo k o m d ru g o m m estu. S kuplja sm ea se b rin e o
b risan ju niza kada se zavri ra d s n jim , tj. niz p osto ji sve d o k vam je p o treb an .
Poglavlje 16: Nizovi 599
Uzgred, dok skupUkusa() nasum ino bira ukuse, obezbeuje da isti elem ent ne bude
izabran dvaput. To se radi u petlji do koja bira nasum ino sve d ok ne pronae neku vred-
nost to se jo ne nalazi u nizu izabran. (Naravno, moglo je da se obavi i poreenje vred-
nosti objekata klase String da bi se ustanovilo da li se izabrani elem ent ve nalazi u nizu
rezultati.) Ako pronae odgovarajui element, dodaje nov ukus i trai sledei (i se pove-
ava za jedan).
Iz rezultata vidite da skupUkusa() svaki p u t bira ukuse sluajnim redosledom.
Veba 2: (1) Napiite m etodu koja prim a int argum ent i vraa niz te veliine, popunjen
objektim a SferaOdBerilijuma.
Viedimenzionalni nizovi
Lako je praviti viedim enzionalne nizove. Za viedim enzionalni niz prostih tipova, svaki
vektor niza piete u n u tar vitiastih zagrada:
//: nizovi/TriDPomocuNew.java
import java.util.*;
//: nizovi/NepravilanNiz.java
import j a v a . u t i l .*;
Prvi new pravi niz iji je prvi elem ent nasum ino odabrane duine, a ostali elem enti
neodreene duine. Drugi new unutranje petlje for popunjava elemente, ali trei indeks
ostavlja kao neodreen do treeg new.
Na isti nain m oete praviti nizove neprostih objekata. Ovde ete videti kako sm o vie
new izraza okupili u n u tar vitiastih zagrada:
} /* Ispis:
[[Sfera 0, Sfera 1], [Sfera 2, Sfera 3, Sfera 4, Sfera 5], [Sfera 6,
Sfera 7, Sfera 8, Sfera 9, Sfera 10, Sfera 11, Sfera 12, Sfera 13]]
* ///:-
Vidite da su i sfere nepravilan niz, u kojem su duine svih lista objekata razliite.
Autom atsko pakovanje radi i sa inicijalizatorim a nizova:
//: ni zo vi/AutomatskoPakovanjeNizova.java
import ja v a . u t i l .*;
//: nizovi/SastavljanjeVisedimenzionalnihNizova.java
// Pravljenje viedimenzionalnih nizova.
import java.uti1 .*;
//: nizovi/VisedimNizOmotaca.java
// Viedimenzionalni nizovi "omotakih" objekata.
import j a v a . u t i l .*;
I opet, u Integer i Double nizovima, autom atsko pakovanje Jave SE5 pravi om otake
objekte um esto nas.
Veba 3: (4) Napiite m etodu koja pravi i inicijalizuje dvodim enzionalni niz tipa double.
Veliinu niza ocireduju argum enti m etode, a inicijalizaone vrednosti su date opsegom
o dredenim poetnom i zavrnom vrednou koje su i argum enti te metode. Napravite
drugu m etodu koja ispisuje niz generisan prvom m etodom . U m etodi main() testirajte
m etode pravljenjem i ispisivanjem nekoliko nizova razliitih veliina.
Veba 4: (2) Ponovite p rethodnu vebu za trodim enzionalni niz.
Veba 5: (1) Pokaite da se viedim enzionalni nizovi neprostih objekata autom atski ini-
cijalizuju na null.
Veba 6: (1) Napiite m etodu koja prim a dva int argum enta koji pokazuju odgovarajue
dim enzije 2-D niza. M etoda treba da napravi i popuni 2-D niz SferaOdBerilijuma u skla-
du sa argum entim a dimenzija.
Veba 7: (1) Ponovite p rethodnu vebu za 3-D niz.
Poglavlje 16: Nizovi 603
Brisanjem se uklanja podatak o param etru tipa, a niz m o ra da zna taan tip koji sadri,
da bi rad s tipovim a proveravanjem uinio bezbednim .
M eutim , m oete param etrizovati tip sam og niza:
//: nizovi/ParametrizovanTipNiza.java
class ClassParametar<T> {
public T[] f ( T [] arg) { return arg; }
}
class ParametarMetode {
public static <T> T[] f(T[] arg) { return arg; }
}
Vodite rauna o pogodnosti upotrebe param etrizovane m etode um esto param etrizo-
vane klase: ne m orate da pravite instancu klase s param etrom za sve razliite tipove na
koje ete je prim eniti, i moete da je napravite statinom . N aravno, ne m oete uvek da
upotrebite param etrizovanu m etodu um esto param etrizovane klase, ali to bi m oglo da
bude bolje reenje.
Nije najtanije rei da je nem ogue napraviti niz generikog tipa. Istina je da prevodi-
lac nee dozvoliti pravljenje instance niza generikog tipa. M eutim , dopustie da napra-
vite referencu na taj niz. Na primer:
List<String>[] ls;
604 Misliti na Javi
Ovo e proi kroz prevodilac bez problem a. I m ada ne moete napraviti objekat niza koji
sadri generiki tip, moete napraviti niz negenerikog tipa i eksplicitno ga konvertovati:
im im ate referencu na L ist< S tring > [], neke provere e se obaviti u vreme pre-
voenja. Problem je to to su nizovi kovarijantni, pa je niz L ist< S tring> [] istovrem eno i
niz O bject]]. To moete upotrebiti za dodeljivanje liste A rrayL ist< Integer> svom nizu, a
da ne izazovete greku ni u vreme prevoenja ni u vrem e izvravanja.
Ukoliko znate da neete svoditi navie i potrebe su vam relativno jednostavne, lako ete
napraviti niz generikih tipova koji e biti elem entarno proveravan u vreme prevoenja.
M eutim gotovo uvek je bolje izabrati generiki kontejner nego niz generikih tipova.
Po pravilu, videete da su generiki tipovi delotvorni na granicam a klase ili metode.
U njenoj unutranjosti, brisanje ini generiki tip neupotrebljivim . Stoga ne moete, na
prim er, napraviti niz generikog tipa:
/ / : nizovi/NizGenerickogTipa.java
// Java nee da prevede nizove generikih tipova.
Arrays.fill()
Standardna klasa A rrays u Javi im a svoju m etodu fill(), ali je ona prilino prosta - samo
kopira jednu vrednost u svaki elem ent niza, a ako se radi o objektim a, kopira istu referen-
cu u svaku lokaciju. Evo prim era:
//: nizovi/PopunjavanjeNizova.java
// Upotreba metode Arrays.fill()
import ja v a . u t i 1
import static n e t . m i n d v i e w . u t i l .Print.*;
Moete da popunite ceo niz ili, kao to pokazuju poslednje naredbe, nekoliko eleme-
nata niza. M eutim , poto m etodom Arrays.fill() m oete da popunite niz samo jednom
vrednou, rezultati nisu naroito upotrebljivi.
Generatori podataka
Za pravljenje zanimljivijih nizova podataka, ali na fleksibilan nain, upotrebiem o kon-
cept G en erato ra predstavljen u poglavlju Generiki tipovi. Ako neka alatka upotrebljava
G enerator, napravljeni podaci se menjaju u zavisnosti od izabranog G en erato ra (to je
Poglavjje 16: Nizovi 607
lako to nije ba sasvim jasno. M oglo bi sc tvrditi i da G e n e ra to r predstavlja obrazac C otntnand (Ko
m anda). M edu tim , ja sm atram da je zadatak p o p u n iti niz i da G e n e ra to r obavlja deo tog zadatka, pa
irii to vie lii na strategiju nego na kom andu.
608 Misliti na Javi
baf[i] = cg.next();
return new java .l an g. St ri ng (b af);
}
}
public static class
Short implements Generator<java.lang.Short> {
private short vrednost = 0;
public java.lang.Short next() { return vrednost++; }
}
public static class
Integer implements Ge ne rator<java.1ang.Integer> {
private int vrednost = 0;
public java.lang.Integer next() { return vrednost++; }
}
public static class
Long implements Generator<java.lang.Long> {
private long vrednost = 0;
public java.lang.Long next() { return vrednost++; }
}
public static class
Float implements Generator<java.lang.Float> {
private float vrednost = 0;
public java.lang.Float next() {
float rezultat = vrednost;
vrednost += 1.0;
return rezultat;
}
}
public static class
Double implements Genera to r< ja va .1ang.Double> {
private double vrednost = 0.0;
public java.lang.Double next() {
double rezultat = vrednost;
vrednost += 1.0;
return rezultat;
}
}
} ///:-
Svaka klasa realizuje neko znaenje pojm a koliina. U sluaju klase GeneratorDa-
teKoIicine.Character, radi se o velikim i m alim slovima koja se ponavljaju. Klasa Gene-
ratorD ateK olicine.String upotrebljava GeneratorDateKolicine.Character za
popunjavanje niza znakova, koje zatim pretvara u String. Veliinu niza odreuje argu-
m ent konstruktora. O bratite panju na to da GeneratorDateKolicine.String upotreblja-
va elem entarni Generator<java.lang.Character> um esto specifine reference na
GeneratorDateKolicine.Character. Kasnije taj generator moe zam eniti RandoinGene-
rator.String iz paketa RandomGenerator.java.
Poglav[je 16: Nizovi 609
//: nizovi/TestiranjeGeneratora.java
import net.mindview.util.*;
Ovde se pretpostavlja da klasa koja se ispituje sadri skup ugneenih objekata tipa Ge-
nerator, od kojih svaki ima podrazumevani konstruktor (onaj bez argum enata). Sve ug-
neene klase proizvodi reflektivna metoda getClasses(). Zatim metoda test() pravi instancu
svakog od tih generatora i ispisuje rezultat koji se dobija s deset poziva m etode next().
Evo skupa G eneratora koji upotrebljavaju generator sluajnih brojeva. Poto se kon-
stru k to r klase R andom inicijalizuje konstantom , rezultat se ponavlja svaki p u t kada po-
m ou jednog od ovih G eneratora pozovete program :
//: net/mindview/util/GeneratorSlucajnih.java
// Generatori koji daju sluajne vr e d n o s t i .
package net.mindview.util;
import j a v a . u t i l .*;
610 Misliti na Javi
//: ni zo vi /TestiranjeGeneratoraSlucajnih.java
import net.mindview.util.*;
//: net/mindview/util/Generisani.java
package net.mindview.util;
import java.util
D efinija klase C ollectionD ata navedena je u poglavlju D etaljno razm atranje kontej-
nera. O na pravi Collection objekat popunjen elem entim a koje je napravio G en erato r
gen. Broj tih elemenata odreuje drugi argum ent konstruktora. Svi podtipovi klase Col-
lection (kontejneri) imaju m etodu toA rray() koja elem entim a kontejnera popunjava niz
zaat argum entom .
Druga m etoda upotrebljava refleksiju za dinam iko pravljenje novog niza odgovara-
jueg tipa i veliine. On se zatim popunjava isto kao 11 prvoj m etodi.
Klasu G enerisani m oemo ispitati nekom od klasa G en eratorD ateK olicine definisa-
nih u prethodnom odeljku:
//: ni zo vi /T estGenerisanih.java
import j a v a . u t i l .*;
import net.mindview.util.*;
Poglavlje 16: Nizovi 613
rezultat[i] = ul a z [ i ] ;
Evo prim era iz kojega moete videti kako se klasa K onvertujU upotrebljava sa obe ver-
zije m etode G enerisani.array():
S y st em .o ut .println(Arrays.toString(b));
boolean[] c = KonvertujU.prost(
Generisani.niz(Boolean.class,
new GeneratorDateK ol ic ine .B oo le an (), 7));
S y st em .o ut.pri ntln (A rr ay s.toStri n g (c ));
}
} /* Ispis:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
[true, false, true, false, true, false, true]
* ///:-
//: nizovi/TestGenerisanjaNizova.java
// Testiranje alatki koje nizove popunjavaju generatorima.
import ja v a . u t i l .*;
import ne t. mi nd vi ew .u ti l.*;
import static ne t. mi nd vi ew .u ti l.Print.*;
} /* Ispis:
al = [true, false, true, false, false, true]
a2 = [104, -79, -76, 126, 33, -64]
a3 = [Z, n, T , c, Q, r]
a4 = [-13408, 22612, 15401, 15161, -28466, -12603]
a5 = [7704, 7383, 7706, 575, 8410, 6342]
a6 = [7674, 8804, 8950, 7826, 4322, 896]
a7 = [0.01, 0.2, 0.4, 0.79, 0.27, 0.45]
a8 = [0.16, 0.87, 0.7, 0.66, 0.87, 0.59]
* ///:-
T im e se obezbeuje i da sve verzije m etode KonvertujU.prost() ispravno rade.
Veba 11: (2) Pokaite da autom atsko raspakivanje ne radi s nizovima.
Veba 12: (1) Napravite inicijalizovan niz tipa double pom ou klase GeneratorDateKo-
licine. Ispiite rezultate.
Veba 13: (2) Popunite objekat tipa String pom ou klase GeneratorDateKolicine.Cha-
racter.
Veba 14: (6) N apravite po jedan niz svakog od prostih tipova, zatim ih popunite pom ou
klase GeneratorDateKoIicine. Ispiite svaki niz.
Veba 15: (2) Izm enite PoredjenjeSKontejnerima.java tako to ete napraviti Generator
za objekte tipa SferaOdBerilijuma, i prepravite m etodu main() tako da taj Generator
upotrebi za Generisani.array().
Veba 16: (3) Na osnovu program a GeneratorDateKolicine.java, napravite klasu
PreskociGenerator koja nove vrednosti proizvodi poveavanjem za 1, u skladu s argu-
m entom konstruktora. Prepravite program TestGenerisanjaNizova.java tako da pokae
da vaa nova klasa radi ispravno.
Veba 17: (5) N apravite i ispitajte Generator za tip BigDecimal, i obezbedite da radi s
m etodam a klase Generisani.
Kopiranje niza
S tandarna biblioteka u favi obezbeuje statiku m etodu System.arraycopy() pom ou
koje se niz m nogo bre kopira nego kada se koristi petlja for za runo kopiranje.
System.arraycopy() je preklopljena i radi s nizovima svih tipova podataka. Evo prim era
kako ova m etoda radi s nizovim a tipa int:
//: ni zovi/KopiranjeNizova.java
// Upotreba metode System.arraycopy()
import java.util
import static ne t. mi nd vi ew .u ti l.Print.*;
A rgum enti m etode arraycopy() su izvorni niz, pom eraj u izvornom nizu od koga tre-
ba zapoeti kopiranje, odredini niz, pom eraj u odredinom nizu od koga treba da pone
kopiranje i broj elem enata za kopiranje. P rirodno, svako prekoraenje granica niza
prouzrokovae izuzetak.
Prim er pokazuje da se m ogu kopirati i nizovi prostih tipova i nizovi objekata. M eu-
tim , ako kopirate nizove objekata, kopiraju se sam o reference, ali ne i sami objekti. To se
zove povrno kopiranje (engl. shallow copy, videti dodatke knjige na Webu).
M etoda System.arraycopy() ne obavlja autom atsko pakovanje niti autom atsko raspa-
kivanje - oba niza m oraju biti tano istog tipa.
Veba 18: (3) N apravite i popunite niz objekata tipa SferaOdBerilijuma. Kopirajte taj niz
u drugi, nov niz i pokaite da je to povrna kopija.
Poreenje nizova
Klasa Arrays nudi preklopljene verzije m etode equals() za poreenje jednakosti dva niza.
I ova m etoda postoji za nizove svih prostih tipova i tipa Object. Da bi bili jednaki, nizovi
m oraju da im aju isti broj elem enata, i svaki elem ent m ora da bude jednak odgovarajuem
elem entu drugog niza, pri em u se m etoda equals () poziva za svaki element. (Za proste
tipove se koristi m etoda equals() om otake klase, npr. Integer.equals() za tip int.) Evo
prim era:
//: nizovi/PoredjenjeNizova.java
// Korienje metode Arrays.equals()
import java.util
import static ne t. m i n d v i e w . u t i l .Print.*;
//: nizovi/UporedivTip.java
// Primena interfejsa Comparable.
import java.util
import net.mindview.util.*;
import static n e t. mi nd vi ew .u ti l.Print.*;
public class UporedivTip implements Comparable {
i nt i ;
int j ;
2 Desijtt Patteriis, E ri i G am m a i dr. (A ison- Wesley, 1995). Videti Thittking in Patterns (w ith Java)
na lokaciji w w w .M indV iew .net.
620 Misliti na Javi
Kaa definiete funkciju poreenja, sam i definiete ta znai uporediti jedan objekat
vae klase s drugim . Ovde se za poredenje koriste sam o vrednosti polja i, a polje j se ne
uzima u obzir.
Poglavjje 16: Nizovi 621
M etoda generator() vraa objekat koji realizuje interfejt. Generator, tako to pravi
ano nim nu unutranju klasu. Na taj nain, inicijalizacijom sluajnim vrednostim a, prave
se objekti klase UporedivTip. U m etodi m ain(), za popunjavanje niza elem enata tipa
UporedivTip koristi se generator, a niz se p o to m ureuje. D a interfejs Com parable nije
bio realizovan, pojavila bi se greka CIassCastException u vrem e prevoenja prilikom
pokuaja pozivanja m etode sort(). To bi se desilo zato to m etoda sort() tip svog argu-
m enta konvertuje u Comparable.
Pretpostavim o da radite s klasom koja ne realizuje interfejs Comparable, ili da klasa
realizuje taj interfejs, ali vam se ne svia kako on a radi i za odreeni tip podataka radije bi-
ste koristili neku drugu funkciju za poreenje. D a biste to postigli, m orate da prim enite
drugi pristup za poreenje objekata. Treba da napravite posebnu klasu koja realizuje in-
terfejs C om parator (ukratko prestavljen u poglavlju uvanje objekata). Ovo je p rim er
projektnog obrasca Strategy. C om parator im a dve m etode, compare() i equals(). M eu-
tim , equals() se prim enjuje (realizuje) sam o kada su po treb n e specijalne perform anse, jer
se pri svakom pravljenju klase ona autom atski nasleuje iz klase Object koja im a svoju
m etodu equals(). Znai, m oete da koristite stand ardn u m eto d u equals() klase Object i
da zadovoljite uslove koje nam ee interfejs.
Klasa Collections (njom e em o se pozabaviti u n arednom poglavlju) sadri m etodu
reverseOreder(); m etoda pravi C om parator koji obre p riro d an redosled ureivanja. To
se jednostavno prim enjuje na nau klasu UporedivTip:
//: nizovi/ObrnutiRedosled.java
// Prikazuje Co l 1ec tio n s .r e v e rs eO rd er ().
import ja v a . u t i 1.*;
import net.mindview.util.*;
import static n e t . mi nd vi ew .u ti l.Print.*;
public class ObrnutiRedosled {
public static void main(String[] args) {
UporedivTip[] a = Generisan.niz(
new U p or ed iv Ti p[ 12 ], U p o r e d i v T i p. ge ne ra tor () );
print("pre uredivanja: ");
pr in t( Ar ra ys .t oS tr ing (a ));
Arrays.sort(a, Col 1 e c t i o n s .re ve rs eO rd er ());
print("nakon ureivanja: ");
pri n t ( A rr ay s.toStri ng (a ));
)
} /* Ispis:
pre ureivanja:
[[i = 58, j = 55], [i = 93, j = 61], [i = 61, j = 29]
, [i = 68, j = 0], [i = 22, j = 7 ] , [i = 88, j = 28]
, [i = 51, j = 89], [i = 9, j = 78], [i = 98, j = 61]
, [i = 20, j = 58], [i = 16, j = 40], [i = 11, j = 22]
]
nakon ureivanja:
[ [i = 98, j = 61], [i = 93, j = 61], [i = 88, j = 28]
, [i = 68, j = 0], [i = 61, j = 29], [i = 58, j = 55]
, [i = 51, j = 89], [i = 22, j = 7], [i = 20, j = 58]
, [i = 16, j = 40], [i = 11, j = 22], [i = 9, j = 78]
]
* ///-
622 Misliti na Javi
Moete napisati i sopstveni Com parator. Sledei Com parator poredi objekte tipa
UporedivTip po vrednosti njihovih polja j, a ne po vrednosti polja i:
//: nizovi/PrimerZaComparator.java
// Primena interfejsa Comparator za neku klasu.
import j a v a . u t i l .*;
import net.mindview.util.*;
import static n e t . mi nd vi ew .u ti l.Print.*;
V eba21: (3) P okuajteda uredite nizobjekata iz vebe 18. Prim enite C o m p arab le da bi-
ste reili problem . Potom napravite C o m p arato r za sortiranje objekata obrn u tim
redosledom.
Poglavlje 16: Nizovi 623
Ureivanje niza
Pom ou ugraenih m etoda moete da uredite proizvoljan niz elem enata prostog tipa, od-
nosno bilo koji niz objekata koji realizuju C o m parab le ili im aju pridrueni C o m p ara-
to r.3 Evo prim era kojim se generiu, a potom i sortiraju, sluajni objekti tipa String:
//: nizovi/UredjivanjeTipaString.java
// Uredjivanje niza elemenata tipa String.
import j a v a . u t i l .*;
import net.mindview.util.*;
import static net.mind vi ew .u ti l.Print.*;
public class UredjivanjeTipaString{
public static void main(String[] args) {
S t r i n g [] sa = Generisani .niz(new String[20],
new GeneratorSlu ca jn ih .St ri ng (5 ));
print("Pre ureivanja: ", A r r a y s .t oS tr in g( sa ));
A r r a y s .s or t( sa );
Arrays2.print("Nakon ureivanja: ", A r ra ys .t oS tr in g( sa ));
Arrays.sort(sa, C o l l e c t i o n s . r e v e r s e O r d e r O ) ;
print("Ureivanje obrnutim redom: " + Arra ys .t oS tr in g( sa ));
Arrays.sort(sa, St ri ng .C AS E_ IN SE NS ITI VE _O RD ER );
print("Uredivanje bez obzira na veliinu slova: " +
Arrays .t oS tr in g( sa ));
}
} /* Ispis:
Pre ureivanja: [YNzbr, nyGcF, 0WZnT, cQrGs, eGZMm, JMRoE, suEcU, OneOE,
dLsmw, HLGEa, hKcxr, EqUCB, bklna, Mesbt, WHkjU, rUkZP, gwsqP, zDyCy,
RFJQA, HxxHv]
Nakon ureivanja: [EqUCB, HLGEa, HxxHv, JMRoE, Mesbt, 0WZnT, OneOE,
RFJQA, WHkjU, YNzbr, bklna, cQrGs, dLsmw, eGZMm, gwsqP, hKcxr, nyGcF,
rUkZP, suEcU, zDyCy]
Ureivanje obrnutim redom: [zDyCy, suEcU, rUkZP, nyGcF, hKcxr, gwsqP,
eGZMm, dLsmw, cQrGs, bklna, YNzbr, WHkjU, RFJQA, OneOE, 0WZnT, Mesbt,
JMRoE, HxxHv, HLGEa, EqUCB]
Ureivanje bez obzira na veliinu slova: [bklna, cQrGs, dLsmw, eGZMm,
EqUCB, gwsqP, hKcxr, HLGEa, HxxHv, JMRoE, Mesbt, nyGcF, OneOE, 0WZnT,
RFJQA, rUkZP, suEcU, WHkjU, YNzbr, zDyCy]
* ///:-
Verovatno ete prim etiti da je rezultat ovog algoritm a za ureivanje niza elem enata
tipa S trin g leksikografski, odnosno na poetak postavlja rei koje poinju velikim slovom,
a potom slede rei koje poinju malim slovom. (Ovako se obino ureuju stavke u tele-
fonskim im enicim a.) Ako hoete da grupiete rei abecedno, tj. bez obzira na to da ii po-
inju velikim ili malim slovom, upotrebite String.CASE_INSENSITIVE_ORDER kao u
poslednjem pozivu m etode so rt() u gornjem prim eru.
Z auo, u lavi 1.0 i 1.1 nije postojala podrka za ureivanje objekata tip a S trin g .
62 4 Misliti na Javi
//: nizovi/PretrazivanjeNiza.java
// Koriscenje Ar ra y s . b i n a r y S e a r c h ( ) .
import java.util
import net.mindview.util.*;
import static riet.mindview.util .Print.*;
U petlji vvhile generiu se sluajne vrednosti za elem ente koji se trae, sve dok se jedna
vrednost ne pronae.
M etoda A rrays.binaryS earch() vraa vrednost koja je vea od nule ili jednaka nuli ako
se pronae traeni element. U sup ro tn om , vraa negativnu vrednost koja predstavlja me-
sto na koje bi taj elem ent trebalo da se u m etne kada bi se redosled niza runo odravao.
Vraena vrednost je:
Poglavlje 16: Nizovi 625
-(taka umetanja) - 1
Taka um etanja je indeks prvog elem enta koji je vei od traenog, odnosno a.size()
ako su svi elem enti niza m anji od traenog.
Ako niz sadri vie elem enata iste vrednosti, ne zna se koji e od njih biti pronaen. To
znai da algoritam ne podrava duplikate elem enata, ve ih tolerie. Ako vam je potrebna
ureena lista bez ponovljenih elem enata, upotrebite klasu TreeSet (koja odrava ureeni
redosled) ili LinkedHashSet (koja odrava redosled um etanja). Ove klase se um esto vas
autom atski staraju o svim pojedinostim a. Samo u sluajevima kada vam je neophodno
poboljanje perform ansi trebalo bi zam eniti, jednu od tih klasa nizom iji se redosled
odrava runo.
Ako ste za ureivanje niza objekata koristili kom parator (nizovi prostih tipova se ne
m ogu ureivati p om ou kom paratora), m orate da upotrebite isti Com parator kada pre-
traujete m etodom binarySearch() (pom ou preklopljene verzije ove funkcije). Na pri-
mer, program UrejivanjeTipaString.java m oe se prilagoditi tako da pretrauje niz:
//: nizovi/AbecednaPretraga.java
// Pretraivanje pomou komparatora.
import java.util.*;
import net.mindview.util.*;
Saetak
U ovom poglavlju, videli ste da Java prua pristojnu podrku za nizove neprom enljive ve-
liine i niskog nivoa. Takvi nizovi im aju dobre perform anse, ali ne i fleksibilnost kao u je-
zicima C i C ++. U prvoj verziji Jave, nizovi neprom enljive veliine i niskog nivoa bili su
apsolutno neophodni, ne sam o zato to su projektanti Jave (i zbog perform ansi) odluili
da Java im a i proste tipove, nego i zato to je podrka za kontejnere u toj verziji bila mi-
nim alna. Dakle, u ranim verzijama Jave, uvek je bilo preporuljivo koristiti nizove.
U kasnijim verzijama Jave, znatno se poboljala podrka za kontejnere, pa o ni sada za-
senjuju nizove po svemu sem po perform ansam a, a i perform anse kontejnera su u m eu-
vrem enu znatno poboljane. Ve sm o na vie m esta rekli da problem e s perform ansam a
obino ne prouzrokuje ono na ta program er sum nja.
Nakon uvoenja autom atskog pakovanja i generikih tipova, dranje prostih tipova u
kontejnerim a postalo je lako, pa je i to razlog da nizove zam enite kontejnerim a. Nizovi
vie nem aju ni tu iskljuivu prednost da om oguuju bezbedan rad s tipovim a, poto i ge-
neriki tipovi daju kontejnere iji se tipovi autom atski proveravaju.
Rekosmo u ovom poglavlju da su generiki tipovi prilino nepodesni za rad s nizovi-
ma, a i sami ete se uveriti kada pokuate da ih upotrebite. esto se deava da u vreme
prevoenja dobijate upozorenja unchecked ak i kada postignete da generiki tipovi i ni-
zovi na neki nain sarauju (kao to ete videti u n arednom poglavlju).
Kada se raspravljalo o konkretnim prim erim a, projektanti jezika Java u vie navrata su
m i govorili da bi umesto nizova trebalo da koristim kontejnere (pom ou nizova sam po-
kazivao specifine tehnike, pa tu m ogunost nisam im ao).
Sve navedeno pokazuje da bi kontejnerim a trebalo da date prednost nad nizovim a
kada program irate u novijim verzijama Jave. Tek kada se dokae da su perform anse pro-
blem (i da e ih prelazak na nizove znatno popraviti), trebalo bi da ponovo podelite pro-
gram na proste faktore i preete na nizove.
Ovo je prilino hrabra tvrdnja, ali neki jezici uopte nem aju nizove niskog nivoa i ne-
promenljive veliine. Imaju samo kontejnere prom enljive veliine koji su m nogo funk-
cionalniji od Javinih nizova. Prim era radi, P ython4 im a tip list ija sintaksa lii na onu
elem entarnih nizova, ali mnogo funk on alniji - m oe se ak i naslediti:
#: nizovi/PythonoveListe.py
aLista = [1, 2, 3, 4, 5]
print type(aLista) # <type 'lista'>
print aLista # [1, 2, 3, 4, 5]
print a L i s t a [4] # 5 Indeksiranje liste
aLista.append(6) # Veliina lista je promenljiva
aLista += [7, 8] # Dodavanje jedne liste drugoj
print aLista # [1, 2, 3, 4, 5, 6, 7, 8]
deoAListe = aLista[2:4]
print deoAListe # [3, 4]
4 Videti www.Python.org.
Poglavlje 16: Nizovi 627
Videti www.plip.net.
Detaljno razmatranje kontejnera
U poglavlju uvanje objekata predstavili sm o Javinu biblioteku kontejnera i n jen u osnovnu
fun kcio n aln o st, to je dovoljno za poetak rada s njim a. U ovom poglavlju iserpnije emo
istraiti ovu va n u biblioteku.
P n t m i n n tak<ntm m iia k n n t p i n p r n
Poglavlje 17: Detaljno razmatranje kontejnera 629
Popunjavanje kontejnera
M ada je problem sa tam panjem sadraja kontejnera reen, popunjavanje kontejnera ima
isti neostatak kao java.util.Arrays. Kao u paketu Arrays, postoji pratea klasa nazvana
Collections koja sadri statine uslune m etode, m eu kojim a i jednu nazvanu fill ( ).
Kao u verziji paketa Arrays, ta m etoda fill ( ) po celom kontejneru sam o duplira jednu re-
ferencu na objekat. Sem toga, ona radi sam o za List objekte, ali se proizvedena lista moe
proslediti k onstruktoru ili nekoj metodi addA ll( ):
//: kontejneri/PopunjavanjeLista.java
// Metode C o l1e c t i o n s .fi11() i Collecti on s. nC op ie s().
import j a v a . u t i 1
class AdresaStringa {
private String s;
public Ad re sa St ri ng a( St ring s) { this.s = s; }
public String t o S t r i n g O {
return s u p e r . t o S t r i n g O + " " + s;
}
}
System.o ut .p ri nt ln (li st );
}
} /* Ispis: (primer)
[AdresaStringa@82ba41 Zdravo, AdresaStringa@82ba41 Zdravo,
AdresaStringa@82ba41 Zdravo, AdresaStringa@82ba41 Zdravo]
[AdresaStringa@923e30 svima!, AdresaStringa@923e30 svima!,
AdresaStringa@923e30 svima!, AdresaStringa@923e30 svima!]
* ///:-
U p rim eru su prikazana dva naina popunjavanja kontejnera (objekta tipa Collec-
tion) referencama na jedan objekat. Prvo, m etoda CoUections.nCopies( ) pravi listu koja
se prosleuje konstruktoru; on popunjava ArrayList.
M etoda to S trin g ( ) klase A dresaStringa poziva m etodu O bject.toString( ) koja daje
im e klase i heksadecim alno prikazan klju za heiranje (engl. hash code) tog objekta - ge-
nerisan m etodom h ashC ode( ). Iz rezultata vidite da sve reference upuuju na isti obje-
kat, a isto vai i nakon poziva druge m etode, Collections.fill( ). M etodu fill( ) jo m anje
korisnom ini to to moe da zam eni sam o elem ente koji su ve u listi - ona ne moe da
dodaje nove elemente.
Generatorsko reenje
Gotovo svi podtipovi interfejsa Collection imaju konstruktor koji prim a drugi objekat
tipa Collection, iz kojega moe da popuni nov kontejner. Dakle, da bism o sainili podat-
ke za testiranje, sam o treba da napravim o klasu koja kao argum ente prim a konstruktore
nekog G eneratora (oni su definisani u poglavlju Generiki tipovi i poblie objaenjeni u
poglavlju N izo vi) i neki broj kolicina:
//: ne t/ mi nd vi ew /u ti1/PodaciKontejnera.java
// Kontejner koji podacima popunjava generator.
package net.mindview.util;
import j a v a . u t i l .*;
Kada se koristi pom ona generika m etoda, sm anjuje se koliina koda potrebnog za
u p otreb u klase.
Program PodaciKontejnera je prim er projektnog obrasca A da pter (Adapter);' on
prilagoava odredeni Generator konstruktoru nekog kontejnera, tj. podtipa klase Collection.
Evo prim era u kojem se inicijalizuje obiekat tipa LinkedHashSet:
//: kontejneri/PodaciZaTestKontejnera.java
import java.util
import net.mindview.util.*;
Elementi su u poretku kojim su bili um etani, poto L inkedH ashSet odrava ulananu
listu koja zadrava redosled umetanja.
Svi generatori definisani u poglavlju N izovi sada su dostupni preko adaptera Podaci-
K outejnera. U ovom prim eru upotrebiem o dva od njih:
//: ko ntejneri/GenerisanjePodatakaKontejnera.java
// Korienje generatora definisanih u poglavlju Nizovi.
import j a v a . u t i l .*;
import net.mindview.util.*;
1 O vo nije stroga definicija adaptera kao ona iz knjige Projektni obrasci, ali sm a tram d a je dovoljno pre-
cizna.
632 Misliti na Javi
System.out.println(new HashSet<Integer>(
new PodaciKontejnera<Integer>(
new Rand om Ge ne ra to r. In teg er (), 10)));
}
} /* Ispis:
[YNzbrnyGc, F0WZnTcQr, GseGZMmJM, RoEsuEcllO, neOEdLsmw, HLGEahKcx,
rEqUCBbkI, naMesbtWH, kjUrUkZPg, wsqPzDyCy]
[573, 4779, 871, 4367, 6090, 7882, 2017, 8037, 3455, 299]
* ///:-
D uinu objekta tipa String koji pravi R andom G enerator.String odreuje konstruktor
u argum entu.
Generatori mapa
Na isti nain m oem o napraviti m apu, ali za nju nam treba klasa Par, poto se za svaki po-
ziv Generatorove m etode n e x t( ) m o ra napraviti par objekata (jedan klju i jedna vred-
nost) za popunjavanje mape:
//: net/mindview/util/Par.java
package net.mindview.util;
}
// Dva zasebna Generatora:
public Po daciIzMape(Generator<K> genK, Ge nerator<V> genV,
int kolicina) {
for(int i = 0 ; i < kolicina; i++) {
p u t ( g e nK .n ex t( ), g e n V . n e x t ( ) ) ;
}
}
// Generator za klju i jedna vrednost:
public PodaciIzMape(Generator<K> genK, V vrednost, int kolicina){
for(int i = 0; i < kolicina; i++) {
p u t ( g e nK .n ex t( ), vrednost);
}
}
// Objekat tipa Iterable i Ge nerator vrednosti:
public Po da ciIzMape(Iterable<K> genK, Genera to r< V> genV) {
for(K kljuc : genK) {
put(kljuc, g e n V . n e x t ( ) ) ;
}
}
// Objekat tipa Iterable i jedna vrednost:
public PodaciIzMape(Iterable<K> genK, V vrednost) {
for(K kljuc : genK) {
put(kljuc, vrednost);
}
}
// Generike pomone metode:
public static <K,V> PodaciIzMape<K,V>
m a p ( G e n e r a t o r < P a r < K , V gen, int kolicina) {
return new PodaciIzMape<K,V>(gen, kolicina);
}
public static <K,V> PodaciIzMape<K,V>
ma p( Generator<K> genK, Generator<V> genV, int kolicina) {
return new P o d a c i IzMape<K,V>(genK, genV, kolicina);
}
public static <K,V> P o d a c i IzMape<K,V>
map(Generator<K> genK, V vrednost, int kolicina) {
return new PodaciIzMape<K,V>(genK, vrednost, kolicina);
}
public static <K,V> PodaciIzMape<K,V>
ma p( Iterable<K> genK, Ge nerator<V> genV) {
return new PodaciIzMape<K,V>(genK, genV);
}
public static <K,V> PodaciIzMape<K,V>
map(Iterable<K> genK, V vrednost) {
return new PodaciIzMape<K,V>(genK, vrednost);
}
} III--
63 4 Misliti na Javi
Program prua izbor - moe se koristiti: jedan objekat tipa G en erato r< P ar< K ,V ,
dva zasebna Generatora, jedan G enerator i jedna konstan tn a vrednost, jedan objekat
tipa Iterable (koji obuhvata svaki objekat tipa Collection) i jedan Generator, ili objekat
tipa Iterable i jedna vrednost. Pom one generike m etode sm anjuju koliinu koda po-
treb n u za pravljenje objekta tipa PodacilzMape.
Evo prim era korienja program a PodacilzMape. I G enerator klase Slova realizuje in-
terfejs Iterable pravljenjem Iteratora; zato se m oe upotrebiti za testiranje m etoda
PodaciIzM ape.m ap( ) koje rade sa svim objektim a koji realizuju Iterable:
//: kontejneri/TestiranjePodatakaMape.java
import j a v a . u t i l .*;
import net.mindview.util.*;
import static ne t. mi nd vi ew .u ti l.Print.*;
D vodim enzionalni niz PODACI tipa S trin g je javan, pa se moe upotrebljavati i drug-
de. FIyw eightM apa m ora realizovati m etodu e n try S e t() koja zahteva nam ensku realiza-
ciju i klase Set i klase M ap.Entry. Uloga zamajca je u tom e to svaki objekat tipa
Poglavlje 17: Detaljno razmatranje kontejnera 641
M ap.Entry jednostavno skladiti sam o svoj indeks, a ne stvarni klju i vrednost. Kada po-
zovete m etodu getKey( ) ili getV alue( ), ona e vam vratiti odgovarajui elem ent PODA-
CI odreen pom ou tog indeksa. Klasa SkupStavki se stara da njena velicina ne bude
vea od niza PODACI.
D rugi deo zamajca realizovan je u program u SkupStavki.Iterator. Umesto da se za sva-
ki par u nizu PODACI pravi objekat tipa Map.Entry, pravi se samo jedna stavka m ape
(Map.Entry) za svaki iterator. O bjekat Stavka se upotrebljava kao prozor u podatke; on
sadri sam o indeks statinog niza znakovnih nizova. Svaki p u t kada pozovete m etodu
n e x t( ) za taj iterator, indeks u objektu Stavka poveava se za 1, tako da pokazuje na sledei
par elemenata, i potom se jedini objekat tipa Stavka tog Iteratora vraa iz m etode next( ).3
M etoda select( ) pravi objekat tipa FlyweightMapa koji sadri SkupStavki eljene velii-
ne, a ovaj se koristi u m etodam a glavni grado vi( ) i im en a( ) pokazanim u metodi m a in ( ).
Za neka ispitivanja, ograniena veliina klase C ountries predstavlja problem . Na isti
nain m oem o napraviti inicijalizovane nam enske kontejnere koji im aju skup podataka
proizvoljne veliine. Sledea klasa je lista proizvoljne veliine koju (zapravo) unapred ini-
cijalizujemo Integer podacim a:
//: net/mindview/uti1/BrojackaListaIntegera.java
// Lista proizvoljne duine s probnim podacima.
package net.mindview.util;
import java.util
20 ,
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
Mape u pakctu java.util prave g ru p n e kopije m eto d am a g etK ey () i g etV a lu e() za Mape, pa ovo radi.
Kada bi nam enska m apa sam o kopirala celu Map.Entry, ovakav p ristu p bi prouzrokovao problem .
642 Misliti na Javi
Evo jedne m ape koja sadri unapred inicijalizovane jedinstvene objekte tipa In teg er i
String; i ona moe biti proizvoljne veliine:
//: net/mindview/util/BrojackaMapaPodataka.java
// Mapa neograniene duine s probnim podacima.
package net.mindview.util;
import java.util
} / * I s p is :
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8= 10 , 9 = J0 , 10=K0,
11 =L0, 12=M0, 13=N0, 14=00, 15=P0, 16=Q0, 17=R0, 18=S0, 19=T0, 20=U0,
21=V0, 22=W0, 23=X0, 24=Y0, 25=Z0, 26=A1, 27=B1, 28=C1, 29=D1, 30=E1,
31=F1, 32=G1, 33=H1, 34= 11, 35 = J1, 36=K1, 37=L1, 38=M1, 39=N1, 40= 01,
41=P1, 42=Q1, 43=R1, 44=S1, 45=T1, 46=U1, 47=V1, 48=W1, 49=X1, 50=Y1,
51=Z1, 52=A2, 53=B2, 54=C2, 55= 02, 56=E2, 57=F2, 58=G2, 59=H2}
* ///:-
lterator<T> ite rato rf) Vraa lterator<T> koji se moe koristiti za kretanje kroz elemente kon-
tejnera.
boolean remove(Object) Ako se argument nalazi u kontejneru, uklanja sejedna instanca tog ele-
menta. Vraa true akoje neto uklonjeno. (Opciona metoda).
boolean removeAII) Uklanja sve elemente koje sadri argument. Vraa true ako je neto
Kolekcija<?>) uklonjeno. (Opciona metoda).
boolean retainAllf Zadrava samo elemente koji se nalaze u argumentu (skupovni presek).
Kolekcija<?>) Vraa true ako se neto promenilo. (Opciona metoda).
int size( J Vraa broj elemenata u kontejneru.
ObjectfJ to A rra y () Vraa niz koji sadri sve elemente kontejnera.
<T> T[] toArray(T[J a) Vraa niz koji sadri sve elemente kontejnera ijije tip isti kao tip niza a,
a ne prosto Object. (Niz se mora konvertovati u odgovarajui tip).
Im ajte u vidu da ne postoji m etoda g e t( ) za izbor elem enta nasum inim pristupom .
Razlog je to to interfejs Collection sadri i Set koji odrava svoj unutranji poredak (pa
bi pretraivanje nasum inim p ristu pom bilo besm isleno). Dakle, za pregled elemenata
kolekcije m orate upotrebiti iterator.
U narednom prim eru prikazane su sve te metode. Iako one rade sa svim klasama koje
realizuju interfejs Collection, kao najmanji zajedniki imenitelj" upotrebljen je ArrayList.
//: kontejneri/MetodeKolekcija.java
// ta sve moete da uradite sa svim kolekcijama.
import java.util
import net.mindview.util.*;
import static n e t . mi nd vi ew .u ti l.Print.*;
print(c);
c.remove(Countries.PODACI[l] [0]);
print(c);
/ / Uklanjanje svih komponenata koje se nalaze
// u kolekciji - argumentu:
c.removeAll(c2);
print(c);
c. ad dA l1 (c 2);
print(c);
// Da 1 i se odredeni element nalazi u ovoj kolekciji?
String vre = C o u n t r i e s . P O D A C I [3][0];
print("c.contains(" + vre + ") = " + c. co nt ai ns (v re ));
// Da li je kolekcija u ovoj kolekciji?
print("c.containsAll(c2) = " + c. co nt ainsAll(c2));
Co ll ec tion<String> c3 =
( (Li st<Stri ng>)c).subList (3, 5);
// Zadravanje samo onih elemenata koji se nalaze
// u skupovima c2 i c3 (presek s k u p o v a ) :
c 2 .r et ai nA l1 (c 3);
print(c2);
// Odbacivanje svih elemenata iz skupa c2
// koji se pojavljuju i u skupu c3:
c2.removeAl 1 (c 3);
print("c2.isEmpty() = " + c 2 .isEm pt y( ));
c = new Ar r a y L i s t < S t r i n g > ( ) ;
c.addAll(Countries.imena(6));
print(c);
c.clear(); // Uklanjanje svih elemenata
print("posle c.clear():" + c);
I
} /* Ispis:
[ALGERIA, ANGOLA, BENIN, B0TSWANA, BURKINA FASO, B U RU ND I,
deset, jedanaest]
C o l 1ections.max(c) = deset
Collections.min(c) = ALGERIA
[ALGERIA, ANGOLA, BENIN, B0TSWANA, BURKINA FASO, B U RU ND I, deset,
jedanaest, ALGERIA, ANGOLA, BENIN, B0TSWANA, BURKINA FASO, BURUNDI]
[ANGOLA, BENIN, B0TSWANA, BURKINA FASO, BURUNDI, deset, jedanaest,
ALGERIA, ANGOLA, BENIN, B0TSWANA, BURKINA FASO, BURUNDI]
[BENIN, B0TSWANA, BURKINA FASO, BURUNDI, deset, jedanaest,
ALGERIA, ANGOLA, BENIN, B0TSWANA, BURKINA FASO, BURUNDI]
[deset, jedanaest]
[deset, jedanaest, ALGERIA, ANGOLA, BENIN, B0TSWANA,
BURKINA FASO, BURUNDI]
c.contains(BOTSWANA) = true
c. co nt ai ns Al1 (c2) = true
[ANGOLA, BENIN]
c2.isEmpty() = true
[ALGERIA, ANGOLA, BENIN, B0TSWANA, BURKINA FASO, BURUNDI]
posle c . c l e a r O : []
* ///:-
646 Misliti na Javi
Prave se ArrayListe koje sadre razliite skupove podataka i bivaju svedene navie na
Collection objekte, pa je jasno da se sem interfejsa Collection ne upotrebljava nita drugo.
U m etodi m a in ( ), pom ou jednostavnih vebi prikazane su sve m etode klase Collection.
N aredni odeljci u ovom poglavlju opisuju razliite realizacije interfejsa List, Set i Map.
Zvezdicom (*) je uvek oznaena realizacija koju bi trebalo podrazum evano izabrati. Opisi
starih klasa Vector, Stack i H ashtable dati su tek na kraju p o g lav lja- iako ne bi trebalo da
ih sam i upotrebljavate, sretaete se s njim a u starom kodu.
Opcione operacije
M etode koje obavljaju razne vrste dodavanja i uklanjanja jesu opcione operacije interfejsa
Collection. To znai da klasa koja realizuje interfejs ne m ora da sadri funkcionalne de-
finicije tih m etoda.
To je veom a neobian nain definisanja interfejsa. Kao to ste videli, u objektno ori-
jentisanom program iranju interfejs je vrsta ugovora. Pom ou njega se kae: Bez obzira
na to kako odluite da realizujete ovaj interfejs, jem im da ovom objektu m oete da alje-
te ove poruke.4 Ali opciona operacija kri to tem eljno obeanje: ne sam o da pozivanje
ovih m etoda nee uraditi nita korisno, ve e i izazvati izuzetak! Kao da sm o izgubili bez-
bednost tipova u vreme prevoenja.
Nije sve ba tako strano. U kolekciji, listi, skupu ili m api, prevodilac vas jo uvek ogra-
niava na pozivanje iskljuivo onih m etoda koje se nalaze u tom interfejsu. To je ipak
bolje od dinam ikih jezika koji pruaju m ogunost pozivanja svake m etode za svaki ob-
jekat, da bi se tek pri pokretanju program a ustanovilo da li pozvana m etoda uopte moe
da radi5. O sim toga, m noge m etode iji je argum ent kolekcija, iskljuivo itaju tu kolek-
ciju: nijedna m etoda za itanje kolekcije nije opciona.
Zato bi iko zadao da je m etoda opciona? Ovakav pristup spreava eksploziju broja in-
terfejsa. Drugaiji naini projektovanja biblioteke kontejnera uvek se zavre sa nerazm r-
sivom gom ilom interfejsa koji opisuju sve varijacije glavne tem e i zbog toga ih je teko
savladati. Nije ak ni m ogue obuhvatiti sve specijalne sluajeve u obliku interfejsa, poto
uvek m ogu da se izmisle novi interfejsi. P ristupom operacija koje nisu podrane postie
se vana svrha (avine biblioteke kontejnera: kontejneri se lako savladavaju i koriste; ope-
racije koje nisu podrane specijalan su sluaj koji se moe nauiti i kasnije. M eutim , da
bi takav pristup delovao, p otrebno je sledee:
I . Izuzetak tipa U n su p p o rted O p eratio n E x cep tio n m ora da sejavlja retko, tj. u veini
ldasa trebalo bi da rade sve operacije, a sam o u specijalnim sluajevima operacija ne
bi trebalo da bude podrana. To vai u Javinoj biblioteci kontejnera poto klase koje
najee koristite (A rrayList, LinkedList, H ashSet i H ashM ap), kao i druge kon
kretne realizacije, podravaju sve operacije. Ovakav pristup om oguuje da napravi-
te novu kolekciju, da pri tom ne obezbedite definicije svih m etoda u interfejsu
C ollection, a da je ipak uklopite u postojeu biblioteku.
4 Terrnin ,,interfejs je ovde u p o treb ljen tako da obuhvata i fo rm alnu rezervisanu re in terface i optije
znaenje: m eto e p o d ran e u svim klasam a i potklasam a".
5 M ada ovo zvui u d n o i m oda beskorisno kada je o p isan o na taj nain, videli ste, naroito u pogla-
vlju Podaci o tipu, da takvo d inam iko p on aanje m oe biti veom a m ono.
Poglavlje 17: Detaljno razmatranje kontejnera 647
Nepodrane operacije
U Javi su est izvor nepodranih operacija kontejner i pripadna struktura podataka ne-
prom enljive duine. Takav kontejner (u gornjem prim eru, listu) od niza proizvodi m eto-
da A rrays.asList( ). S druge strane, vi odluujeteda li e bilo koji kontejner (ukljuujui tu
i m ape) generisati izuzetke U nsupportedO perationException zbog upotrebe nepro-
menljivih m etoda u Idasi Collections. P rim er koji sledi sadri oba sluaja:
//: kontejneri/Nepodrzane.java
// Nepodrane operacije u Ja vi ni m kontejnerima.
import java.util
Poto m etoda A rrays.asList( ) pravi listu od niza odredene duine, ima smisla da
bud u podrane sam o one operacije koje ne menjaju d u in u niza. Svaka m etoda koja bi
prom enila d u inu pripadne struktu re podataka izazvala bi izuzetak UnsupportedO pera-
tionException koji ukazuje na poziv nepodrane m etode (greku program era).
Vodite rauna o tom e da svakoj kolekji uvek moete da prosledite rezultat m etode
Arrays.asList( ) kao konstruktorski argum ent (ili da pozovete m etodu addA lI( ), ili sta-
tinu m etodu C ollections.addA ll( )) da biste napravili pravi kontejner koji om oguuje
upotrebu svih m etoda - to se vidi iz prvog poziva m etode test( ) u funkciji m a in ( ). Takav
poziv proizvodi novu strukturu podataka prom enljive duine.
Nepromenljive m etode klase Collections omotavaju kontejner posrednikom koji izaziva
UnsupportedOperationF.xception ako izvrite bilo koju operaciju koja na bilo koji nain
menja taj kontejner. Cilj korienja tih m etoda jeste pravljenje konstantnog kontejnerskog
objekta. Naveemo kasnije oelokupan spisak nepromenljivih m etoda klase Collections.
Poglavlje 17: Detaljno razmatranje kontejnera 649
Funkcije liste
Kao to ste videli, prost tip List se prilino lako koristi. Iako najee koristite m etodu
a d d ( ) za um etanje objekata, m etodu g e t( ) za uzim anje objekata jedan po jedan i itera-
t o r ( ) za dobijanje iteratora niza, postoje i druge m etode koje m ogu da budu korisne.
Svaka od m etoda u prim eru koji slei obavlja drugu grupu aktivnosti: ono to svaka li-
sta m oe da uradi (osnovniTest( )), kretanje po listi pom ou iteratora
(k retanjeIteratoroin( )) u odnosu na izm enu objekata pom ou iteratora (prom enalte-
ratorom f )), prikaz dejstva obrade listi (vidljivTest( )), i operacije dostupne sam o u
ulananim listam a (LinkedList):
//: kontejneri/Liste.java
// ta se sve moe raditi s listama.
import ja v a . u t i 1 .
import net.mindview.util.*;
import static ne t. mindview.uti1 .P r i n t .*;
List<String> b = Countrie s. im en a( 25 );
print("b = " + b ) ;
a.addAl1 (b);
a.addAl1 (b);
p r in t( a);
// Umetanje, uklanjanje i zamena elemenata
// pomou Listlteratora:
ListIterator<String> x = a.listIterator(a.size()/2);
x. a d d( "j ed an ");
pr i n t ( a ) ;
pr in t( x. ne xt () );
x.remove();
p r in t( x. ne xt () );
x . se t( "4 7" );
p r in t( a);
// Kretanje kroz listu unazad:
x = a. l i s t l t e r a t o r ( a . s i z e O ) ;
wbile(x.hasPrevious())
printnb(x.previous() + " ");
print();
print("metoda vidljivTest goto va);
)
// Postoje operacije koje mogu obaviti
// samo ulanane liste:
public static void testirajUlancanu() {
LinkedList<String> 11 = new Li nk ed List<String>();
1 1 .addAll(Countri es .imena(25));
pri nt (11);
// Lista kao stek, stavljanje na stek:
1 1 .addFirst("jedan");
11.addFi r s t( "d va ");
pri nt (11 );
// "Zavirivanje" na vrh steka:
print (11 .getFi r s t ());
// Kao skidanje sa steka:
print(l 1 . r e m o v e F i r s t O ) ;
pri n t (11 .removeFi r s t ()) ;
// Lista kao red za ekanje,
// izvlaenje elemenata iz "repa":
pri n t (11.r e mo ve La st());
print(l 1);
}
public static void main(String[] args) {
// Pravljenje i popunjavanje nove liste svaki put:
osnovniTest(
new LinkedList<String>(Countries.imena(25)));
osnovniTest(
new Ar ra yList<String>(Countries.imena(25)));
652 Misliti na Javi
kretanjeIteratorom(
new Li nk ed Li st <S tr in g> (Co un tr ie s. im en a( 25 )) );
kretanjeIteratorom(
new ArrayLi st<Stri n g > ( C o u n t r i e s .i m e n a (25)));
promenaI te ra to ro m(
new Li nk ed Li st <S tr in g> (Co un tr ie s. im en a( 25 )) );
promenaIteratorom(
new A r r a y L i s t < S t r i ng >( Cou nt ri es .i me na (2 5) ));
vidljivTest(
new Li nk ed Li st <S tr in g> (Co un tr ie s. im en a( 25 )) );
te st ir aj Ul an ca nu ();
}
} /* (Pokrenite da biste videli rezultat)
* ///:-
Set |interfejs) Svaki element koji dodajete u skup mora da budejedinstven; u suprot-
nom, Set ne dodaje duplikat elementa. Objekii koji se dodaju u skup
moraju da definiu metodu eq u a ls[J kojom se utvruje jedinstvenost
objekta. Set ima istovetan interfejs kao Collettion. Interfejs skupa ne
garantuje odravanje elemenata u odreenom rasporedu.
HashSet* Klasa koja se koristi za skupove gde je vano brzo pronalaenje ele-
menata. Objekti moraju da definiu i metodu hash C o d ef).
TreeSet Ureden skup u obliku stabla. Iz ovog skupa mo/cte da izdvojite niz
ureden u odreenom redosledu. Elementi moraju da definiu i interfejs
Comparable.
LinkedHashSet Ima brzinu pretraivanja klase HashSet. ali iraerno odrava redosled
kojim su elementi bili umetani (redosled umetania) pomou ulanane
liste. Zato se rezultati pojavljuju u redosledu umeianja kada iterirate kroz
Set. Elementi moraju definisati i metodu h as h C o d e )).
Zvezdica pored HashSet pokazuje sledee: ako nem a dri,;>ih ogranienja, to treba da
bude podrazum evani izbor zato to je optim alan po brzini.
O brazac za definiciju m etode hashC od e( ) bie opisan u instavku poglavlja. eq u als( )
m orate da definiete i za skladitenje s transform acijom kljvi u (heiranje) i za skladitenje
u stablu, ali je m etoda h ash C o d e( ) apsolutno neophodna saino ako e se klasa nalaziti u
skupu tipa HashSet (to je verovatno, poto bi ova klasa ut- avnom trebalo da bude va
prvi izbor kao realizacija za Set) ili LinkedHashSet. M e u j'n , d obar stil program iranja
nalae da se uvek redefinie m etoda h ashC o de( ) ako se redeimie eq u als( ).
Ovaj prim er ilustruje m etode koje m oraju biti definisane i ; bi se odreeni tip uspeno
upotrebljavao sa odreenom realizacijom interfejsa Set:
class TipSkupa {
i nt i ;
public TipSkupa(int n) { i = n; )
public boolean equals(Object o) {
return o instanceof TipSkupa && (i == ((TipSkupa)o).i);
1
public String toString() { return Integer.toStrin g ( i ); }
8, 8, 8, 6, 5, 1]
[0, 5, 5, 6, 5, 0, 3, 1, 9, 8, 4, 2, 3, 9, 7, 3, 4, 4, 0, 7, 1, 9, 6, 2,
1, 8, 2, 8, 6, 7]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9]
java.lang.ClassCastException: TipSkupa cannot be cast to
j a va.lang.Comparable
java.lang.ClassCastException: Ti pHesiranja cannot be cast to
j a va.lang.Comparable
* ///:-
Da bi se pokazalo koje m etode su neophodne za odreeni skup i da bi se istovrem eno
izbeglo dupliranje koda, napravljene su tri klase. O snovna klasa TipSkupa prosto skla-
diiti jedan int i ispisuje ga m etodom to S trin g ( ). Poto sve klase uskladitene u skupovi-
ma m oraju im ati m etodu eq u als( ), i ona je uskladitena u osnovnoj klasi. Jednakost je
zasnovana na vrednosti celog broja i.
TipHesiranja nasleuje TipSkupa i dodaje m etodu h ashC ode( ) neophodnu da bi ob-
jekat bio smeten u realizaciju interfejsa Set s transform isanim kljuem.
T ipS tabla realizuje interfejs C om p arable koji je neophodan ako e objekat biti ko-
rien u ureenom kontejneru, kao to je SortedSet. (Jedina trenutno dostupna klasa
koja ga realizuje je TreeSet.) O bratite panju na to da u m etodi co m p areT o () nisam ko-
ristio jednostavnu i oiglednu konstrukciju r e tu rn i-i2. Iako je to esta greka u pro-
gram iranju, sve bi radilo kako treba sam o kada bi i i i2 bili neoznaeni celi brojevi (pod
uslovom da Java im a rezervisanu re u n sig n ed za neoznaen ceo broj, to nije siuaj).
Greka se pojavljuje za oznaen ceo broj koji nije dovoljno velik da predstavi razliku dva
oznaena cela broja (tip int). Ako je i veliki pozitivan ceo broj, a j veliki negativan ceo
broj, i-j e dovesti do prekoraenja i dae negativnu vrednost, to nije ispravno.
O d m etode co in p areT o () obino oekujete da proizvodi prirodan redosled usaglaen
s m etodom e q u a ls ( ). Ako e q u a ls () daje tru e za odreeno poreenje, onda bi
co m p areT o () trebalo da da nulu kao rezultat istog poreenja, a ukoliko e q u a ls () daje fal-
se za neko poreenje, onda bi co m p areT o () za isto poreenje trebalo da da rezultat raz-
liit od nule.
U klasi TipoviZaSkupove, m etode f ill( ) i te s t ( ) definisane su pom ou generikih
tipova da bi se spreilo dupliranje koda. Ponaanje skupa (objekta tipa Set) m etoda te s t( )
proverava s tri poziva m etode fill() za ispitni skup, pri em u pokuava da u njega ubaci
duplikate objekata. Metoda f ill() prim a skup proizvoljnog tipa i Class objekat istog tipa.
Pomou objekta tipa Class pronalazi konstruktor koji prim a celobrojni argum ent i pozi-
va taj ko nstruktor da bi skupu dodavala elemente.
Iz rezultata vidite da H ashSet uva elem ente u nekom m isterioznom poretku (koji
em o objasniti u nastavku poglavlja), L inkedH ashSet uva elem ente u poretku kojim su
bili um etnuti, a TreeSet uva elem ente u ureenom poretku (zbog naina realizacije me-
tode co m p areT o (), to je sluajno opadajui poredak).
656 Misliti na Javi
SortedSet
Elem enti u kontejneru tipa SortedSet zajemeno su u ureenom poretku, zbog ega sle-
dee m etode u interfejsu SortedSet m ogu da prue dod atn u funkcionalnost:
Com parator co m parato r( ): Proizvodi C om parator koji se upotrebljava za ovaj skup
(Set) ili null za prirodan poredak.
Object first(): Proizvodi najnii element.
Object Ia st( ): Proizvodi najvii element.
SortedSet subSet(odElement, doElement): Proizvodi prikaz ovog skupa sa elemen-
tim a od odElement, ukljuivo, do doEIement, iskljuivo.
SortedSet headSet(doElement): Proizvodi prikaz ovog skupa sa elem entim a m anjim
od doElement.
SortedSet tailSet(odElement): Proizvodi prikaz ovog skupa sa elem entim a jednakim
ili veim od elem enta odElement.
Evo jednostavnog prim era:
Iterator<Stn'ng> it = so rt ed Se t. it er at or ();
for(int i = 0; i <= 6; i++) {
if(i == 3) najmanji = it.next();
if(i == 6) najveci = it.next();
else i t . n ex t( );
}
print(najmanji);
p r in t( na jv ec i);
print(sorted Se t. su bSe t( na jm an ji, n a j v e c i ) ) ;
pr in t( so rt ed Se t. he adS et (n aj ve ci ));
pri n t ( s or te dS et.tai1Set(najmanj i));
}
} /* Ispis:
[cetiri, dva, jedan, osam, pet, sedam, sest, tri]
cetiri
tri
osam
tri
[osam, pet, sedam, sest]
[cetiri, dva, jedan, osam, pet, sedam, sest]
[osam, pet, sedam, sest, tri]
* ///:-
Redovi za ekanje
Seni u aplikacijama za paralelno izvravanje, Java SE5 je realizovala Queue (red za ekanje)
samo u kontejnerim a LinkedList i PriorityQueue koji se razlikuju po ponaanju, a ne po
perform ansam a. Sledi elem entarni prim er s veinom realizacija reda za ekanje (koje u
ovom prim eru nee sve funkcionisati), ukljuujui tu i redove za ekanje napravljene za
paralelno izvravanje. Elemente treba um etati od jednog kraja, a vaditi od drugog:
//: kontejneri/PonasanjeRedaZaCekanje.java
// Poredi ponaanje nekih redova za ekanje
import java.util.concurrent.*;
import j a v a .ut i 1.*;
import net.mindview.util.*;
658 Misliti na Javi
//: kontejneri/ListaZadataka.java
// Sloenija upotreba kontejnera PriorityQueue.
import j a v a . u t i l .*;
Veba 11: (2) Napravite klasu koja sadri objekat tipa Integer inicijalizovan m etodom ja-
va.util.Random na vrednost izm edu 0 i 100. Realizujte Comparable pom ou tog Integer
polja. Popunite objekat tipa PriorityQueue objektim a vae klase i izvucite te vrednosti
m etodom p o I l( ) da bi se pokazalo da kontejner proizvodi oekivani poredak.
p u b l i c c la s s Dvored<T> {
p r i v a t e L in ke d L is t< T > dvored = new Li nkedLi s t < T > ( ) ;
p u b l i c v o id a d d F i r s t ( T e) { d v o r e d . a d d F i r s t ( e ) ; }
p u b l i c vo id addLast(T e) { d v o r e d . a d d L a s t ( e ) ; }
p u b lic T g e tF ir s t() { re tu rn d v o r e d .g e tF ir s t( ) ; }
p u b lic T g e tLa st() { re tu rn d v o re d .g e tL a s t(); }
p u b l i c T r e m o v e F ir s t ( ) { r e t u r n d v o r e d . r e m o v e F i r s t ( ) ; }
p u b l i c T removeLast() { r e t u r n d v o r e d . r e m o v e L a s t( ) ; }
p u b lic i n t s iz e () { retu rn d v o re d .s iz e O ; }
p u b lic S trin g to S trin g O { re tu rn d v o re d .to S tr in g O ; }
// I druge metode po p o t r e b i . . .
} ///= -
Ako ovaj Dvored upotrebite u sopstvenim program im a, verovatno ete m orati da do-
date jo m etoda da bi postao upotrebljiv.
Sledi jednostavna provera klase Dvored:
p u b l i c c la s s DvoredTest {
s t a t i c v o id t e s t P o p u n ja v a n ja ( D v o re d < I n te g e r > dvored) {
f o r ( i n t i = 20; i < 27; i+ + )
d v o re d .a d d F irs t(i);
f o r ( i n t i = 50; i < 55; i++)
d v o re d .a d d L a s t(i);
}
Poglavlje 17: Detaljno razmatranje kontejnera 661
Elementi se ree umeu na oba kraja i vade sa oba kraja, pa se Dvored koristi rede od
obinog reda za ekanje (Queue).
Iscrpnije o Mapama
Kao to ste saznali u poglavlju uvanje objekata, osnovna nam ena m ape ( asocijativnog ni-
za ) jeste da odrava parove klju-vrednost (asocijacije, pridruivanja, m apiranja, presli-
kavanja), tako da vrednost m oete pronai pom ou kljua. Standardna Javina biblioteka
sadri razliite osnovne realizacije Mape: HashMap, TreeMap, LinkedHashMap, Weak-
HashMap, ConcurrentHashMap i IdentityHashMap. Svima im je zajedniki osnovni
interfejs Map, a razlikuju se u ponaanju i efikasnosti, poretku uvanja i prezentovanja
parova, roku uvanja objekata u mapi, radu m ape u vienitnim program im a i nainu
utvrivanja jednakosti kljua. Iz broja realizacija interfejsa Map trebalo bi da zakljuite
koliko je ova alatka vana.
Da biste mogli bolje da shvatite M ape, pogledaem o kako se pravi asocijativni niz. Evo
jedne izuzetno jednostavne realizacije:
p u b l i c c la s s A s o c i j a t i v n i N i z < K , V > {
p riv a te 0 b je c t [] [] p a ro vi;
p r i v a t e i n t in d e k s ;
p u b l i c A s o c i j a t i v n i N i z ( i n t du zin a ) {
p a ro v i = new O b je c t [ d u z in a ] [ 2 ] ;
}
p u b l i c v o id p u t ( K k l j u c , V v r e d n o s t) {
i f ( i n d e k s >= p a r o v i . d u z i n a )
th ro w new A r r a y I n d e x 0 u t 0 f B o u n d s E x c e p t io n ( ) ;
662 Misliti na Javi
Performanse
Perform anse su temeljni problem pri radu s m apam a, jer je linearno pretraivanje me-
todom g e t( ) veoma spor nain traenja kljua. Ovde pom ae bri kontejner H ashM ap.
Umesto sporog traenja kljua, on upotrebljava posebnu vrednost nazvanu k lju za hei-
ranjc (engl. hash codc). Klju za heiranje predstavlja nain da se odreena inform acija u
objektu pretvori u relativno jedinstven celi broj (in t) za taj objekat. M etoda
h a s h C o d e () je definisana u korenskoj klasi O bject, pa svi Java objekti m ogu da proizvedu
klju za heiranje. Kontejner H ashM ap uzim a h a s h C o d e () objekta i njom e brzo traga za
kljuem. Tim e se dobija ogrom no poboljanje perform ansi.6
Naveemo osnovne realizacije interfejsa Map. Zvezdica kod H ashM ape pokazuje da
bi je trebalo podrazum evano izabrati (ako nem a drugih ogranienja), zato to je optim i-
zovana po brzini. Ostale realizacije im aju naglaenija druga obeleja, te su sporije od
H ashM ape.
Transform acija kljueva je najei nain skladitenja elem enata u mapi. Kasnije emo
objasniti kako se obavlja ta transform acija.
Za kljueve za Mapu postavljaju se isti zahtevi kao za elem ente skupa (Set). Upoznali
ste ih u prim eru TipoviZaSkupove.java. Svaki klju m ora imati m etodu eq u a ls(). Ako se
klju upotrebljava u Mapi transform isanih kljueva, on m ora imati i propisnu m etodu
h ash C od e(). Klju koji se upotrebljava u TreeMapi m ora realizovati Comparable.
U narednom prim eru pokazaem o op era je d ostupne preko interfejsa Map, uz po-
m o prethodno definisanog skupa ispitnih podataka BrojackaMapaPodataka:
/ / : k o n t e j n e r i/ M a p e . ja v a
/ / ta se moe u r a d i t i s mapama.
im p o r t j a v a . u t i l . c o n c u r r e n t . * ;
im p o r t j a v a . u t i 1 . * ;
im p o r t n e t . m i n d v i e w . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s Mape {
p u b l i c s t a t i c v o id p r i n t K e y s ( M a p < I n t e g e r , S t r in g > mapa) {
p r i n t n b ( " V e l i i n a = " + m a p a .s iz e O + " , " ) ;
p rin tn b ("K lju e v i: " );
p r i n t ( m a p a . k e y S e t ( ) ) ; / / Daje skup k lju e v a
}
p u b l i c s t a t i c v o id t e s t ( M a p < I n t e g e r , S t r i n g > mapa) {
p r i n t ( m a p a . g e t C l a s s ( ) .g e tS im p le N a m e O ) ;
m a p a .p u tA l1 (new Broja cka MapaPodataka(25)) ;
Poglavlje 17: Detaljno razmatranje kontejnera 665
* ///:-
666 Misliti na Javi
M etoda printK eys() pokazuje kako se pravi kolekcija (Collection) od Mape. M etoda
keyS et() proizvodi skup (Set) kljueva iz Mape. Rezultate m etode v a lu es() lako ete
tam pati zbog poboljane podrke za tam panje u Javi SE5; ta m etoda pravi kolekciju od
svih vrednosti u M api. (Vodite rauna o tom e da kljune rei m oraju biti jedinstvene, dok
vrednosti m ogu im ati duplikate.) Poto M apa odrava te kolekcije, svaka izmena u kolek-
ciji odraava se u njoj pridruenoj Mapi.
O statak program a prua jednostavne prim ere svih operacija s M apam a i testira sve
osnovne vrste M apa.
Veba 14: (3) Pokaite da java.util.Properties radi u gornjem program u.
SortedMap
Ako im ate neku realizaju interfejsa SortedMap (od njih je dostupna sam o TreeMap),
ldjuevi su zajam eno u ureenom poretku, zbog ega sledee m etode interfejsa Sor-
tedMap m ogu da prue d o d atn u funkcionalnost:
Comparator com p arator(): Proizvodi kom parator za upotrebu u ovoj Mapi ili null
za p rirodni poredak.
T firstK ey(): Proizvodi najm anji klju.
T lastICey(): Proizvodi najvei Jdju.
SortedMap subMap(odKlju, doKlju): Proizvodi prikaz dela m ape s kljuevima od
kljua odKlju, ukJjuivo, do kljua doKlju, iskljuivo.
SortedMap headMap(toKey): Proizvodi prikaz dela m ape s kljuevima m anjim od
kljua doKIju.
SortedMap tailMap(fromKey): Proizvodi prikaz dela m ape s kljuevima jednakim ili
veim od Jjua odKlju.
Ovaj prim er lii na PrimerZaSortedSet.java i pokazuje to dodatno ponaanje
TreeMape:
/ / : k o n te j n e r i/ P r im e r Z a S o r t e d M a p . ja v a
/ / ta se moe u r a d i t i s mapom TreeMap.
im p o rt j a v a . u t i l . * ;
im p o r t n e t . m i n d v i e w . u t i 1 . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i 1 . P r i n t . * ;
p u b l i c c la s s PrimerZaSortedMap {
p u b l i c s t a t i c v o id m ain ( S t r i n g [ ] arg s) {
T re e M a p < I n t e g e r , S t r in g > sortedMap =
new T re e M a p < In te g e r ,S tr in g > ( n e w Bro ja cka M a p a Po d a ta ka(lO ));
p ri n t(sortedM ap);
I n t e g e r n a jm a n ji = s o r t e d M a p . f i r s t K e y ( ) ;
I n t e g e r n a jv e c i = s o rte d M a p .1a s t K e y ( ) ;
p ri n t(n a jm a n ji);
pri n t(n a jv e c i);
I t e ra to r < In te g e r> i t = sortedM ap.keyS et(). i t e r a t o r ( ) ;
f o r ( i n t i = 0; i <= 6; i+ + ) {
Poglavlje 17: Detajjno razmatranje kontejnera 667
i f ( i == 3) n a jm a n ji = i t . n e x t ( ) ;
i f ( i == 6) n a jv e c i = i t . n e x t ( ) ;
e ls e i t . n e x t ( ) ;
1
p rin t(n a jm a n ji);
p rin t(n a jv e c i);
p r i n t ( s o r t e d M a p . s u b M a p ( n a jm a n ji, n a j v e c i ) ) ;
p rin t( s o r t e d M a p . h e a d M a p ( n a j v e c i) ) ;
p r i n t ( s o r t e d M a p . t a i 1Map(najmanj i ) ) ;
}
} / * Is p is :
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=10, 9=J0}
0
9
3
7
{3=D0, 4=E0, 5=F0, 6=G0}
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 5=G0}
{3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=10, 9=J0}
* ,///:-
LinkedHashMap
M apa LinkedHashMap transform ie sve kljueve radi brzine, ali tokom prolaska parove
daje u redosledu um etanja (System .out.println() iterira kroz m apu, pa rezultate prolas-
ka moete videti). Sem toga, realizacija LinkedHashMape moe se u konstruktoru kon-
figurisati tako da upotrebljava algoritam najdavnijeg korienja (engl. least-recendy-used,
LRU) odnosno pristupanja, pa su na poetku liste elementi kojima nije pristupano (te su
stoga kandiati za uklanjanje). Tim e je olakano pravljenje program a koji periodino i-
ste smee cia bi se utedeo m em orijski prostor. Evo jednostavnog prim era u kojem su pri-
kazane obe funkcionalnosti:
/ / : k o n t e j n e r i /PrimerZaLinkedHash Map.java
/ / ta se moe u r a d i t i s kontejn erom LinkedHashMap.
im p o r t j a v a . u t i 1 . * ;
im p o r t n e t . m i n d v i e w . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s PrimerZaLinkedHashMap {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
L in k e d H a s hM a p <In te g e r,S trin g > linkedMap =
new L in k e d H a s h M a p < In te g e r,S trin g > (
new B ro ja ckaM apaPodataka(9));
668 Misliti na Javi
pr in t(linkedMap);
// Poredak najdavnijeg korienja:
linkedMap =
new LinkedHashMap<Integer,String>(16, 0.75f, true);
linkedMap.putAll(new Broj ac ka Ma pa Po da ta ka( 9));
pr in t(linkedMap);
for(int i = 0 ; i <6; i++) // Prouzrokuj pristupanje:
linkedMap.get(i);
print(linkedMap);
1 inkedMap.get(O);
pr in t(linkedMap);
}
} /* Ispis:
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=10}
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=10}
{6=G0, 7=H0, 8=10, 0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0}
{6=G0, 7=H0, 8=10, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 0=A0}
* ///:-
Iz ispisa vidite da prolazak kroz m apu zaista daje parove u redosledu um etanja, ak i u
LRU verziji. M eutim , nakon (samo) prvih est pristupanja u LRU verziji, poslednje tri
stavke prelaze na poetak liste. Zatim, kada se ponovo pristupi stavci 0, ona prelazi na
zaelje liste.
//: kontejneri/Medved.java
// Izgleda uverljivo, ali ne radi kao klju HashMape.
//: kontejneri/Prognoza.java
Poglavfje 17: Deta|jno razmatranje kontejnera 669
p u b l i c c la s s Prognoza {
p r i v a t e s t a t i c Random s lu c a ja n = new Random(47);
p r i v a t e boolean senka = s l u c a ja n . n e x t D o u b le ( ) > 0 . 5 ;
p u b lic S trin g to S tr in g ( ) {
if ( s e n k a )
r e t u r n "Jo e s t sedmica z i m e ! " ;
e ls e
r e t u r n "Rano p r o l e e l " ;
}
} ///:-
/ / : k o n te jn e ri/D e te k to rP ro le c a .ja v a
/ / Kakvo e b i t i vreme?
im p o r t j a v a . l a n g . r e f l e c t . * ;
im p o r t j a v a . u t i l . * ;
im p o rt s t a t i c n e t . i n i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s D e te k to r P r o le c a {
/ / K o r i s t i kla su Medved i l i neku njenu p o t k la s u :
p u b l i c s t a t i c <T extends Medved>
v o id o tk riv a n je P ro le c a (C 1 a s s < T > ty p e ) thro ws Exce p tio n {
Co n s tru c to r<T > meda = t y p e . g e t C o n s t r u c t o r ( i n t . c l a s s ) ;
Map<Medved,Prognoza> mapa =
new HashMap<Medved,Prognoza>();
f o r ( i n t i = 0; i < 10; i+ + )
m a p a .p u t (m e d a .n e w ln s t a n c e (i) , new P r o g n o z a O ) ;
p r i n t ( " m a p a = " + mapa);
Medved md = m e d a .n e w ln sta n c e (3 );
p r i n t ( " T r a e n j e prognoze za " + m d);
i f(m a p a .c o n ta i nsKey(md))
print(m ap a .g e t(m d ));
el se
p r i n t ( " N i j e pronaen k l j u : " + md);
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exce p tio n {
o t k r i v a n je P r o le c a ( M e d v e d . c la s s ) ;
}
} / * Is p is :
mapa= {Medved #3=Rano p r o l e e ! , Medved #7=Rano p r o l e e ! ,
Medved #5=Rano p r o l e e ! , Medved #9=Jo e s t sedmica z im e !,
Medved #8=Jo e s t sedmica z im e !, Medved #0=Jo e s t sedmica z im e !,
Medved #6=Rano p r o l e e ! , Medved #4=Jo e s t sedmica z im e !,
Medved #l=Jo e st sedmica z im e ! , Medved #2=Rano p r o l e e ! }
T ra e n je prognoze za Medved #3
N i j e pronaen k l j u : Medved #3
* ///:-
670 Misliti na Javi
Svaki Medved dobija identifikacioni broj da biste u H ashM api mogli da pronadete
odreeni objekat tipa Prognoza tako to ete kazati: Daj m i objekat tipa Prognozapri-
druen objektu #3 tipa Medved. Klasa Prognoza sadri objekat tipa boolean inicijalizo-
van m etodom java.util.random () i m etodu to S trin g() koja tum ai rezultate. M etoda
otkrivanjeProIeca() napravljena je procesom refleksije da generie p rim erak klase Med-
ved ili njene potklase i da ga upotrebljava. To e nam dobro doi kasnije, kada za reavanje
ovde prikazanog problem a nasledim o nov tip klase Medved.
HashMapa se popunjava objektim a tipa Medved i njim a prid ru en im objektim a tipa
Prognoza. Ta HashMapa se ispisuje da biste videli da je popunjena. Zatim se Medved broj
3 koristi kao klju za pronalaenje prognoze za objekat #3 tipa Medved (za koji m oete vi-
deti da m ora biti u Mapi).
Sve izgleda veom a jednostavno, aii ne radi - ne m oe da se pronae klju za #3. Pro-
blem je to to se Medved autom atski nasleuje od zajednike korenske klase Object, pa se
za generisanje kljua za heiranje za svaki objekat upotrebljava m etoda h ash C o d e() klase
Object. O na za heiranje podrazum evano upotrebljava sam o adresu svog objekta. Zato
prvi prim erak Medved(3) ne proizvodi klju za heiranje jednak kljuu za heiranje dru-
gog prim erka Medved(3), koji sm o pokuali da upotrebim o za pretraivanje.
M oda mislite da je dovoljno napisati odgovarajuu redefiniciju m etode h ash C od e().
Ali ni to nee funkcionisati sve dok ne uradite jo neto: redefiniete m etodu eq u a ls()
koja je takoe deo klase Object. HashMapa upotrebljava eq u a ls() prilikom utvrivanja
da li je klju jednak nekom kljuu u tabeli.
Prava m etoda eq u als() m ora zadovoljiti sledeih pet uslova:
1. Refleksivna: Za svaki x, x.equals(x) treba da vraa true.
2. Simetrina: Za svaki x i y, x.equals(y) treba da vraa true ako i sam o ako
y.equals(x) vraa true.
3. Tranzitivna: Za svaki x, y i z, ako x.equals(y) vraa true i y.equals(z) vraa true,
onda x.equals(z) treba da vraa true.
4. Konsistentna: Za svaki x i y, svaki poziv x.equals(y) treba dosledno da vraa true ili
dosledno da vraa false, ukoliko se inform acije upotrebljene pri utvrivanju jedna-
kosti objekata ne prom ene.
5. Za svaki x razliit od null, x.equals(null) treba da vraa false.
Ponavljam, podrazum evana m etoda O bject.equals() jednostavno poredi adrese ob-
jekata, pa jedan Medved(3) nije jednak drugom objektu Medved(3). Dakle, da biste u
HashMapi mogli da upotrebljavate sopstvene klase kao kljueve, m orate redefinisati i
hashC od e() i eq u a ls(), kao to je uraeno u sledeem reenju problem a s medvedom:
/ / : k o n t e jn e r i/ M e d v e d 2 . ja v a
/ / Klasa u p o t r e b lje n a kao k l j u u HashMapi
/ / mora r e d e f i n i s a t i metode hashCode() i e q u a l s ( ) .
//: kontejneri/DetektorProleca2.java
// Klju koji funkcionie.
Prvo, prisetite se zato transform iem o kljueve: hteli sm o m ogunost da jedan obje-
kat pronadem o pom ou drugog. To se m oe postii i pom ou kontejnera TreeMap ili ak
i realizacijom sopstvene Mape. N asuprot realizaciji s transform isanjem kljueva, naredni
prim er realizuje Mapu p om ou p ara ArrayList kontejnera. Za razliku od prim era Asoci-
jativniNiz.java, u narednom se interfejs Map p o tp u n o realizuje, to objanjava posto-
janje m etode en tryS et():
//: kontejneri/SporaMapa.java
// Mapa realizovana ArrayListama.
import java.util.*;
import net.mindview.util.*;
/ / : k o n t e j n e r i/ S t a v k a M a p e . ja v a
/ / Jednostavan i n t e r f e j s M ap.E ntry za p rim e re r e a l i z o v a n j a i n t e r f e j s a
Map.
im p o r t j a v a . u t i 1
}
p u b l i c boolean e q u a l s ( 0 b j e c t o) {
i f ( ! ( o in s t a n c e o f StavkaMape)) r e t u r n f a l s e ;
StavkaMape sm = (StavkaMape)o;
return
( k l j u c == n u l l ?
sm.getKey() == n u l l : k l j u c . e q u a l s ( s m . g e t K e y ( ) ) ) &&
(v re d n o st == n u l l ?
sm .getV alue()= = n u l l : v r e d n o s t . e q u a l s ( s m . g e t V a l u e ( ) ) ) ;
}
p u b lic S trin g to S tr in g O { r e tu r n k l ju c + " =" + vrednost; }
} ///:-
Ovde veoma jednostavna klasa StavkaMape uva i vraa kljueve i vrednosti. To je u
m etodi entrySet() iskorieno za pravljenje skupa parova klju - vrednost. O bratite
panju na to da entrySet() upotrebljava HashSet za uvanje parova, pa StavkaMape jed-
nostavno koristi m etodu h ash C od e() objekta kljuc. Iako je ovo reenje veom a jednostav-
no i naizgled funkcionie u trivijalnom testu u m etodi SporaM apa.m ain(), to nije
korektna realizacija zato to se pravi kopija skupova kljucevi i vrednosti. Korektna reali-
zacija skupa en trySet() treba da prui u v id u Mapu, a ne da pravi njenu kopiju, i taj uvid
e om oguiti modifikaciju prvobitne m ape (to kopija ne om oguuje). Priliku da reite
ovaj problem nai ete u vebi 16.
Vodite rauna o tom e da m etoda e q u a ls () klase StavkaM ape m ora da proverava i
kljueve i vrednosti. Znaenje m etode h a s h C o d e () bie opisano uskoro.
Predstavu sadraja klase SporaM apa u obliku znakovnog niza (String) autom atski
pravi m etoda to S trin g () definisana u klasi A bstractM ap.
U m etodi S p o ra M ap a .m a in () uitava se S poraM apa i zatim se prikazuje njen sadraj.
Poziv m etode g e t( ) pokazuje da to funkcionie.
Veba 15: (1) Ponovite vebu 13 uz upotrebu m ape SporaM apa.
Veba 16: (7) Prim enite testove iz program a M aps.java na klasu S poraM apa da biste pro-
veriii kako funkcionie. Popravite sve to u klasi SporaM apa ne funkcionie korektno.
Veba 17: (2) Realizujte ostatak interfejsa M ap za klasu SporaM apa.
Veba 18: (3) Napravite SporSkup po uzoru na m apu SporaM apa.java.
Transform isanje ide jo korak dalje jer im plicira da sam o elite da klju smestite negde
gde se m oe brzo pronai. Najbra struk tura za skladitenje grupe elemenata je niz, pa e
on biti upotrebljen za predstavljanje inform acija o kljuu (rekao sam inform acija o
kljuu, a ne sam og kljua). Budui da je veliina niza neprom enljiva, im am o problem :
elimo da sm estim o neodreen broj vrednosti u M apu, ali ako je broj kljueva odreen
veliinom niza, kako em o to postii?
O dgovor je da taj niz nee sadrati kljueve. Iz objekta kljua bie izveden broj - indeks
u tom nizu. Taj broj je k lju za heiranje (engl. hash code) koji daje m etoda h a s h C o d e () (u
reniku raunarske nauke nju nazivam o he fu n k c ija ilifu n k c ija za transform isanje kljue-
va), defm isana u klasi O bject i verovatno redefinisana u vaoj klasi.
Da bi se reio problem niza neprom enljive veliine, vie kljueva m oe dati isti indeks.
Dakle, m ogu nastati sudari (engl. collisions). Stoga nije vano koliki je niz; u njem u e biti
mesta za kljueve za heiranje svih objekata kljueva.
Zato postupak pronalaenja vrednosti poinje izraunavanjem kljua za heiranje koji
se upotrebljava kao indeks niza. Kada biste m ogli jem iti da nee biti sudaranja (to je m o-
gue ako im ate neprom enljiv broj vrednosti), onda biste imali savrenu fu n k c iju za trans-
form isanje kljueva, ali to je poseban sluaj.7 U svim drugim sluajevima, sudaranjem se
bavi spoljno nadovezivanje (engl. externalchaining): niz ne pokazuje neposredno na vredn-
ost, nego na listu vrednosti. Za tim vrednostim a traga se m etodom e q u a ls() na linearan
nain. Naravno, taj deo pretraivanja je m nogo sporiji, ali ako je funkcija za transfor-
misanje kljua dobra, u svakom odeljku liste bie tek nekoliko vrednosti. Stoga se umesto
pretraivanja cele liste, brzo skae na odeljak u kojem za pronalaenje vrednosti treba upo-
rediti tek nekoliko stavki. To je m nogo bre i zato je kontejner H ashM ap tako brz.
Poto sada znate osnove transform isanja kljueva, m oem o da realizujemo jednostav-
nu M apu s transform isanim kljuevima:
/ / : k o n t e jn e ri/ J e d n os ta vn a H a sh M a p a .ja v a
/ / Prim e r mape s t r a n s f o r m is a n im k lju e v im a .
im p o r t j a v a . u t i 1
im p o r t n e t . m i n d v i e w . u t i l . * ;
l ' Javi SE5, savrena funkcija za tran sfo rm isan je kljueva (he funkcija) realizovana je u kontej-
n erim a E num M ap i EnumSet, zato to enum definie neprom enljiv broj instanci. Videti poglavlje
Nabrojoni tipovi.
676 Misliti na Javi
i f ( k o f e [ i n d e k s ] == n u l l )
k o f e [ in d e k s ] = new L in k e d L i s t< S ta v k a M a p e < K ,V ( ) ;
Lin ke d Lis t< S ta v ka M a p e< K ,V kofa = k o f e [ i n d e k s ] ;
StavkaMape<K,V> par = new StavkaM ape<K,V >(klju c, v r e d n o s t ) ;
boolean pronadjen = f a l s e ;
L is t I t e r a t o r < S t a v k a M a p e < K , V i t = k o f a . l i s t I t e r a t o r ( ) ;
w h ile (it.h a s N e x t()) {
StavkaMape<K,V> iP a r = i t . n e x t ( ) ;
if(iP a r.g e tK e y () .e q u a ls (k lju c )) {
sta ra V re d n o st = i P a r . g e t V a l u e ( ) ;
i t . s e t ( p a r ) ; / / Zameni s t a r o novim
pro nadje n = t r u e ;
bre ak;
)
}
if(Ip ro n a d je n )
k o fe [in d e k s ].a d d (p a r);
r e t u r n s t a ra V re d n o s t;
}
p u b l i c V g e t ( O b je c t k l j u c ) {
i n t indeks = M a t h . a b s (k lju c .h a s h C o d e O ) % VELICINA;
i f ( k o f e [ i n d e k s ] == n u l l ) r e t u r n n u l l ;
for(StavkaMape<K,V> iP a r : k o f e [ i n d e k s ] )
i f(iP a r.g e tK e y (). e q u a ls (k lju c ))
re tu rn iP a r .g e tV a lu e () ;
retu rn n u ll;
}
p u b l i c S e t< M ap .E ntry< K ,V e n t r y S e t ( ) {
S e t< M ap .E ntry < K ,V skup= new HashSet<Map. E n t r y < K , V ( ) ;
fo r(L in k e d L is t< S ta v k a M a p e < K ,V ko fa : k o fe ) {
i f ( k o f a == n u l l ) c o n t in u e ;
for(StavkaMape<K,V> mpar : kofa)
s k u p .ad d (m p a r);
}
r e t u r n skup;
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) {
Jednosta vnaHashMapa<Strin g,String> m =
new J e d n o s ta v n a H a s h M a p a < S trin g ,S trin g > ();
m.putAl 1 ( C o u n t r i e s . g l a v n i j r a d o v i ( 2 5 ) ) ;
S y s te m .o u t.p rin tln (m );
S y s t e m . o u t . p r in t ln ( m . g e t ( " E R I T R E A " ) ) ;
S ys te m .o u t.p rin tln (m .e n try S e t());
}
} / * Is p is :
{CAMEROON=Yaounde, C0NG0=Brazzavi11e, CHAD=N1djamena, COTE D'IVOIR
(IVORV COAST)=Yamoussoukro, CENTRAL AFRICAN REPUBLIC=Bangui,
GUINEA=Conakry, BOTSWANA=Gaberone, BISSAU=Bissau, EGYPT=Cairo,
ANGOLA=Luanda, BURKINA FAS0=0uagadougou, ERITREA=Asmara,
THE GAMBIA=Banjul, KENYA=Nairobi, GAB0N=Librevi11e, CAPE VERDE=Praia,
Poglav[je 17: Detaljno razmatranje kontejnera 677
s Ispostavlja se d a p rim broj zapravo nije idealan kao veliina kofa za heiranje, i novije realizacije hei-
ranja u Javi upotrebljavaju veliinu jednaku nekom step en u b roja dva (a to je rezultat opsenog ispi-
tivanja). Deljenje i o sta ta k o d deljenja su najsporije o p eracijek o jeo b av ljaju savrem eni procesori. Ako
je d u in a ta b e le je d n a k a n e k o m s te p e n u b ro ja d v a , u m e s to d e lje n ja m o e se u p o tr e b iti m a s k ira n je .
P o to je get( ) n ajea o p e ra c ija , d e lje n je (% ) p ro u z ro k u je \ eliki d e o tro k o v a k o je e lim in i e p ris tu p
ste p e n b ro ja d v a" (ali m o e d a u ti e i na n eke h a s h C o d e ( ) m e to d e ).
678 Misliti na Javi
Veba 21: (2) Prepravite program JednostavnaHashMapa tako da prijavljuje broj ,,pro-
ba p otrebnih kada doe do sudara. D rugim reima, koliko p u ta se m o ra pozvati n e x t()
za Iteratore koji prolaze ulananim listam a u potrazi za p o d u d arn im elementima?
Veba 22: (4) Realizujte m etode clea r() i rem ove() za kontejner JednostavnaHashMapa.
Veba 23: (3) Realizujte ostatak interfejsa Map za kontejner JednostavnaHashMapa.
Veba 24: (5) Po uzoru na prim er u program u JednostavnaHashMapa.java, napravite i
testirajte JednostavanHashSkup.
Veba 25: (6) U m esto da za svaku kofu upotrebljavate po jedan Listlterator, prepravite
klasu StavkaMape tako da bude sam ostalna jednostruko ulanana lista (svaka Stavka-
Mape treba da im a vezu unapred ka sledeoj klasi StavkaMape). Prepravite ostatak koda
u program u JednostavnaHashMapa.java tako da novi pristup ispravno funkcionie.
//: k o n t e j n e r i/ K 1 ju e v iZ a T ra n s f o r m is a n je Z n a k o v n ih N iz o v a . ja v a
p u b l i c c la s s K 1 ju e viZ a T ra ns fo rm isan je Z n ak o vn ih N iz o v a {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
S t r i n g [ ] dvazdravo = "Zdravo Z d r a v o " . s p l i t ( " " ) ;
S y s t e m . o u t . p r in t ln ( d v a z d r a v o .h a s h C o d e O ) ;
S y s t e m . o u t . p r i n t l n ( d v a z d r a v o .h a s h C o d e O ) ;
}
} /* Is p is : ( p r im e r)
69609650
69609650
* ///:-
Oigleno je da se hashC od e() za tip String izraunava na osnovu sadraja datog zna-
kovnog niza (objekta tipa String).
Dakle, da bi m etoda hashC od e() bila delotvorna, m ora biti brza i sm isaona, tj. m ora
generisati vrednost na osnovu sadraja objekta. Ne zaboravite da ta vrednost ne m ora biti
jedinstvena bavite se brzinom , a ne jedinstvenou - ali kom binacija m etoda
h ash C od e() i eq u a ls() m ora u potpunosti odrediti identitet objekta.
Poto se hashC od e() dodatno obraduje pre pretvaranja u indeks kofa, opseg vredno-
sti rezultata te m etode nije vaan; dovoljno je da ona generie ceo broj (int).
Ima tu jo neto: dobra m etoda hashC o e() treba da daje ravnom erno raspodeljene
vrenosti. Ako se te vrednosti negde gomilaju, onda e kontejner HashMap ili HashSet
na nekim mestim a biti gue popunjen i nee biti onoliko brz kao to m oe biti uz ravno-
m erno raspodeljene rezultate funkcije za heiranje.
U knjizi Efikasno program iranje na Javi (M ikro knjiga, 2004), Joshua Bloch daje osnov-
ni recept za generisanje pristojne m etode hashC od e():
1. U celobrojnu prom enljivu (tipa int) nazvanu rezultat smestite neki broj razliit od
nule, recimo 17.
2. Za svako znaajno polje f u objektu (tj. svako polje koje m etoda eq u a ls() uzim a u
obzir) izraunajte celobrojni (int) hashC od e() c:
p u b l i c c la s s Pre b ro ja n Z n a ko v n iN iz {
p r i v a t e s t a t i c L i s t < S t r i n g > n a p r a v lje n o =
new A r r a y L i s t < S t r i n g > ( ) ;
p r i v a t e S t r i n g s;
p r i v a t e i n t i d = 0;
p u b l i c P r e b r o ja n Z n a k o v n iN iz ( S t r in g znn) {
s = znn;
n a p ra v lje n o .a d d (s );
/ / i d j e ukupan b r o j i n s t a n c i datog znakovnog
/ / n iz a k o je k o r i s t i P re b ro ja n Z n a k o v n iN iz :
f o r ( S t r i n g s2 : n a p r a v lje n o )
if( s 2 .e q u a ls ( s ))
i d++;
}
p u b lic S trin g to S trin g O {
r e t u r n "Znakovni n i z : " + s + i d : " + id +
11 hashCode(): " + hashCode();
}
p u b l i c i n t hashCode() {
/ / Veoma je d n o sta va n p r i s t u p :
/ / r e t u r n s.hashCode() * i d ;
/ / Upotrebiemo r e c e p t Joshue Blocha:
i n t r e z u l t a t = 17;
r e z u l t a t = 37 * r e z u l t a t + s .h a s hC od e ();
r e z u l t a t = 37 * r e z u l t a t + i d ;
retu rn r e z u lt a t ;
}
p u b l i c boolean e q u a l s ( 0 b j e c t o) {
r e t u r n o in s t a n c e o f P re b ro ja n Z n a k o v n iN iz &&
s . e q u a l s ( ( ( P r e b r o j a n Z n a k o v n i N i z ) o ) . s ) &&
i d == ( ( P r e b r o ja n Z n a k o v n iN iz ) o ) . i d ;
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
M a p < P r e b ro ja n Z n a k o v n iN iz ,In te g e r> mapa =
new H a s h M a p < P r e b ro ja n Z n a k o v n iN iz ,In te g e r > () ;
P r e b r o ja n Z n a k o v n iN iz [ ] pzn = new P re b ro ja n Z n a k o v n iN iz ;
f o r ( i n t i = 0; i < p z n . d u z in a ; i+ + ) {
Poglavlje 17: Detaljno razmatranje kontejnera 681
p u b l i c c la s s Je d in ka implements Comparable<Jedinka> {
p r i v a t e s t a t i c long b r o j a c = 0;
p r i v a t e f i n a l long i d = b ro ja c + + ;
682 Misliti na Javi
p r i v a t e S t r i n g ime;
p u b l i c J e d in k a ( S t r in g ime) { t h i s . i m e = ime; }
/ / 'im e ' i s opciono:
p u b l i c J e d in k a () {}
p u b lic S trin g to S trin g O {
r e t u r n g e tC la ss ().g e tS im p le N a m e () +
(ime == n u l l ? " " : " + im e );
}
p u b l i c long i d ( ) { r e t u r n i d ; }
p u b l i c boolean e q u a ls ( O b je c t o) {
r e t u r n o i n s t a n c e o f J e d in k a &&
i d == ( ( J e d i n k a ) o ) . i d ;
}
p u b l i c i n t hashCode() {
i n t r e z u l t a t = 17;
i f ( i m e != n u l l )
r e z u l t a t = 37 * r e z u l t a t + im e .h a sh C o d e ();
r e z u l t a t = 37 * r e z u l t a t + ( i n t ) i d ;
return re z u lta t;
}
p u b l i c i n t compareTo(Jedinka a rg ) {
/ / Prvo se porede imena k ia s a :
S t r i n g prv o = g e t C la s s ( ) . g e tS im p l e N a m e ( ) ;
S t r i n g a rg P rv i = a r g . g e t C l a s s ( ) .g e tS im pleN am e ();
i n t p rv o P o re d je n je = p rv o . c o m p a r e T o ( a rg P rv i) ;
i f ( p r v o P o r e d j e n j e != 0)
r e t u r n p rv o P o re d je n je ;
i f ( i m e != n u l l && a rg .im e != n u l l ) {
i n t d ru g o P o re d je n je = im e .c o m p a re T o (a r g .im e ) ;
i f ( d r u g o P o r e d j e n j e != 0)
r e t u r n d ru g o P o re d je n je ;
}
r e t u r n ( a r g . i d < i d ? -1 : ( a r g . i d == i d ? 0 : 1 ) ) ;
}
} lll--~
M etoda co m p areT o () im a hijerarhiju poreenja, tako da proizvodi sekvencu ureenu
prvo po stvarnom tipu, zatim po im enu ako ono postoji, i najzad po redosledu pravljenja.
U ovom prim eru videete kako sve to radi:
/ / : k o n t e j n e r i / T e s t i r a n j e J e d i n k i . ja v a
im p o rt h o ld in g .M a p O f L i s t;
im p ort p o d a c i o t i p u . l j u b i m c i
im p o rt j a v a . u t i l
p u b l i c c la s s T e s t i r a n j e J e d i n k i {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) {
Set<Jedinka> I j u b i m c i = new T r e e S e t < J e d i n k a > ( ) ;
f o r ( L i s t < ? extends LJubimac> 11 j :
Poglavlje 17: Deta[jno razmatranje kontejnera 683
M a p O f L is t . l j u b i t e l j i L j u b i m a c a . v r e d n o s t i { ) )
f o r(L J u b im a c l j : l l j )
1ju b im c i .a d d ( l j ) ;
S y s te m .o u t.p rin tln (lju b im c i);
}
} / * Is p is :
[Cat E l s i e May, Cat P in k o la , Cat S h a c k le t o n , Cat S t a n f o rd aka
S t i n k y el Negro, Cymric M o l l y , Dog M a r g r e t t , Mutt Sp ot, Pug Louie
aka L ouis S n o r k e ls t e i n Dupree, Rat F i z z y , Rat F r e c k ly , Rat. Fuzzy
* ///:-
Poto svi ovi ljubim ci im aju im ena, ureuje se prvo po tipu, zatim po im enu i najzad
po im enu u n u ta r njihovog tipa.
N apisati odgovarajue m etode h ash C od e() i eq u als() za novu klasu um e da bude za-
petljano. Alatke koje e vam pri tom e pom oi pronai ete u Apache projektu Jakarta
C om m ons na adresi jakarta.apache.org/com m ons, p o d lan g (ovaj projekat im a i m no-
go drugih potencijalno korisnih biblioteka, pa izgleda da je to odgovor Javine zajednice
na lokaciju u'mv.froosf.org zajednice korisnika C + + -a).
Veba 26: (2) U program PrebrojanZnakovniNiz dodajte char polje koje se takoe inici-
jalizuje u konstruktoru i prepravite m etode h ash C od e() i eq u a ls() tako da obuhvate
vrednost ovog polja.
Veba 27: (3) Prepravite m etodu h ash C od e() u program u PrebrojanZnakovniNiz.java
tako to ete ukloniti kom binaciju sa id, i pokaite da PrebrojanZnakovniNiz i dalje radi
kao klju. Zato ovaj pristup ne valja?
Veba 28: (4) Dodavanjem m etoda h a sh C o d e(), eq u a ls() i realizovanjem interfejsa
Comparable za svaki tip N_torke prepravite net/m indview/util/N_torka.java tako da
postane klasa opte nam ene.
Izbor realizacije
Dosad je trebalo da shvatite sledee: iako postoje sam o etiri osnovna tipa kontejnera
- M ap, List, Set i Q ueue - svaki od tih interfejsa im a vie realizacija. Ako vam treba funk-
cionalnost odreenog interfejsa, kako da izaberete njegovu realizaciju?
Svaka realizacija ima svoja obeleja, prednosti i nedostatke. Na prim er, na slici s poet-
ka ovog poglavlja vidite da je obeleje klasa Hashtable, Vector i Stack to to su nasleene
iz prethodnih verzija Jave (engl. legacy), kako se stari kod ne bi ruio zbog prevoenja no-
vim prevodiocim a (ali ih ne treba koristiti u novim program im a).
Vrste redova za ekanje u (Q ueues) u Javinim bibliotekam a razlikuju se sam o po
nainu prim anja i vraanja vrednosti (vanost toga objasniem o u poglavlju Paralclno
izvravanje).
Razlika izmeu kontejnera esto se svodi na to kakvi su ,,u pozadini- tj. koje strukture
podataka fiziki realizuju eljeni interfejs. Na prim er, poto ArrayList i LinkedList reali-
zuju interfejs List, elem entarne List operacije su iste bez obzira na to koju od njih upo-
trebite. M eutim , u pozadini A rrayListe je niz, dok je LinkedList realizovana na nain
uobiajen za dvostruko ulananu listu, kao grupa pojedinanih objekata koji sadre
684 Misliti na Javi
podatke i reference na prethodni i sledei elem ent u listi. Upravo zato, ako nam eravate da
m nogo um eete i uklanjate elem ente usred liste, koristite LinkedList. (LinkedList im a i
dodatn u funkcionalnost, utvrenu u listi AbstractSequentialList.) Ali ako vam to nije
potrebno, uzm ite listu ArrayList koja je obino bra.
Kao drugi prim er, Set se moe realizovati kao TreeSet, HashSet ili LinkedHashSet.9
Ponaanje svakog od tih skupova je drugaije: HashSet je podesan za tipinu u p o treb u i
najbre obavlja pretraivanje, LinkedHashSet uva parove u poretku um etanja, a u po-
zadini skupa TreeSet nalazi se m apa TreeMap koja uvek daje ureen skup. Realizaciju bi-
rate u skladu s ponaanjem koje vam je potrebno.
Ponekad razliite realizacije odredenogkontejnera im aju neke zajednike operacije, ali
su perform anse tih operacija razliite. U tom sluaju, realizaciju birate na osnovu toga
koliko esto koristite odreenu operaciju i koliko brza ona m ora da bude. U takvim slua-
jevim a se o razlikama izm eu realizacija kontejnera m oe zakljuivati i kroz ispitivanje
perform ansi.
/ / : k o n te jn e ri/T e s t.ja v a
/ / S t r u k t u r a za vremensko i s p i t i v a n j e k o n t e jn e r a .
p u b l i c a b s t r a c t cla ss Test<C> {
S t r i n g ime;
p u b l i c T e s t ( S t r i n g ime) { t h i s . i m e = ime; }
/ / R e d e f i n i i t e ovu metodu za svaku v r s t u i s p i t i v a n j a .
/ / Vraa s t v a r n i b r o j p o n a v l ja n ja i s p i t i v a n j a .
a b s t r a c t i n t i s p i t ( C k o n t e j n e r , Pa ra m ls p it a p i ) ;
} III--
Svaki objekat tipa Test skladiti ime tog testa (ispitivanja). Kada pozovete m etodu
ispit( ), m orate joj dati kontejner koji treba ispitati i ,,prenosioca ili objekat za prenos
podataka koji sadri sve param etre tog ispitivanja. To su param etri velicina, jednak bro-
ju elem enata u kontejneru, i petlje, koji odreuje broj iteracija za to ispitivanje. Ti para-
m etri se m ogu koristiti u svakom ispitivanju ali i ne m oraju.
Svaki kontejner e biti podvrgnut nizu poziva m etode is p it(), svaki p u t s razliitim
param etrim a ispitivanja (objektom tipa Paramlspita), pa Paramlspita sadri i dve sta-
tine m etode n iz ( ) za lako pravljenje nizova Paramlspita objekata. Prva verzija m etode
n iz ( ) p rim a listu prom enljivih argum enata koja naizm enino sadri vrednosti velicina i
petlji, a druga verzija prim a listu iste vrste, sem to su vrednosti sm etene u znakovne ni-
zove (objekte tipa String) - pa se moe upotrebljavati za ralanjivanje argum enata na
kom andnoj liniji:
p u b l i c c la s s Pa ra m ls p it a (
p u b lic fin a l i n t v e lic in a ;
p u b lic f in a l i n t p e t lje ;
p u b lic P a ra m ls p ita (in t v e lic in a , in t p e tlje ) {
th is .v e lic in a = v e lic in a ;
th is . p e t lje = p e tlje ;
}
/ / P r a v l j e n j e n iz a o b je k a ta t i p a Pa ra m ls p it a od sekvence p r o m e n l j i v i h
/ / argumenata:
p u b l i c s t a t i c P a r a m ls p it a [ ] n i z ( i n t . . . v r e d n o s t i ) {
in t v e lic in a = v re d n o s ti.le n g th /2 ;
P a r a m ls p it a [ ] r e z u l t a t = new P a r a m l s p i t a [ v e l i c i n a ] ;
i n t n = 0;
f o r ( i n t i = 0; i < v e l i c i n a ; i+ +)
r e z u l t a t [ i ] = new P a r a m I s p i t a ( v r e d n o s t i [ n + + ] , v r e d n o s t i [ n + + ] ) ;
retu rn r e z u lta t;
}
/ / P r e t v o r i n iz o b je k a ta t i p a S t r i n g u n i z o b je k a ta t i p a P a r a m ls p it a :
p u b l i c s t a t i c P a r a m ls p it a [ ] n i z ( S t r i n g [ ] v r e d n o s t i ) {
i n t [ ] v r d n s t i = new i n t [ v r e d n o s t i . l e n g t h ] ;
f o r f i n t i = 0; i < v r d n s t i . 1 e n g th ; i++)
v r d n s t i[ i] = In te g e r.d e c o d e (v re d n o s ti[i]);
retu rn n iz ( v r d n s t i) ;
}
} ///:-
vanja, a za jedno ispitivanje param etre listaP aram m oete da prom enite prosleivanjem
liste listaP aram prilagoene za to ispitivanje:
/ / : k o n te jn e ri/T e s te r.ja v a
/ / P r im e n ju je Test o b je k t e na l i s t e r a z l i i t i h k o n t e jn e r a .
im p o r t j a v a . u t i l
p u b l i c c la s s Tester<C> {
p u b l i c s t a t i c i n t s i r i n a P o l j a = 8;
p u b l i c s t a t i c P a r a m ls p it a G podrazumevaniParam= P a r a m l s p i t a . n i z (
10, 5000, 100, 5000, 1000, 5000, 10000, 50 0 );
/ / R e d e f i n i i t e ovo da b i s t e m o d i f i k o v a l i i n i c i j a l i z a c i j u
/ / pre i s p i t i v a n j a :
protected C i n i c i j a l i z u j ( i n t v e lic in a ) { re tu rn ko n tejne r; }
protected C ko n tejne r;
p r i v a t e S t r i n g n a s lo v =
p riv a te L ist< T e st< C is p it iv a n ja ;
p riv a te s t a t i c S trin g p o lje S tr in g () {
r e t u r n "%" + s i r i n a P o l j a + " s " ;
}
p riv a te s t a t ic S trin g p o lje B ro jO {
r e t u r n "%" + s i r i n a P o l j a + " d " ;
}
p r i v a t e s t a t i c i n t s i r i n a V e l i c i n e = 5;
p r i v a t e s t a t i c S t r i n g p o l j e V e l i c i n e = "%" + s i r i n a V e l i c in e + " s " ;
p r i v a t e P a r a m ls p it a [ ] lis t a P a r a m = podrazumevaniParam;
p u b l i c T e ste r(C k o n t e j n e r , L i s t < T e s t < C i s p i t i v a n j a ) {
t h is . k o n t e jn e r = k o ntejner;
t h i s . is p itiv a n ja = is p itiv a n ja ;
i f ( k o n t e j n e r != n u l 1)
n a slo v = k o n t e j n e r . g e t C l a s s ( ) .getSim ple N am e();
}
p u b l i c T e s te r(C k o n t e j n e r , L i s t < T e s t < C i s p i t i v a n j a ,
P a r a m ls p it a [ ] lis t a P a r a m ) {
th is (k o n te jn e r, is p itiv a n ja ) ;
t h i s . 1istaParam = lis t a P a r a m ;
}
p u b l i c v o id z a d a jN a s lo v ( S t r in g novNaslov) {
n a slo v = novNaslov;
}
/ / Pomone g e n e r i k e metode :
p u b l i c s t a t i c <C> v o id pokre ni (C k n t n r , L i s t < T e s t < C i s p i t i va nja ) {
new T e s t e r < C > ( k n t n r , i s p i t i v a n j a ) . v r e m e n s k o ls p it ( ) ;
}
p u b l i c s t a t i c <C> vo id p o kre n i( C k n t n r ,
L i s t < T e s t < C i s p i t i v a n j a , P a r a m ls p it a [ ] lis ta P a r a m ) {
new T e s t e r < C > ( k n t n r, i s p i t i v a n j a , 1is t a P a r a m ) . v r e m e n s k o ls p it ( ) ;
}
Poglavlje 17: Detaljno razmatranje kontejnera 687
p r i v a t e v o id p r i k a z i Z a g l a v l j e ( ) {
/ / I z r a u n a j i r i n u i dopuni znacima
in t s ir in a = s irin a P o lja * is p it iv a n ja . s iz e ( ) + s irin a V e lic in e ;
i n t d u z in a C r t ic a = s i r i n a - n a s l o v . l e n g t h ( ) - 1;
S t r i n g B u i l d e r z g l a v l j e = new S t r i n g B u i l d e r ( s i r i n a ) ;
f o r ( i n t i = 0 ; i < d u z i n a C r t i c a / 2 ; i+ + )
z g la v lje .a p p e n d ( '- ');
z g la vlje .a p pe n d O ' ) ;
z g la v lje .a p p e n d (n a s lo v );
z g la v lje .a p p e n d (' ' ) ;
f o r ( i n t i = 0; i < d u z i n a C r t i c a / 2 ; i+ + )
z g la v lje .a p p e n d ( '- ');
S y s te m .o u t.p rin tln (z g la v l j e ) ;
/ / I s p i s i v a n j e z a g l a v l j a ko lo n a :
S ys te m .o u t.fo rm a t(p o lje V e lic in e , " v e l . " ) ;
fo r(T e s t i s p i t : is p itiv a n ja )
S ys te m .o u t.fo rm a t(p o lje S trin g (), is p it . im e ) ;
S y s te m .o u t.p rin tln ();
}
/ / Pokreni i s p i t i v a n j a za ovaj k o n t e j n e r :
p u b l i c v o id v r e m e n s k o I s p i t( ) {
p rik a z iZ a g la v lje O ;
f o r ( P a r a m I s p i t a param : li s t a P a r a m ) {
S y s t e m . o u t . f o r m a t ( p o l j e V e l i ci ne, p a ra m . v e li c i n a ) ;
f o r(T e s t< C > i s p i t : i s p i t i v a n j a ) {
C kkontejner = i n i c i j a l i z u j(p a ra m .v e li c in a ) ;
lo ng s t a r t = System.nanoTime();
/ / Poziv r e d e f i n i s a n e metode:
i n t p o n a v l ja n ja = i s p i t . i s p i t ( k k o n t e j n e r , param);
long t r a j a n j e = System.nanoTime() - s t a r t ;
lo ng vremeZaJednoPonavljanje = t r a j a n j e / p o n a v l ja n ja ;
/ / Nanosekunde
S y s t e m . o u t . f o r m a t ( p o l j e B r o j ( ) , vrem eZaJednoPonavlja nje );
}
S y s te m .o u t.p rin tln ();
}
}
} ///:-
M etode p oljeString() i p oljeB roj() proizvode znakovne nizove za form atiranje rezul-
tata prilikom ispisa. Standardnu irinu za form atiranje m enjate m odifikovanjem statine
vrednosti sirinaPolja. Metoda prikaziZaglavlje() form atira i ispisuje zaglavlje s podaci-
ma iz svakog ispitivanja.
Ako vam je potrebna specijalna inicijalizacija, redefiniite m etodu in icijalizu j(). O na
proizvodi inicijalizovan objekat kontejner odgovarajue veliine - moete modifikovati
postojei objekat kontejner ili napraviti novi. U m etodi isp it() vidite da se rezultat hvata
u lokalnoj referenci nazvanoj kontejner, to om oguuje da uskladiteni lan kontejner
zam enite p otp u n o drugaije inicijalizovanim kontejnerom .
688 Misliti na Javi
Povratna vrednost svake m etode T est.ispit() m ora biti broj operacija obavljenih to-
kom tog ispitivanja, to se koristi za izraunavanje broja nanosekundi potrebnih za svaku
operaciju. Imajte u vidu da m etoda S ystem .nanoT im e() obino daje vrednosti ija gra-
nularnost prem auje jedan (i m enja se u zavisnosti od raunara i operativnog sistema), a
to e prouzrokovati odreenu koliinu um a u rezultatim a.
Rezultati se m ogu m enjati u zavisnosti od raunara na kojem se ispitivanja obavljaju;
ova ispitivanja su nam enjena sam o za relativno poreenje perform ansi razliitih kontej-
nera, a ne za apsolutno m erenje tih perform ansi.
p u b l i c c la s s P e rfo rm a n seL is ta {
s t a t i c Random s lu c a ja n = new Random();
s t a t i c i n t p o n a v l ja n ja = 1000;
s t a t ic L is t< T e s t< L is t< In te g e r > i s p it iv a n ja =
new A r r a y L is t < T e s t < L i s t < I n t e g e r > ( ) ;
s t a t i c L i s t < T e s t < L i n k e d L i s t < I n t e g e r > is p it iv a n ja R e d a Z a C e k a n je =
new A r r a y L i s t < T e s t < L i n k e d L i s t < I n t e g e r > ( ) ;
s ta tic {
is p itiv a n ja .a d d (n e w T e s t< L is t< In te g e r ( " a d d " ) {
i n t i s p i t ( L i s t < I n t e g e r > l i s t a , P a r a m ls p ita p i ) {
in t p e tlje = p i . p e tlje ;
i n t v e lic in a L iste = p i . v e l i c i n a ;
f o r ( i n t i = 0 ; i < p e t l j e ; i+ + ) {
1i s t a . c l e a r ( ) ;
f o r ( i n t j = 0; j < v e l i c i n a L i s t e ; j+ + )
lis ta .a d d (j);
}
return p e t lje * v e lic in a L is te ;
}
});
is p i t i v a n j a . a d d ( n e w T e s t < L i s t < I n t e g e r ( " g e t " ) {
i n t i s p i t ( L i s t < I n t e g e r > l i s t a , P a r a m ls p ita p i ) {
i n t p e t lje = p i . p e t l j e * p o n a v lja n ja ;
in t v e lic in a L is te = l is t a . s iz e ( ) ;
f o r ( i n t i = 0; i < p e t l j e ; i++)
Poglavlje 17: Detafjno razmatranje kontejnera 689
1i s t a . g e t ( s l u c a j a n . n e x t I n t ( v e l i c i naLi s t e ) ) ;
return p e t lje ;
}
});
is p itiv a n ja .a d d (n e w T e s t< L is t< In te g e r ( " s e t" ) {
i n t i s p i t ( L i s t < I n t e g e r > l i s t a , P a ra m ls p ita p i ) {
i n t p e t l j e = p i . p e t l j e * p o n a v lja n ja ;
in t v e lic in a L is te = lis t a . s iz e ( ) ;
f o r ( i n t i = 0; i < p e t l j e ; i+ + )
1i s t a . s e t ( s l u c a j a n . n e x t l n t ( v e l i c i n a L i s t e ) , 4 7 );
retu rn p e t lje ;
}
});
is p itiv a n ja .a d d (n e w T e s t< L is t< In te g e r ( " ite ra d d " ) {
i n t i s p i t ( L i s t < I n t e g e r > l i s t a , P a r a m ls p it a p i ) {
f i n a l i n t PETLJE = 1000000;
i n t p o lo v in a = l i s t a . s i z e ( ) / 2;
L is tIte ra to r< In te g e r> i t = lis t a . lis t lt e r a t o r ( p o lo v in a ) ;
f o r ( i n t i = 0; i < PETLJE; i+ + )
it.a d d (4 7 );
r e t u r n PETLJE;
}
});
is p itiv a n ja .a d d (n e w T e s t< L is t < I n t e g e r ( " in s e r t " ) {
i n t i s p i t ( L i s t < I n t e g e r > l i s t a , P a r a m ls p ita p i ) {
in t p e tlje = p i.p e tlje ;
f o r ( i n t i = 0; i < p e t l j e ; i++)
l i s t a . a d d ( 5 , 4 7 ) ; / / M in im iz o v a n je t r o k o v a
/ / nasuminog p r i s t u p a n j a
return p e t lje ;
}
});
i s p itiva n ja .ad d (n ew T e s t< L is t< In te g e r ("re m o v e ") {
i n t i s p i t ( L i s t < I n t e g e r > l i s t a , P a ra m ls p ita p i ) {
in t p e t lje = p i.p e tlje -,
in t v e lic in a = p i.v e lic in a ;
f o r ( i n t i = 0; i < p e t l j e ; i+ + ) {
1i s t a . c l e a r ( ) ;
1i s t a . a d d A l 1 (new B r o j a c k a L i s t a l n t e g e r a ( v e l i c i n a ) ) ;
whi 1e ( l i s t a . s i z e O > 5)
1i s t a . r e m o v e ( 5 ) ; / / M in im iz o v a n je tr o k o v a
/ / nasuminog p r i s t u p a n j a
}
retu rn p e t lje * v e lic in a ;
}
});
/ / I s p i t i v a n j a ponaanja reda za e ka n je :
is p it iv a n ja R e d a Z a C e k a n je .a d d (n e w T e s t < L in k e d L i s t<
In te g e r ("a d d F irs t") {
690 Misliti na Javi
}
return p e t lje * v e lic in a ;
}
});
}
s t a t i c c la s s I s p i t i v a c L i s t a extends T e s t e r < L i s t < I n t e g e r {
p u b lic Is p itiv a c L is ta ( L is t< In te g e r > k o n tejne r,
L is t< T e s t< L is t< In te g e r> is p itiv a n ja ) {
s u p e r ( k o n t e jn e r , i s p i t i v a n j a ) ;
}
/ / Pre svakog i s p i t i v a n j a popuni do o d g ova ra ju e v e l i i n e :
@0verride p r o t e c t e d L i s t < I n t e g e r > i n i c i j a l i z u j ( i n t v e l i c i n a ) {
k o n te jn e r.c le a r();
k o n t e j n e r . a d d A ll( n e w B r o j a c k a L i s t a I n t e g e r a ( v e l i c i n a ) ) ;
return kontejner;
}
/ / Pomona metoda:
p u b l i c s t a t i c v o id p o k r e n i ( L i s t < I n t e g e r > l i s t a ,
L is t< T e s t< L is t< In te g e r > is p it iv a n ja ) {
new I s p i t i v a c L i s t i ( 1 i s t a , i s p i t i v a n j a ) . v r e m e n s k o I s p i t ( ) ;
}
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
i f ( a r g s . 1 ength > 0)
Tester.podrazumevaniParam = P a r a m l s p i t a . n i z ( a r g s ) ;
/ / Na n iz se mogu p r i m e n i t i samo sle dea dva i s p i t i v a n j a :
T e s te r< L is t< In te g e r is p itN iz a =
new T e s t e r < L i s t < I n t e g e r ( n u l l , i s p i t i v a n j a . p o d L i s t a ( l , 3 ) ) {
/ / Ovo e b i t i pozvano pre svakog i s p i t i v a n j a .
/ / P r o iz v o d i l i s t u n e p ro m e n ljiv e v e l i i n e s nizom u p o z a d i n i :
@0verride p r o t e c t e d
L is t < I n t e g e r > i n i c i j a l i z u j ( i n t v e l i c i n a ) {
In te g e r[] ia = G e n e ra te d .n iz (In te g e r.c la s s ,
new C o u n t ingG enerator. I n t e g e r O , s i z e ) ;
return A r r a y s . a s L is t ( ia ) ;
}
};
is p i t N i z a . z a d a j N a s l o v ( " N i z kao l i s t a " ) ;
is p itN iz a .v re m e n s k o Is p it();
Tester.podrazu meva ni Param= Pa ra m ls p it a . n i z (
10, 5000, 100, 5000, 1000, 1000, 10000, 20 0 );
i f ( a r g s . l e n g t h > 0)
Tester.podrazumevaniParam = P a r a m l s p i t a . n i z ( a r g s ) ;
Is p itiv a c L is ta .p o k re n i(n e w A rra y L is t< In te g e r> (), i s p i t i v a n j a ) ;
I s p i t i v a c L i s t a . p o k r e n i (new L i n k e d L i s t < I n t e g e r > ( ) , i s p i t i v a n j a ) ;
I s p i t i v a c L i s t a . p o k r e n i (new V e c t o r < I n t e g e r > ( ) , i s p i t i v a n j a ) ;
T e s t e r . s i r i n a P o l j a = 12;
T e s t e r < L i n k e d L i s t < I n t e g e r is p it iv a n je R e d a Z a C e k a n je =
692 Misliti na Javi
/ / : k o n t e j n e r i / G r a n i ceOdRandom.java
/ / Daje l i metoda Math.random() b ro je v e 0 . 0 i 1.0?
/ / {RunByHand}
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s GraniceOdRandom {
s t a t i c v o id u p o tr e b a ( ) {
p rin t("U p o tre b a :");
p rin t ( " \ tG r a n ic e 0 d R a n d o m d o n j a " ) ;
p rin t ( " \ tG r a n ic e 0 d R a n d o m g o r n j a " ) ;
S y s te m .e x it(l);
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
i f ( a r g s . l e n g t h != 1) u p o t r e b a ( ) ;
if(a rg s .e q u a ls ("d o n ja ")) {
w h i1e(Math .random() != 0 .0 )
; / / Pokuavaj i d a l j e
p rin t("D a la 0 .0 !" ) ;
}
e ls e i f ( a r g s . e q u a l s ( " g o r n j a " ) ) {
w h i1e (M a th . random() != 1.0)
; / / Pokuavaj i d a l j e
p rin t("D a la 1 .0 !" ) ;
}
el se
u p o tr e b a O ;
}
) III--
Program pokreete upisivanjem jedne od sledeih instrukcija na kom andnu liniju:
ja v a GraniceOdRandom donja
ili
ja v a G r a n iceOdRandom g o rn ja
696 Misliti na Javi
/ / : k o n te jn e r i/P e r fo rm a n s e S k u p o v a .ja v a
/ / Pokazuje r a z l i i t e performanse Skupova.
/ / { A rg s : 100 5000} Malo, da b i t e s t i r a n j e b u i l d a b i l o k r a t k o
im p o r t j a v a . u t i l . * ;
p u b l i c c la s s PerformanseSkupova {
s t a t i c L is t < T e s t < S e t < I n t e g e r > i s p i t i v a n j a =
new A r r a y L i s t < T e s t < S e t < I n t e g e r > ( ) ;
s ta tic {
is p itiv a n ja .a d d (n e w T e s t< S e t< In te g e r ("a d d ") {
i n t i s p i t ( S e t < I n t e g e r > skup, P a r a m ls p ita p i ) {
in t p e tlje = p i.p e tlje ;
in t v e lic in a = p i. v e lic in a ;
f o r ( i n t i = 0; i < p e t l j e ; i+ + ) {
s k u p .c le a r();
f o r ( i n t j = 0; j < v e l i c i n a ; j+ + )
s k u p .a d d (j);
}
retu rn p e t lje * v e lic in a ;
}
});
is p itiv a n ja .a d d (n e w T e s t< S e t< In te g e r ("c o n ta in s ") {
i n t i s p i t ( S e t < I n t e g e r > skup, P a r a m ls p ita p i ) {
i n t p e t l j e = pi . p e t l j e ;
i n t opseg = p i . v e l i c i n a * 2;
f o r ( i n t i = 0; i < p e t l j e ; i+ + )
f o r ( i n t j = 0; j < opseg; j+ + )
s k u p .c o n ta in s (j);
r e t u r n p e t l j e * opseg;
}
});
is p itiv a n ja .a d d (n e w T e s t< S e t < I n t e g e r ( " it e r a t e " ) {
i n t i s p i t ( S e t < I n t e g e r > skup, P a r a m ls p it a p i ) {
i n t p e t l j e = p i . p e t l j e * 10;
f o r ( i n t i = 0; i < p e t l j e ; i+ + ) {
Poglavlje 17: Detaljno razmatranje kontejnera 697
Perform anse skupa HashSet po pravilu su bolje od onih skupa TreeSet, naroito pri
dodavanju elem enata i traganju za njim a (m etodom co n ta in s()), to su dve najvanije
operacije. TreeSet postoji zato to svoje elem ente odrava u ureenom poretku, pa ga
upotrebljavam o sam o onda kada nam treba ureen Set. Zbog unutranje stru k tu re pot-
rebne za ureivanje i zato to se iteriranje ee izvodi, ono je obino bre u kontejneru
tipa TreeSet nego tipa HashSet.
O bratite paniu na to da su um etanja u skupu LinkedHashSet dugotrajnija nego u
skupu HashSet; to vai zato to odravanje ulanane Iiste prouzrokuje doatne trokove,
jer se dodaje onim a za kontejner s transform isanjem kljua.
Veba 34: ( 1) Izm enite PerformanseSkupova.java tako da objekti tipa Set skladite zna-
kovne nizove (String), a ne Integere. Za pravljenje ispitnih vrednosti upotrebite Genera-
to r i/ poglavlja I\ri:o \i.
698 Misliti na Javi
/ / : ko n te jn e r i/P e r fo rm a n s e M a p a .ja v a
/ / Pokazuje r a z l i i t e performanse r a z n ih Mapa.
/ / { A r g s : 100 5000} Malo, da bi t e s t i r a n j e b u i l d a b i l o k r a t k o
im p o rt j a v a . u t i l
p u b l i c c la s s PerformanseMapa {
s t a t i c L is t < T e s t < M a p < I n t e g e r , I n t e g e r > i s p i t i v a n j a =
new A r r a y L i s t < T e s t < M a p < I n t e g e r , I n t e g e r > ( ) ;
s ta tic {
is p i t i v a n j a . a d d ( n e w T e s t < M a p < I n t e g e r , I n t e g e r ( " p u t " ) {
i n t i s p i t ( M a p < I n t e g e r , I n t e g e r > mapa, P a ra m ls p it a p i ) {
in t p e tlje = p i.p e tlje ;
in t v e lic in a = p i. v e lic in a ;
f o r ( i n t i = 0; i < p e t l j e ; i+ + ) {
m a p a .c le a r();
f o r ( i n t j = 0; j < v e l i c i n a ; j+ + )
m a p a . p u t ( j, j ) ;
}
retu rn p e t lje * v e lic in a ;
}
});
is p i t i v a n j a . a d d ( n e w T e s t < M a p < I n t e g e r , I n t e g e r ( " g e t " ) {
i n t i s p i t ( M a p < I n t e g e r , I n t e g e r > mapa, P a r a m ls p ita p i ) {
in t p e tlje = p i . p e tlje ;
i n t opseg = p i . v e l i c i n a * 2;
f o r ( i n t i = 0; i < p e t l j e ; i+ + )
f o r ( i n t j = 0; j < opseg; j+ + )
m a p a .g e t(j);
r e t u r n p e t l j e * opseg;
}
f);
i s p i t i v a n j a . a d d ( n e w Test<Map<Integer, I n t e g e r ( " i t e r a t e " ) {
i n t i s p i t (M a p < I n t e g e r ,I n t e g e r> mapa, Pa ra m ls p it a p i ) {
i n t p e t l j e = p i . p e t l j e * 10;
f o r ( i n t i = 0; i < p e t l j e ; i ++) {
I t e r a t o r i t = mapa. e n t r y S e t ( ) . i t e r a t o r ( ) ;
w h i1e ( i t . hasNext( ) )
it.n e x t();
)
r e t u r n p e t l j e * m a p a . s iz e ( ) ;
}
});
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
i f ( a r g s . l e n g t h > 0)
Poglavfje 17: Detaljno razmatranje kontejnera 699
Tester.podrazumevaniParam = P a r a m l s p i t a . n i z ( a r g s ) ;
T e s t e r . p o k r e n i(n e w T r e e M a p < I n t e g e r , I n t e g e r > ( ) , i s p i t i v a n j a ) ;
T e s t e r . p o k r e n i(n e w H a s h M a p < I n t e g e r , I n t e g e r > ( ) , i s p i t i v a n j a ) ;
T e s t e r . p o k r e n i(n e w L in k e d H a s h M a p < I n t e g e r , I n t e g e r > ( ) . i s p i t i v a n j a ) ;
T e s te r.p o k re n i(
new I d e n t i t y H a s h M a p < I n t e g e r , I n t e g e r > ( ) , i s p i t i v a n j a ) ;
T e s t e r . p o k r e n i(n e w W eakH a sh M a p < In te g e r,In te g e r> (), i s p i t i v a n j a ) ;
T e s t e r . p o k r e n i( n e w H a s h t a b l e < I n t e g e r , I n t e g e r > ( ) , i s p i t i v a n j a ) ;
}
} /* Is p is : (p r im e r)
v e l. put get i t e r a t e
10 748 168 100
100 506 264 76
1000 771 450 78
10000 2962 561 83
-------- HashMap
v e l. put get i t e r a t e
10 281 76 93
100 179 70 73
1000 267 102 72
10000 1305 265 97
-- LinkedHashMap
v e l. put get i t e r a t e
10 354 100 72
100 273 89 50
1000 385 222 56
10000 2787 341 56
IdentityHashMap ----------
v e l. put get i t e r a t e
10 290 144 101
100 204 287 132
1000 508 336 77
10000 767 266 56
WeakHashMap -
vel . put get i t e r a t e
10 484 146 151
100 292 126 117
1000 411 136 152
10000 2165 138 555
----- Hashtable - -
v e l. put get i t e r a t e
10 264 113 113
100 181 105 76
1000 260 201 80
10000 1245 134 77
*///:-
700 Misliti na Javi
Uslune metode
Za kontcjnere postoji vie sam ostalnih uslunih m etoda, napisanih u obliku statinih me-
toda klase java.util.Collections. Ve ste u po /n ali neke od njih, kao to su ad d A ll(),
reverscO rder() i binarySearch(). I sledeoj tabeli navodim o ostale (sinhronizovane i
neprom enljive uslune m etode bie opisane u narednim odeljcima). U tabeli su generiki
tipovi upotrebljeni sam o tam o gde su relevantni:
//: kontejneri/UsluzneMetode.java
// Jednostavni primeri usiunih metoda klase Collections.
import ja v a . u t i 1 .*;
import static net.mindview.uti 1 .P r i n t .* ;
p u b l i c c la s s L is t S o r t S e a r c h {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) {
L is t< S trin g > l i s t a =
new A r r a y L i s t < S t r i n g > ( U t i 1i t i e s . 1 i s t a ) ;
1i s t a . a d d A l 1 ( U t i 1i t i e s . 1i s t a ) ;
p rin t(lis ta );
C o l l e c t i o n s . s h u f f l e ( l i s t a , new Random(47));
p rin t("Is p re tu ra n a : " + lis t a ) ;
/ / U k la n ja n je p o s l e d n j i h elemenata pomou L i s t l t e r a t o r a :
L i s t I t e r a t o r < S t r i n g > i t = 1i s t a . 1i s t l t e r a t o r ( l O ) ;
w h i l e ( i t . hasN ext( ) ) {
it.n e x t();
it.re m o v e ();
}
p rint("S kraena: " + l i s t a ) ;
C o lle c tio n s .s o rt(1i s t a ) ;
print("U re e n a : " + l i s t a ) ;
S trin g k lju c = 1i s t a . g e t (7 );
i n t indeks = C o l1e c t i o n s . b i n a r y S e a r c h ( l i s t a , k l j u c ) ;
p r i n t ( " M e s t o k l j u a " + k l j u c + " j e " + indeks +
" , l i s t a . g e t ( " + indeks + " ) = " + 1 i s t a . g e t ( i n d e k s ) ) ;
C o l l e c t i o n s . s o r t ( l i s t a , String.CASE_INSENSITIVE_ORDER);
p r i n t ( " U r e e n a bez o b z ir a na v e l i k a i mala s lo v a : " + l i s t a ) ;
k l j u c = 1i s t a . g e t ( 7) ;
indeks = C o l l e c t i o n s . b i n a r y S e a r c h ( l i s t a , k l j u c ,
String.CASE INSENSITIVE ORDER);
706 Misliti na Javi
Kao pri pretraivanju i ureivanju nizova, i ovde vai sledee: ukoliko listu uredite po-
m ou nekog kom paratora, pom ou istog kom paratora m orate obaviti i b inarno pretrai-
vanje - m etodom b in a ry S ea rc h ().
U ovom program u prikazana je i m etoda sh u ffle() klase C ollections koja nasum ino
m enja redosled elemenata liste. Jedan L istlterator je napravljen na odreenom mestu ispre-
turane (engl. shuffle) liste i upotrebljen za uklanjanje elemenata od tog mesta do kraja liste.
Veba 40: (5) Napravite klasu s dva objekta tipa S tring i realizujte u njoj interfejs Com -
p arab le tako da poreenje uzima u obzir sam o prvi objekat tipa String. Popunite jedan
niz i jedan objekat tipa A rrayList objektim a vae klase, koristei generator RandoinG e-
nerator. Pokaite da se sortiranje obavlja ispravno. Potom napravite C o m p arato r koji
uzim a u obzir samo drugi objekat tipa S trin g i pokaite da je sortiranje opet ispravno.
Obavite i binarno pretraivanje pom ou svoje realizacije interfejsa C om parator.
V eba41: (3) Izmenite klasu iz prethodne vebe tako da radi s kontejnerim a tipa H ashSet
i kao klju u kontejnerim a tipa H ashM ap.
V eba42: (2) Izmenite vebu 40 tako da lista bude sortirana abecedno.
/ / : k o n t e j n e r i /S a m o Za C it a n je .ja v a
/ / Pomou metoda C o l1e c t i o n s . u n m o d i f i a b l e.
im p o rt j a v a . u t i l . * ;
im p o rt n e t . m i n d v i e w . u t i l . * ;
Poglavlje 17: Detafjno razmatranje kontejnera 707
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s SamoZaCitanje {
s t a t i c C o l l e c t i o n < S t r i n g > podaci =
new A r r a y L i s t < S t r i n g > { C o u n t r i e s . i m e n a ( 6 ) ) ;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
C o lle c tio n < S trin g > c =
C o lle c tio n s .u n m o d ifia b le C o lle c tio n (
new A r r a y L i s t < S t r i n g > ( p o d a c i ) ) ;
p r i n t ( c ) ; / / ita n je fu n k c io n i e
/ / ! c . a d d ( " j e d a n " ) ; / / Nema menjanja
S e t < S t r in g > s = C o l l e c t i o n s . u n m o d i f i a b l e S e t (
new H a s h S e t < S t r in g > ( p o d a c i) ) ;
p r i n t ( s ) ; / / i t a n j e f u n k c io n i e
/ / ! s . a d d ( " j e d a n " ) ; / / Nema menjanja
/ / Za S o rte dS e t:
S e t < S t r in g > ss = C o l l e c t i o n s . u n m o d i f i a b l e S o r t e d S e t (
new T re e S e t < S t r in g > ( p o d a c i) ) ;
/ / Za SortedMap:
M a p < S t r in g , S t r in g > sm =
C o l1e c t i ons.unmodi f ia b le S o r te d M a p (
new T r e e M a p < S t r in g . S t r in g > ( C o u n t r ie s . g l a v n i _ g r a d o v i ( 6 ) ) ) ;
}
} / * Is p is :
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI]
ALGERIA
[BURKINA FASO, BURUNDI, BOTSWANA, BENIN, ANGOLA, ALGERIA]
{BURKINA FASO=Ouagadougou, BURUNDI=Bujumbura, BOTSWANA=Gaberone,
BENIN=Porto-Novo, ANGOLA=Luanda, ALGERIA=Algiers}
* ///:-
Poziv neprom enljivc m etode za odreeni tip ne prouzrokuje proveru u vreme pre-
vodenja, ali nakon to se ta transform acija obavi, poziv bilo koje m etode koja menja
sadraj tog kontejnera prouzrokuje U n su pp orted O peratio n E x cep tio n .
708 Misliti na Javi
p u b l i c c la s s S i n h r o n i z a c i j a {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) {
C o lle c tio n < S trin g > c =
C o l1e c t i o n s. s ynchro ni zedCol 1e c t i o n (
new A r r a y L i s t < S t r i n g > ( ) ) ;
L i s t < S t r i n g > l i s t a = C o l1e c t i o n s . s y n c h r o n i z e d L i s t (
new A r r a y L i s t < S t r i n g > ( ) ) ;
S e t < S t r in g > s = C o l1e c t i o n s . s y n c h r o n iz e d S e t (
new H a s h S e t < S t r in g > ( ) ) ;
S e t < S t r in g > ss = C o l1e c t i o n s . s y n c h ro n iz e d S o r te d S e t(
new T r e e S e t < S t r i n g > ( ) ) ;
M a p < S t r in g , S t r in g > m = C o l1e ctio n s .s y n c h r o n iz e d M a p (
new H a s h M a p < S t r in g , S t r in g > ( ) ) ;
M a p < S t r in g , S t r in g > sm =
C o l1e c t io n s . s y n c h r o n i zedSortedMap(
new T r e e M a p < S t r in g , S t r i n g > ( ) ) ;
}
} ///:-
Brzo otkazivanje
Javini kontejneri imaju i m ehanizam koji spreava da vie procesa istovremeno menja
sadraj kontejnera. Problem nastaje ako ste usred iteriranja kroz kontejner, a neki drugi
proces uskoi i um etne, ukloni ili izmeni neki objekat u tom kontejneru. Moda ste taj ele-
Poglavfje 17: Detaljno razmatranje kontejnera 709
m ent kontejnera ve proli, m oda je on ispred vas, m oda e se kontejner sm anjiti nakon
to pozovete m etodu s iz e () - scenarija za katastrofu im a koliko hoete. Biblioteka Java
kontejnera upotrebljava m ehanizam brzog otkazivanja (engl. fail-fast); u kontejneru trai
izm ene koje nije prouzrokovao va proces lino. Ako otkrije da neko drugi m enja sadraj
kontejnera, odm ah generie izuzetak ConcurrentModificationException. Taj aspekat se
naziva brzo otkazivanje - problem se ne trai naknadno, nekim sloenijim algoritm om .
M ehanizam brzog otkazivanja je sasvim lako videti u praksi - dovoljno je napraviti ite-
rato r i zatim neto dodati kolekciji na koju iterator pokazuje:
/ / : ko n te jn e ri/B rz o O tk a z iv a n je .ja v a
/ / Pokazuje ponaanje nazvano " b rz o o t k a z i v a n j e " .
im p o r t j a v a . u t i l . * ;
p u b l i c c la s s B r z o O tk a z iv a n je {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
C o l l e c t i o n < S t r i n g > c = new A r r a y L i s t < S t r i n g > ( ) ;
Ite ra to r< S trin g > i t = c . i t e r a t o r ( ) ;
c.add("N eki o b je k a t" ) ;
try {
S trin g s = i t . n e x t ( ) ;
} c a t c h ( C o n c u r r e n t M o d if ic a t io n E x c e p t io n e) {
S y s te m .o u t.p rin tln (e );
}
}
} / * Is p is :
j a v a . u t i 1 .Concu rrentModi f i c a t i o n E x c e p t i o n
* ///:-
uvanje referenci
Biblioteka java.lan g .ref sadri skup klasa koje om oguuju veu fleksibilnost u
sakupljanju smea. Te klase su naroito korisne kada radite s velikim objektim a koji m ogu
iscrpeti m em oriju. O d apstraktne klase Reference nasledene su tri klase: SoftReference,
W eakR eference i P hantom R eference. Svaka od njih sakupljau smea prua drugaiji
nivo indirekcije ukoliko je objekat o kojem se radi dostian sam o preko jednog od tih Re-
ference objekata.
Ako je objekat d ostia n , m oe se pronai negde u program u. To m oe znaiti da im ate
obinu referencu steka koja upuuje pravo na objekat, ali mogli biste im ati i referencu
objekta koji sadri referencu objekta o kojem se radi; tih meuveza m oe biti mnogo.
710 Misliti na Javi
/ / : ko n te jn e ri/R e fe re n c e .ja v a
/ / Prim er o b je k a ta t i p a Reference
im p o r t j a v a . l a n g . r e f
im p o r t j a v a . u t i l . * ;
c la s s VeomaVeliki {
p r i v a t e s t a t i c f i n a l i n t VELICINA = 10000;
p r i v a t e long'[] l a = new 1ong[V ELICINA];
p r iv a te S trin g id e n t;
p u b l i c V e o m a V e lik i( S t r in g i d ) { id e n t = i d ; }
p u b lic S trin g to S tr in g O { re tu rn id e n t; }
p r o t e c t e d v o id f i n a l i z e ( ) {
S y s t e m . o u t . p r i n t l n ( " F i n a l i zo va n je " + i d e n t ) ;
}
}
p u b l i c c la s s Reference {
p r i v a t e s t a t i c ReferenceQueue<VeomaVeli k i> rq =
new ReferenceQueue<VeomaVeli k i > ( ) ;
p u b l i c s t a t i c v o id checkQueue() {
Reference<? extends VeomaVeliki> urd = r q . p o l l ( ) ;
i f ( u r d != n u l l )
Poglavlje 17: Detaljno razmatranje kontejnera 711
Kada pokrenete ovaj program (preusm erite njegov izlaz u tekstualnu datoteku da biste
rezultate mogli da gledate stranicu po stranicu), videete da objekti bivaju sakupljani u
smee iako im i dalje m oete pristupati preko objekta tipa Reference - referencu objekta
pribavljate m etodom g e t ( ). Videete i to da ReferenceQueue uvek proizvodi null objekat
tipa Reference. Da bi taj objekat postao upotrebljiv, nasledite odreenu klasu Reference,
a novoj klasi dodajte upotrebljivije metode.
712 Misliti na Javi
Kontejner WeakHashMap
Biblioteka kontejnera im a posebnu m apu za skladitenje slabih referenci: to je W eak-
HashMap. Ta klasa olakava pravljenje kanonizovanih m apiranja (preslikavanja). Takvim
m apiranjem tedite m em oriju jer pravite sam o jednu instancu odreene vrednosti. Kada
program u zatreba ta vrednost, on potrai postojei objekat u tom m apiranju i upotrebi
njega (um esto da ga pravi od nule). M apiranje m oe napraviti vrednosti u sklopu svoje
inicijalizacije, ali se vrednosti ee prave tek na zahtev.
Poto je ovo tehnika za utedu m em orije, ba je podesno to WeakHashMap om o-
guuje skupljau smea da autom atski isti njene kljueve i vrednosti. S kljuevima i
vrednostim a koje elite da smestite u m apu WeakHashMap ne m orate da radite nita po-
sebno; sam a m apa ih autom atski om otava u objekte tipa WeakReference. O kida koji
dozvoljava ienje jeste injenica da se klju vie ne upotrebljava, kao to je prikazano u
narednom prim eru:
/ / : k o n t e j n e r i/ K a n o n s k o M a p ir a n j e . ja v a
/ / Prim e r s kontejnerom WeakHashMap.
im p o r t j a v a . u t i l
c la s s Element {
p r iv a te S trin g id e n t;
p u b l i c E le m e n t (S tr in g i d ) { i d e n t = i d ; }
p u b l i c S t r ir . g t o S t r i n g ( ) { r e t u r n i d e n t ; }
p u b l i c i n t hashCode() { r e t u r n i d e n t .h a s h C o d e ( ) ; }
p u b l i c boolean e q u a ls (O b je c t r ) {
r e t u r n r i n s t a n c e o f Element &&
i d e n t . e q u a l s ( ( ( E le m e n t)r ) . i d e n t ) ;
}
p r o t e c t e d v o id f i n a l i z e ( ) {
System .out. p r i n t ln ( " F in a liz o v a n je " +
g e t C l a s s ( ) .getSimpleName() + " " + i d e n t ) ;
}
}
c la s s K l j u c extends Element {
p u b lic K lju c (S trin g id ) { s u p e r(id ); }
}
p u b l i c c l a s s KanonskoMapir a n je {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) {
i n t v e l i c i n a = 1000;
/ / I l i i z a b e r i t e v e l i i n u na komandnoj l i n i j i :
i f ( a r g s . l e n g t h > 0)
v e l i c i n a = new l n t e g e r ( a r g s [ 0 ] ) ;
Poglavlje 17: Detaljno razmatranje kontejnera 713
K l j u c [ ] k l j u c e v i = new K l j u c [ v e l i c i n a ] ;
WeakHashMap<Kljuc,Vrednost> mapa =
new WeakHashMap<Kljuc,Vrednost>();
f o r ( i n t i = 0; i < v e l i c i n a ; i+ + ) {
K l j u c k = new K l j u c ( I n t e g e r . t o S t r i n g ( i ) ) ;
Vrednost v = new V r e d n o s t ( I n t e g e r . t o S t r i n g ( i ) ) ;
i f ( i % 3 == 0)
k l j u c e v i [ i ] = k; / / Sauvaj kao " p ra v e " r e f e r e n c e
m ap a .p u t(k , v ) ;
)
Syste m .g c();
}
} /* ( P o k r e n it e da b i s t e v i d e l i re z u lta te ) * / / / : -
Vector i Enumeration
Jedini niz koji je mogao da se proiruje u Javi 1.0/1.1 bio je Vector,pa se dosta koristio. Nje-
govi nedostaci su suvie brojni da bi se ovde naveli (potraite prvo izdanje ove knjige na lo-
kaciji www.RruceEckel.coin). U osnovi, to je bio ArrayList s dugim , nezgodnim im enim a
metoda. U biblioteci kontejnera nove Jave, Vector je prilagoen da bi mogao da radi i kao
kolekcija i kao lista. To je pomalo udno zato to bi neki ljudi mogli pom isliti kako je klasa
Vector poboljana, a ona u stvari postoji samo da bi podravala stari Java kod.
Verzija iteratora u Javi 1.0/1.1 drugaije se zvala - Enum eration - tj. nije korien ter-
min koji je svima poznat. Interfejs Enumeration je m anji od interfejsa Iterator i sadri
sam o dve m etode s dugakim imenima: boolean hasMoreElements( ) koja vraa true
ako kontejner sadri jo elemenata, i Object nextElement( ) koja vraa sledei element
kolekcije ako on postoji (inae generie izuzetak).
Enumeration je samo interfejs bez realizacije, pa ga ak i nove biblioteke ponekad ko-
riste, to nije preporuljivo ali je barem bezopasno. Iako bi prilikom pisanja novih pro-
gram a uvek trebalo koristiti Iterator, m orate znati da postoje biblioteke koje ele da vam
proslede objekat tipa Enumeration.
714 Misliti na Javi
O sim toga, pom ou m etode C o Ile ctio n s.e n u m eratio n () moete da napravite objekat
tipa E n u m e ra tio n za bilo koju kolekciju, kao u ovom prim eru:
/ / : k o n te jn e ri/N a b ra ja n je .ja v a
/ / Java 1 . 0 / 1 . 1 k la s e V e c t o r i Enumeration.
im p o r t j a v a . u t i l . * ;
im p o rtn e t.m in d v ie w .u til.*;
p u b l i c c la s s N a b ra ja n je {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
V e c t o r < S t r in g > v = new V e c t o r < S t r in g > ( C o u n t r ie s . n a m e s ( lO ) ) ;
En u m e ra tio n < Stri ng > e = v . e l e m e n t s ( ) ;
w h i1e ( e . hasMoreElements( ) )
S yste m .o u t.p rin t(e .n e x tE le m e n t() + ", " ) ;
/ / Pra vi Enumeration od k o l e k c i j e :
e = C o lle c t io n s . e n u m e r a t io n ( n e w A r r a y L i s t < S t r i n g > ( ) ) ;
}
} / * Is p is :
ALGERIA, ANGOLA, BENIN, B0TSWANA, BURKINA FASO, BURUNDI,
CAMEROON, CAPE VERDE, CENTRAL AFRICAN REPUBLIC, CHAD
* ///:-
Da biste napravili objekat tipa Enumeration, pozovite m etodu elem en ts(), koju po-
tom m oete da upotrebite za prolazak kroz listu.
U poslednjem redu pravi se objekat klase ArrayList i koristi m etoda en u m eration ()
za dobijanje objekta tipa Enumeration na osnovu iteratora klase ArrayList. Dakle, m oe-
te da koristite nove kontejnere i sa starim kodom u kom e se upotrebljava Enumeration.
Klasa Hashtable
Kao to ste videli u delovima ovog poglavlja posveenim uporeivanju perform ansi, klasa
Hashtable je veoma slina klasi HashMap, ak su i imena m etoda ista. Zato nem a razloga
da se u novim program im a um esto klase HashMap koristi Hashtable.
Klasa Stack
Pojam steka objanjen je ranije, u odeljku o klasi LinkedList. Klasa Stack iz Jave 1 .0 /1 .1
udna je: um esto da koristi klasu Vector i kom poziciju, ona je izvedena (nasleena) iz kla-
se Vector. Zato im a sva obeleja i ponaanje kiase Vector, uz dodatne funkcije steka. Teko
je razaznati da li su projektanti sm atrali da je to posebno korisno, ili se radi o neznanju;
ipak, jasno je da projekat nije revidiran pre putanja u distribuciju, pa se i tako lo dizajn
jo uvek sree (ali ga vi nem ojte koristiti).
Evo jednostavnog prim era steka na koji se stavlja svaki red iz niza objekata tipa String.
Pokazano je kako je kao stek jednako lako koristiti ulananu Iistu (objekat tipa Linked-
List) ili stek napravljen u poglavlju uvcmje objekata:
Poglavfje 17: Detaljno razmatranje kontejnera 715
/ / : k o n t e j n e r i / S t e k o v i . ja v a
/ / P r i k a z i v a n j e k la s e Stack.
im p o r t j a v a . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s S te ko vi {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
S ta c k < S tr in g > s t k = new S ta c k < S trin g > ( ) ;
for(M esec m : M e s e c .va lu e s O )
s tk .p u s h (m .to S trin g ());
p rin t("s te k = " + s tk ) ;
/ / Stek kao V e cto r:
s tk . a d d E le m e n t ( " P o s le d n ji r e d " ) ;
p rin t("e le m e n t 5 = " + s tk .e le m e n tA t(5 ));
p r i n t ( " V a d i m e le m e n t e : " ) ;
w h i1e ( ! s t k . e m p t y ( ) )
p rin tn b (s tk .p o p () + " " ) ;
/ / Ulanana l i s t a kao s te k :
L i n k e d L i s t < S t r in g > l s t e k = new L i n k e d L i s t < S t r in g > ( ) ;
fo r(M esec m : M ese c .va lu e s ( ) )
1s te k .a d d F i r s t ( m . t o S t r i n g ( ) ) ;
p r i n t ( " 1 s te k = " + l s t e k ) ;
w h i1e ( ! 1s t e k . i sEmpty( ) )
p r i n t n b (1 s t e k . r e m o v e F ir s t ( ) + " " ) ;
Klasa BitSet
Klasa BitSet se koristi za efikasno uvanje velike koliine inform acija tipa u k lju e n o -is-
kljueno. O na je efikasna sam o s take gledita veliine; ako vam je potreban brz pristup,
treba da znate da je ova klasa neto sporija od nizova prirodnog tipa.
Osim toga, m inim alna veliina skupa bitova je long, tj. 64 bita. To znai da klasa BitSet
nee biti efikasna za uvanje kraih podataka, npr. onih od 8 bitova. U tom sluaju, bolje
je da napravite sopstvenu klasu, ili sam o niz u koji ete sm estiti podatke ako vam je bitna
veliina. (To e biti sluaj sam o ako pravite m nogo objekata koji sadre liste inform acija
tipa ukljueno-iskljueno, a odluku treba doneti tek na osnovu rezultata program a z.a op-
timizaciju i ostalih m erenja. Ukoliko ste to odluili sam o zato to ste sami neto proglasili
za preveliko, imaete veom a sloen program i izgubiete m nogo vrem ena.)
O bian kontejner se iri kada m u odajete nove elem ente, a to radi i BitSet. Sledei
prim er pokaz.uje kako radi klasa BitSet:
/ / : k o n t e j n e r i / B i t o v i . ja v a
/ / P r i k a z i v a n j e k la s e B i t S e t .
im p ort j a v a . u t i l
im p o r t s t a t i c n e t . m i n d v i e w . u t i 1 . P r i n t . * ;
p u b l i c c la s s B i t o v i {
p u b l i c s t a t i c v o id i spi s i Bi t o v e ( B i t S e t b) {
p rin t( " b ito v i: " + b );
S t r i n g B u i 1d e r b b i t o v i = new S t r i n g B u i 1d e r ( ) ;
f o r ( i n t j = 0; j < b . s i z e ( ) ; j+ + )
b b i t o v i . a p p e n d ( b . g e t ( j ) ? "1" : " 0 " ) ;
p rin t("b it-m a s k a : " + b b it o v i) ;
)
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) {
Random rand = new Random(47);
/ / Uzmi b a j t najmanje t e i n e od n e x t l n t ( ) :
b yte b t = ( b y t e ) r a n d . n e x t l n t ( ) ;
B it S e t bb = new B i t S e t ( ) ;
f o r ( i n t i = 7; i >=0; i - - )
i f ( ( ( l i ) & b t ) != 0)
b b .s e t(i);
el se
bb. c l e a r ( i );
Poglavlje 17: Detaljno razmatranje kontejnera 717
in t i t = ra n d .n e x tln t();
B i t S e t bi = new B i t S e t ( ) ;
f o r ( i n t i = 31; i >=0; i - - )
i f ( ((1 i ) & it) != 0)
b i . s e t( i );
el se
b i . c le a r( i);
p rin t("v re d n o s t tip a in t : " + it);
is p is iB i to v e (b i);
/ / T e s t i r a j skupove b i t a >= 64 b i t a :
B i t S e t bl27 = new B i t S e t O ;
b l 2 7 . s e t (127);
p r i n t ( " b i t b r o j 127 j e u k l j u e n : " + b l 2 7 ) ;
B i t S e t b255 = new B i t S e t ( 6 5 ) ;
b255. s e t ( 25 5 );
p r i n t ( " b i t b r o j 255 j e u k lj u e n : " + b 2 5 5 ) ;
B i t S e t b1023 = new B i t S e t ( 5 1 2 ) ;
b 1023. s e t (1023);
b l 0 2 3 . s e t ( 1024);
p r i n t ( " b i t b r o j 1023 j e u k lj u e n : " + b l0 2 3 ) ;
} / * Is p is : }
v r e d n o s t t i p a b y t e : -107
b i t o v i : { 0 , 2, 4, 7}
bi t - m a s k a :
1 0 101 0 010 0 000 0 000 0 000000000000 000000000000000000000000000000000000000000000
vr e d n o s t t i p a s h o r t : 1302
b i t o v i : { 1 , 2, 4, 8 , 10}
b it - m a s k a :
101010010000000000000000000000000000000000000000000000000000000000000000000
v r e d n o s t t i p a i n t : -2014573909
b i t o v i : { 0 , 1, 3, 5, 7, 9, 11, 18, 19, 21, 22, 23, 24, 25, 26, 31}
b it - m a s k a :
1010 1 001 0 000 0 000 0 0000000000000000000000000000000000000000000000000000000000
b i t b r o j 127 j e u k lj u e n : {127}
b i t b r o j 255 j e u k l j u e n : {255}
b i t b r o j 1023 j e u k lj u e n : {1023, 1024}
* ///= -
718 Misliti na Javi
Saetak
Ima onih koji tvrde da je biblioteka kontejnera najvanija biblioteka objektno orijentisanog
jezika. U veini programa kontejneri se upotrebljavaju vie od ijedne druge kom ponente
biblioteke. Neki jezici (Python, na prim er) imaju ugraene ak i osnovne kontejnerske
kom ponente (liste, mape i skupove).
Kao to ste videli u poglavlju uvanje objekata, pom ou kontejnera se moe uraditi
m nogo toga zanimljivog, a bez m nogo napora. M eutim , doi e trenutak kada ete m o-
rati da znate vie o kontejnerim a kako biste mogli pravilno da ih upotrebljavate - kon-
kretno, m orate znati dovoljno o operacijam a transform isanja kljueva (heiranja) da
biste napisali sopstvenu m etodu h a s h C o d e () (a m orate znati i kada je to neophodno), i
m orate znati ovoljno o raznim realizacijama kontejnera da biste izabrali onu koja vam
treba. U ovom pogiavlju objasnili sm o te pojm ove i razm otrili jo neke korisne detalje o
biblioteci kontejnera. U ovom tren utku trebalo bi da ste prilino dobro priprem ljeni za
korienje Java kontejnera u svakodnevnim program erskim zadacima.
Biblioteku kontejnera je teko projektovati (to vai za veinu dizajnerskih problem a s
bibliotekama). U C ++-u, kontejnerske klase su obuhvatale m nogo razliitih klasa. I'o je
bilo bolje od onoga to je postojalo pre kontejnerskih klasa jezika C ++ (a to je nita), ali se
nije moglo lepo prevesti u Javu. Druga je krajnost kontejnerska biblioteka koja se sastoji od
jedne jedine klase, container, koja istovrem eno radi kao linearna sekvenca i asocijativni
niz. Javina biblioteka kontejnera odrava neku ravnoteu: ima svu funkcionalnost koju
oekujete od zrele biblioteke kontejnera, ali ju je lake nauiti i lake se koristi od kontej-
nerskih klasa jezika C++ i ostalih slinih biblioteka kontejnera. Rezultat ponegde izgleda
udno. Za razliku od nekih drugih odluka sprovedenih u starim Java bibliotekama, te ud-
novatosti nisu nastale sluajno, nego su posledica odluka paljivo odvaganih kako bi se po-
stigao kom prom is po pitanju sloenosti.
R eenja o d a b ra n ih vebi d a ta su u e le k tro n sk o m d o k u m e n tu Thc Thinking in Jtiva Annotatcd Sohi-
tion Guide , koji sc m o e k u p iti na lok aciji wwiv.MindVicw.cinn.
Javin ulazno-izlazni sistem
Stvaranje dobrog ulaztio-izlaznog (U /I) sistem a jed a n je od teih zadataka za projektanta je-
zika. Posledica toga je veliki broj razliitih pristupa.
Klasa File
Pre nego to se pozabavim o klasama koje i itaju i upisuju podatke u tokove, prouiem o
uslune klase koje postoje u biblioteci, a pom au u radu s datotekam a.
Klasa File ima zbunjujue ime: moete se prevariti i pomisliti da se odnosi na datoteku.
Bolje ime za klasu bilo bi FilePath. O na moe da predstavlja !;eodreenedatoteke ili im ena
skupa datoteka u direktorijum u. Ako je re o skupu datoteka, moete da ga potraite meto-
dom list( ) koja vraa niz podataka tipa String. Vraanje niza um esto neke prilagodljive
kontejnerske klase opravdano je zato to je broj elemenata nepromenljiv, a ako elite dru-
gaiji spisak saraja direktorijum a, treba da napravite drugaiji objekat klase File. U ovom
odeljku prikazuje se korienje ove klase i njoj pridruenog interfejsa FilenameFilter.
Listanje direktorijuma
Pretpostaviem o kako hoete da vidite spisak sadraja direktorijum a. Objekat klase File
moete upotrebiti na dva naina. Ako pozovete m etodu lis t ( ) bez argum enata, dobiete
kom pletnu listu datoteka u direktorijum u koji opisuje taj objekat. Ukoliko elite ograni-
enu listu, npr. sve datoteke s nastavkom .java, upotrebite filtar direktorijum a, klasu
koja pokazuje kako se biraju objekti klase File koji e se prikazivati.
720 Misliti na Javi
Evo kratkog prim era. O bratite panju na to da se rezultati veom a lako ureuju po abe-
cednom redosledu pom ou m etode java.utii.Arrays.sort( ) i kom paratora String.
CASE_INSENSITIVE_ORDER:
p u b l i c c la s s L i s t a n j e D i r e k t o r i j u m a {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
F i l e p u t a n ja = new F i l e ( " . ) ;
S trin g [] lis t a ;
i f ( a r g s . l e n g t h == 0)
lis ta = p u ta n ja .lis t();
el se
lista = putanja.list(new Filt ar lm en a( ar gs ));
A r r a y s . s o r t ( l i s t a , String.CASE_INSENSITIVE_ORDER);
f o r ( S t r i n g s t a v k a D ir : l i s t a )
System.out.pri ntln(stavkaDir);
}
}
class Filtarlmena implements Fi1en am eF i1ter {
private Pattern uzorak;
public FiltarImena(String regiz) {
uzorak = Pattern.compi1e ( r e g i z ) ;
}
public boolean accept(File dir, String ime) {
return uzorak .m at ch er (i me ).m at ch es( );
}
} /* Ispis:
PrimerZaDi rektorijum.java
Li stanjeDi rektorijuma.java
ListanjeDi rektorijumaZ.java
Li stanjeDi rektorijuma3.java
* ///:-
Klasa F iita rlm en a realizuje interfejs Filenam eFilter. Korisno je videti koliko je inter-
fejs F ilenam eFilter jednostavan:
Ova klasa postoji sam o da bi m etodi li s t ( ) pruila m etodu a c c e p tf), da bi list( ) mogla
povratno da pozove a c c e p t() i tako utvrdi koja im ena datoteka bi trebalo da se nau u
listi. Stoga se ovakva struktura esto naziva p o vra tn i poziv (engl. callback). Konkretnije,
ovo je prim er projektnog obrasca Strategy (Strategija), poto li s t ( ) realizuje tek osnovnu
funkcionalnost, a vi dajete Strategy u obliku interfejsa F ilenam eFilter koji dovrava algo-
Poglavlje 18: Javin ulazno-izlazni sistem 721
ritam potreban metodi lis t() za pruanje usluge. Poto je argument metode lis t() objekat
klase FilenameFilter, to znai da joj moete proslediti objekat bilo koje klase koja reali-
zuje interfejs FilenameFilter, i tako (ak i u vreme izvravanja) odrediti nain ponaanja
metode lis t( ). Svrha Strategije je da se obezbedi prilagodljivost koda.
Argument metode accept() m ora da bude objekat klase File koji predstavlja direkto-
rijum, kao i String koji sadri ime datoteke. Zapamtite da metoda lis t( ) poziva metodu
accep t() za svako ime datoteke u direktorijumu, da bi videla koje od njih treba ukljuiti
u listu. Na to ukazuje rezultat metode accept() koji je tipa boolean.
Metoda accept() koristi metodu m atcher(ime) da bi proverila da li se regularni izraz
regiz podudara sa imenom datoteke. Rezultat metode lis t() je niz koji se postepeno pravi
pomou metode accept().
A n o n im n e unutranje klase
Ovaj primer je savren za prepravljanje pomou anonimne unutranje klase (takve klase
su opisane u poglavlju Unutranje klase). Kao prva promena, uvodi se metoda filter( )
koja vraa referencu na FilenameFilter:
Obratite panju na to da argument metode filte r() mora da bude oznaen kao final.
To je neophodno da bi anonimna unutranja klasa mogla da koristi objekat koji je izvan
njene oblasti vaenja.
Ovakav pristup je bolji zato to je klasa koja realizuje interfejs FilenameFilter sada vr-
sto povezana s klasom ListanjeDirektorijuma2. Meutim, ovaj pristup se moe dodatno
poboljati kada se definie anonimna unutranja klasa kao argument metode Iist( ); u
tom sluaju, program je jo krai:
//: ui/ListanjeDirektorijuma3.java
// Pravljenje anonimne unutranje klase "na licu mesta".
// { A r g s : "D.*\.java"}
import java.util.regex.*;
import java.io.*;
import j a v a . u t i l .*;
public class ListanjeDirektorijuma3 {
public static void main(final String[] args) {
File putanja = new File(".");
S trin g [] lis t a ;
i f ( a r g s . 1 ength == 0)
lis ta = p u ta n ja .lis t();
el se
l i s t a = p u ta n ja .lis t( n e w F ile n a m e F ilte r() {
p r i v a t e P a t t e r n uzorak = P a t t e r n . compi1e ( a r g s ) ;
p u b l i c boolean a c c e p t ( F i l e d i r , S t r i n g ime) {
r e t u r n u z o r a k . m a tc h e r ( i m e ) .m atches( ) ;
}
});
A r r a y s . s o r t ( 1 i s t a , S t r i n g . CASE I NSENSITIVE_0RDER);
fo r(S trin g s t a v k a D ir : lis ta )
S y s te m .o u t.p rin tln (s ta v k a D ir);
}
} / * Is p is :
PrimerZaDi r e k t o r i j u m . j a v a
Li s t a n je D i r e k t o r i j u m a . ja v a
Li s t a n je D i r e k t o r i j u m a 2 . j a v a
Li s t a n j e D i r e k t o r i j u m a 3 . j a v a
* ///:-
Argument metode m a in () sada je oznaen kao final, poto anonimna unutranja kla-
sa direktno koristi args.
Ovo pokazuje kako anonimne unutranje klase omoguuju pravljenje spefinih,
unikatnih klasa za brzo reavanje problema. Prednost ovog pristupa jeste to to je kod koji
reava odredeni problem izolovan na jednom mestu. S druge strane, kod nije uvek lako
itljiv, pa morate mudro da ga koristite.
Veba 1: (3) Izmenite program ListanjeDirektorijuma.java (ili neku od njegovih varija-
nata) tako da FilenameFilter otvara i ita svaku datoteku (uslunom metodom net.m in-
dview.util.TextFile) i prihvata je na osnovu toga sadri li ona bilo koji od argumenata
s komandne linije koji slede iza imena datoteke.
Poglavlje 18: Javin ulazno-izlazni sistem 723
/ / : n e t / m i ndvi e w / u t i 1 / D i r e k t o r i j u m . j a v a
/ / P r o iz v o d i sekvencu F i l e o b je k a ta k o j i odgovaraju
/ / regularnom i z r a z u , b i l o u lo ka lnom d i r e k t o r i j u m u ,
/ / b i l o prolasko m kroz s t a b lo d i r e k t o r i juma.
package n e t . m i n d v i e w . u t i l ;
im p o r t j a v a . u t i 1 . r e g e x . * ;
im p o r t j a v a . i o . * ;
im p o rt j a v a . u t i l
p u b l i c f i n a l c la s s D i r e k t o r i j u m j
p u b lic s t a t ic F ile [ ]
lo k a l ( F i l e d i r , f i n a l S t r i n g r e g i z ) {
r e t u r n d i r . 1i s t F i 1es(new F i 1enameFi1t e r ( ) {
p r i v a t e P a t t e r n uzorak = P a t t e r n . c o m p i l e ( r e g i z ) ;
p u b l i c boolean a c c e p t ( F i l e d i r , S t r i n g ime) {
r e t u r n u z o ra k .m a tc h e rf
new Fi 1e ( i m e ) . getNameO) .matches ( ) ;
}
I);
}
publ i c s t a t i c Fi 1e [ ]
1oka1( S t r i n g p u t a n ja , f i n a l S t r i n g r e g i z ) { // P r e k lo p lje n o
r e t u r n lo k a l( n e w F i l e ( p u t a n j a ) , r e g i z ) ;
}
/ / Dvojka za v r a a n je para o b je k a ta :
p u b l i c s t a t i c c la s s I n f o S t a b la implements I t e r a b l e < F i l e > {
p u b l i c L i s t < F i l e > d a to te k e = new A r r a y L i s t < F i l e > ( ) ;
p u b l i c L i s t < F i l e > d ir m i = new A r r a y L i s t < F i l e > ( ) ;
/ / Podrazumevani i t e r a b i l n i element j e l i s t a d a to te k a :
p u b l i c I t e r a t o r < F i 1e> i t e r a t o r ( ) {
retu rn d a t o t e k e . it e r a t o r ( ) ;
724 Misliti na Javi
vie informacija u svakoj rekurziji. Da bismo mogli da razlikujemo obine datoteke od di-
rektorijuma, povratna vrednost je zapravo ,,n-torka objekata - jedna lista koja sadri
obine datoteke i druga koja sadri direktorijume. Polja su namerno deklarisana kao jav-
na (public), poto je svrha InfoStabla da prikupi objekte - da vraate samo jednu listu,
ne biste je napravili privatnom, pa ni vraanje para objekata ne znai da ih morate napra-
viti privatnim. Obratite panju na to da InfoStabla realizuje Iterable<FUe> koji proizvo-
di datoteke, pa je podrazumevana iteracija" po listi datoteka, dok iteraciju po
direktorijumima zadajete sa dirm i.
Metoda InfoStabla.toString() upotrebljava klasu ,,pretty printer" da bi se ispis lake
pregledao. Podrazumevane metode to S trin g () za kontejnere, tampaju sve elemente jed-
nog kontejnera u istom redu. U velikim kolekcijama to postaje teko itljivo, pa bi se mo-
glo poeleti i neko drugo formatiranje. Sledea alatka dodaje prelaske u novi red
i uvlaenja za svaki element:
//: net/'mindview/util/PPrint.java
// Pretty-printer za kolekcije
package net.mindview.util;
import java.uti1
//: io/PrimerZaDirektorijum.java
// Primer upotrebe uslunih metoda za Direktorijum.
import java.io.*;
import net.mindview.util.*;
import static ne t. mi nd vi ew .u ti l.Print.*;
.\TestE0F.java
A T r a n s f e r T o . java
.\ x f i1es\ThawAlien.java
AF r e e z e A l i e n . c l a s s
.\GZIPcompress.class
.\Zi pC ompress.class
* ///:-
p u b l i c c la s s N a p r a v i D i r e k t o r i j u m e {
p r i v a t e s t a t i c v o id u p o tr e b a ( ) {
S y s te m .e rr.p rin tln (
"K o ri e n je :N a p ra v iD ire k to riju m e p u ta n ja l . . . \ n " +
" P r a v i sve p u t a n je \ n " +
" K o r i e n j e : N a p r a v i D i r e k t o r i jume -d p u t a n j a l . . . \ n " +
" B r i e sve p u t a n je \ n " +
" K o r i e n j e : N a p r a v i D i r e k t o r i j u m e - r p u t a n j a l p u t a n ja 2 \ n " +
"Pre im e n u je p u t a n j u l u p u t a n j u 2 " ;
S y s te m .e x it(l);
}
p r i v a t e s t a t i c v o id p o d a c i D a t o t e k e ( F i l e f ) {
S y s te m .o u t.p rin tln (
" A p s o lu tn a p u t a n j a : " + f . g e t A b s o l u t e P a t h ( ) +
" \ n moe da se i t a : " + f .c a n R e a d () +
" \ n moe da se u p i s u j e : " + f . c a n W r i t e ( ) +
" \ n ime: " + f.g e tN a m e () +
\n r o d i t e l j : " + f . g e t P a r e n t ( ) +
"\n putan ja : " + f.g e tP a th ( ) +
" \ n d u in a : " + f . l e n g t h ( ) +
\ n datum p o s le d n j e promene: " + f . 1a s t M o d i f i e d ( ) ) ;
Poglavlje 18: Javin ulazno-lzlazni sistem 729
Ulaz i izlaz
U U/I bibliotekama esto se koristi apstraktan pojam - tok podataka (engl. stream). Tok
predstavlja neki izvor ili ponor podataka u obliku objekta koji je u stanju da daje ili prima
delove podataka. Tok skriva detalje o tome ta se deava s podacima unutar stvarnog U/I
ureaja.
Klase Javine biblioteke za U/I podeljene su na ulazne i izlazne, to moete videti u hi-
jerarhiji Javinih klasa u dokumentaciji na Webu. Zbog nasleivanja, sve klase izvedene iz
InputStream ili Reader imaju osnovnu metodu re a d () za itanje jednogbajta ili niza baj-
tova. Slino, sve klase izvedene iz O utputStream ili W riter imaju osnovnu metodu write(
) za upisivanje jednog bajta ili niza bajtova. Meutim, obino neete koristiti te metode,
jer one postoje da bi ih koristile druge klase koje obezbeuju korisnije metode. Retko ete
praviti objekat toka korienjem samo jedne klase; umesto toga, grupisaete vie objekata
da biste postigli eljenu funkcionalnost. Mogunost da se napravi vie objekata radi do-
bijanja jednog toka, glavni je krivac za nerazumljivost Javine biblioteke tokova.
Korisno je kategorizovati klase prema njihovoj funkcionalnosti. U Javi 1.0 projektanti
biblioteka su se vodili idejom da se sve klase koje imaju veze sa ulazom, izvoe iz klase In-
putStream , a da sve klase povezane sa izlazom nasleuju klasu OutputStream .
Kao i dosad u knjizi, pokuau da prikaem klase, ali u podrazumevati da ete sve de-
talje, npr. kompletne spiskove metoda, traiti u dokumentaciji na Webu.
4. cev (engl. pipe) koja radi kao prava cev: podaci se stavljaju na jednom kraju, a izla-
ze na drugom
5. niz drugih tokova koji se mogu objediniti u jedan tok
6. drugi izvori, npr. veza sa Internetom (o ovome se govori u knjizi Thinking in Enter-
prise Java, dostupnoj na adresi www.MindView.net).
Svaki od ovih tipova ulaza povezan je sa odreenom potklasom klase InputStream.
Pored toga, FilterlnputStream takoe je vrsta ulaznog toka koji slui kao osnova za do-
punske klase, tj. za dodeljivanje atributa ili korisnih interfejsa ulaznim tokovima. O ovo-
me e biti rei u nastavku.
Ipak, nije tako. Iako su neki elementi prvobitne biblioteke tokova zastareii (ako ih kori-
stite, dobiete upozorenje od prevodioca), klase InputStream i O utputStream i dalje
obezbeduju vane funkcije binarno orijentisanog ulaza/izlaza, dok klase Reader i W riter
obezbeduju znakovno orijentisani Unicode ulaz/izlaz. Pored toga:
1. U lavu 1.1 dodate su nove klase u hijerarhiji ulaznih i izlaznih tokova, pa je oigled-
no da klase InputStream i O utputStream nisu zamenjene.
2. Postoje prilike kada morate da koristite klase iz binarne hijerarhije u kombinaciji
s klasama u znakovnoj hijerarhiji. Da bi se to postiglo, postoje posrednike klase:
InputStreamReader konvertuje InputStream u Reader, a O utputStream W riter
konvertuje O utputStream u Writer.
Hijerarhije klasa Reader i W riter postoje prvenstveno zbog internacionalizacije. Stara
U/I hijerarhija podrava samo osmobitne binarne tokove, odnosno ne radi dobro sa e-
snaestobitnim Unicode znakovima. Poto se Unicode koristi za internacionalizaciju (a Ja-
vin izvorni tip char je esnaestobitni Unicode), hijerarhije klasa Reader i W riter su
dodate da bi se podrao standard Unicode u svim U/I operacijama. Pored toga, projekto-
vane su nove biblioteke koje rade bre nego stare.
PipedlnputStream PipedReader
PipedOutputStream PipedW riter
U veini sluajeva otkriete da su interfejsi dve razliite hijerarhije slini, ako ne i istovetni.
736 Misliti na Javi
Jedno pravilo je sasvim jasno: kad god elite da koristite readL ine(), to vie ne bi tre-
balo da radite pomou klase D atalnputStream (o tome ete dobiti upozorenje tokom
prevoenja), ve pomou klase BufferedReader. U svim ostalim sluajevima, D atalnput-
Stream se i dalje preporuuje.
Da bi se olakao prelazak na korienje klase PrintW riter, njeni konstruktori prihva-
taju sve objekte tipa O utputStream , ali i Writer. Medutim, PrintW riter ne omoguuje
nita bolje formatiranje od klase PrintStream ; njihovi interfejsi su doslovno isti.
Konstruktor klase PrintW riter takode ima opciju za automatsko pranjenje internih
bafera, to se deava nakon svakog poziva metode p rin tln () ako je indikator postavijen u
konstruktoru.
//: io/BaferisanaUlaznaDatoteka.java
import java.io.*;
Veba 10: (2) Promenite vebu 8 tako da kao dodatne argumente s komandne linije pri-
hvata rei koje e traiti u datoteci. Ispiite sve redove u kojima se rei pronau.
Veba 11: (2) U primeru unutrasnjeklase/UpravljanjeStaklenomBastom.java, Kontro-
lerStakleneBaste sadri fiksiran skup dogaaja. Promenite program tako da ita dogaaje i
njihova relativna vremena iz tekstualne datoteke. (nivo teine 8): Za pravljenje dogaaja
upotrebite projektni obrazac Factory M ethod (Proizvodna metoda) pronai ete ga u knjizi
Thinking in Patterns (with Java) koja se moe preuzeti s lokacije www.MindView.net.
itanje iz memorije
U ovom odeljku se na osnovu String rezultata metode BufferedInputFile.read() pravi
objekat klase StringReader. Potom se poziva metoda re a d () koja ita jedan po jedan znak
i alje ga na konzolu.
p u b l i c c la s s C i t a n je lz M e m o r i je {
p u b l i c s t a t i c v o i m ain ( S t r i n g [] args)
throws I 0 E x c e p tio n {
S trin g R e a d e r i n = new S trin g R e a d e r (
B u f f e r e d l n p u t F i 1e . r e a d ( " C i t a n j e l z M e m o r i j e . j a v a " ) ) ;
i n t c;
w h i l e ( ( c = i n . r e a d ( ) ) != -1)
S y s te m .o u t.p rin t((c h a r)c );
}
} /* ( P o k r e n it e da b i s t e v i d e l i re z u lta t) * / / / : -
Obratite panju na to da metoda re a d () vraa sledei bajt kao ceo broj (int) i stoga se
on mora konvertovati u tip char da bi se pravilno ispisivao.
//: i o / F o r m a t ir a n U la z I z M e m o r ije . ja v a
im p o r t j a v a . i o . * ;
p u b l i c c la s s F o r m a t ir a n llla z I z M e m o rije {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] arg s)
throws I0 E x c e p tio n {
try {
D a taln putS tre am u la z = new D a ta InputStream (
new B yte A rr a y In p u tS tr e a m (
B a f e r i sa n a U la zn aD a to te ka .re a d (
74 0 Misliti na Javi
"FormatiranUlazIzMemorije.java"),getBytes()));
while(true)
System.out.print((char)ulaz.readByte());
} catch(EOFException e) {
System.err.println("Kraj toka");
}
}
} /* (Pokrenite da biste videli rezultat) *///:~
/ / : u i/P ro v e ra K ra ja .ja v a
/ / Provera k r a j a d a to te k e tokom njenog i t a n j a b a j t po b a j t .
im p o r t j a v a . i o . * ;
p u b l i c c la s s Prov e ra K ra ja {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
throws IOExce ption {
Data ln putStre am u la z =
new Data InputStream(
new B u ffe r e d In p u tS tr e a m (
new F i l e I n p u t S t r e a m ( " P r o v e r a K r a j a . j a v a " ) ) ) ;
w h i1e ( u l a z . a v a i 1a b l e ( ) != 0)
S y s te m .o u t. p r i n t ( ( c h a r ) u l a z . r e a d B y t e ( ) ) ;
}
} /* ( P o k r e n it e da b i s t e v i d e l i r e z u l t a t ) * / / / : -
/ / : io /O s n o v e P is a n ja U D a to te k u .ja v a
im p o r t j a v a . i o . * ;
p u b l i c c la s s OsnovePisanjaUDatoteku {
s t a t i c S t r i n g d a to te k a = "O sno v e P is a n ja U D a to te k u .o u t";
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
throvvs IOException {
BufferedRe ader u la z = new B u fferedReader(
new S trin g R e a d e r(
B a f e r is a n a U la z n a D a t o t e k a . r e a d (" O s n o v e P is a n ja U D a to t e k u . ja v a ") ) ) ;
P r i n t W r i t e r out = new P r i n t W r i t e r (
new B u ffe r e d W r ite r( n e w F i l e W r i t e r ( d a t o t e k a ) ) ) ;
i n t brojRedova = 1;
S t r i n g s;
w h i l e ( ( s = u l a z . r e a d L i n e O ) != nul 1 )
ou t.prin tln (b ro jR e d o va+ + + " + s);
o u t.c lo s e O ;
/ / P r ik a i u s k la d i t e n u d a to te k u :
S y s t e m . o u t . p r i n t l n ( B a f e r i sanaUlaznaDatoteka. r e a d ( d a t o t e k a ) ) ;
}
} /* ( P o k r e n it e da b i s t e v i d e l i re z u lta t) *///:-
Dok se redovi upisuju u datoteku, uveava se ukupan broj redova. Obratite panju na
to da nisam upotrebio klasu LineN um berlnputStream , poto je sasvim beskorisna. Kao
to je ovde pokazano, veoma je lako pratiti ukupan broj redova.
Kada se ulazni tok iscrpe, metoda readLine( ) vraa null. Videete eksplicitan poziv
metode cIose( ) za datoteku out. Ako ne pozovete metodu close( ) za izlaznu datoteku,
moe se desiti da bateri ne budu ispranjeni i da se zato izgube podaci.
/ / : i o / P r e c i caZaPi s a n je u D a to te k u . ja v a
im p o r t j a v a . i o . * ;
p u b l i c c la s s P re c ic aZaP is anjeuDatoteku {
s t a t i c S t r i n g d a to te k a = " P r e c ic a Z a P is a n je u D a t o t e k u . o u t " ;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
throws IOException {
BufferedReader u la z = new BufferedReader(
new S trin g R e a de r(
B a fe r is a n a U la z n a D a to te k a .r e a d ( "PrecicaZaPi s a n je u D a to t e k u . j a v a " ) ) ) ;
/ / Evo p r e ic e :
P r i n t W r i t e r o u t = new P r i n t W r i t e r ( d a t o t e k a ) ;
i n t brojRedova = 1;
S t r i n g s;
w h i l e ( ( s = u l a z . r e a d L i n e O ) != n u l l )
742 Misliti na Javi
Baferisanje je i dalje tu, samo ne morate sami da ga radite. Naalost, za ostale uobia-
jene programerske zadatke nisam napisao preice, pa tipian U/I i dalje zahteva mnogo
redundantnog teksta. Meutim, u ovoj knjizi se upotrebljava usluna metoda TextFile
koja e biti definisana malo kasnije u ovom poglavlju - ona pojednostavljuje te uobiaje-
ne programerske zadatke.
Veba 12: (3) Promenite vebu 8 tako da se otvara tekstualna datoteka u koju tekst moe
i da se upisuje. Upiite u datoteku redove koji se nalaze u ulananoj listi (LinkedList) i nji-
hove brojeve. (Nemojte koristiti klase LineNumber.)
Veba 13: (3) Promenite vebu OsnovePisanjaUDatoteku.java tako da za praenje broja
redova upotrebljava LineNumberReader. Obratite panju na to koliko je lake pratiti taj
broj programski.
Veba 14: (2) Na osnovu programa OsnovePisanjaUDatoteku.java, napiite program
koji poredi performanse upisivanja u datoteku pri korienju baferisanog i nebaferisanog
ulaza/izlaza.
//: io/CuvanjelRekonstruisanjePodataka.java
import java.io.*;
Veba 15: (4) Proitajte HTML okum entaciju klasa D ataO utputStream i D atalnputSt-
ream na Webu. Na osnovu programa CuvanjelPronalazenjePodataka.java, napiite
program koji skladiti i zatim rekonstruie sve mogue tipove s kojima rade klase Data-
O utputStream i D atalnputStream . Dokaite da se svi tipovi ispravno skladite i rekon-
struiu.
//: io /KoriscenjeRandomAccessFi 1e . j a v a
im p o r t j a v a . i o . * ;
p u b l i c c la s s KoriscenjeRa ndomAccessFi1e {
s t a t i c S t r i n g d a to te k a = " r t e s t . d a t " ;
s t a t i c v o id d i s p l a y ( ) throws IO Exce ption {
RandomAccessFi1e r f = new RandomAccessFile (datoteka, "r");
f o r ( i n t i = 0; i < 7; i+ + )
S y s t e m . o u t . p r i n t l n(
"Vre dn o st " + i + " : " + r f . re a d D o u b le () ) ;
S y s t e m . o u t . p r i n t l n ( r f . rea d U T F()) ;
rf,c lo s e ();
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
throws I 0 E x c e p t io n {
RandomAccessFile r f = new RandomAccessFi1e ( d a t o t e k a , " r w " ) ;
f o r ( i n t i = 0 ; i < 7 ; i+ + )
r f .w r it e D o u b le ( i*1.4 1 4 );
rf.w rite U T F ("K ra j d a to te k e ");
r f ,c lo s e ();
d is p la y ();
r f = new R a ndom A ccessFile (datoteka, " r w " ) ;
r f . se e k ( 5 * 8 ) ;
rf.w rite D o u b le (4 7 .0 0 0 1 ) ;
rf.c lo s e ();
di s p la y ( ) ;
}
} / * Is p is :
Vrednost 0: 0 .0
Vrednost 1: 1.414
Vrednost 2: 2.828
Vrednost 3: 4.242
Poglavlje 18: Javin ulazno-izlazni sistem 745
Vrednost 4: 5.656
Vrednost 5: 7.069999999999999
Vrednost 6: 8.484
Kra j d a to te k e
Vrednost 0: 0.0
Vre d n ost 1: 1.414
Vrednost 2: 2.828
Vrednost 3 : 4.242
V re d n ost 4: 5.656
V re d n ost 5: 47.0001
V rednost 6: 8.484
Kra j d a to te k e
* ///:-
Metoda d isplay() otvara datoteku i prikazuje njenih sedam elemenata kao vrednosti
tipa double. U metodi m ain( ), datoteka se pravi, otvara i menja. Poto svaki broj tipa
double (uvek) zauzima osam bajtova, da biste metodom seek() pronali estu vrednost
po redu, morate izraunati 5*8 i dobiete poziciju njenog poetnog bajta u datoteci.
Kao to je ranije pomenuto, klasa RandomAccessFile je potpuno izdvojena od ostatka
hijerahije U/I tokova, osim to realizuje interfejse D atalnput i DataOutput. Ona ne po-
drava dekorisanje, pa je zbog toga ne moete kombinovati ni s jednim aspektom potkla-
sa InputStream i O utputStream . Morate pretpostaviti da je klasa RandomAccessFile
ispravno baferisana, poto tu funkciju ne moete da joi dodate.
ledina opcija koja vam stoji na raspolaganju jeste drugi argument konstruktora; datote-
ku s nasuminim pristupom moete da otvorite radi itanja (r) ili itanja i upisivanja (rw).
Imajte u vidu da umesto klase RandomAccessFile moete koristiti nio datoteke pres-
likane u memoriju.
Veba 16: (2) Proitajte HTM LdokumentacijuklaseRandomAccessFilenaW ebu. Na os-
novu programa KoriscenjeRandomAccessFile.java, napiite program koji smeta i zatim
rekonstruie sve mogue tipove s kojima radi klasa RandomAccessFile. Dokaite da se svi
tipovi ispravno skladite i rekonstruiu.
Cevovodi
Klase PipedlnputStream , PipedO utputStream , PipedReader i PipedW riter pomenute
su u ovom poglavlju samo ukratko. Nemojte na osnovu toga zakljuiti da nisu korisne.
Njihova korisnost nije oigledna dok ne ponete da isprobavate vienitni rad, jer se cevo-
vodi upotrebljavaju za komunikaciju izmeu niti. O ovome e, uz primer, biti rei u po-
glavlju Paralelno izvravanje.
jo gore, zbog dekoratora je prilino teko zapamtiti kako se otvaraju datoteke. Dakle, bilo
bi dobro dodati biblioteci pomone klase koje e te elementarne operacije raditi umesto
nas. Java SE5 je klasi PrintW riter dodala prigodni konstruktor koji olakava otvaranje
tekstualne datoteke za upisivanje. Meutim, ostalo je jo mnogo drugih poslova koji se
esto ponavljaju, pa bi valjalo napisati kod za njih jednom zauvek.
Sledi klasa TextFile koju smo ve u prethodnim primerima iz ove knjige koristili da
pojednostavimo upisivanje i itanje datoteka. Ona sadri statine metode za itanje i upi-
sivanje tekstualnih datoteka u obliku jednog znakovnog niza, a moete napraviti i Text-
FUe objekat koji redove te datoteke uva u listi ArrayList (pa tokom rada sa sadrajem
datoteke imate na raspolaganju svu njenu funkcionalnost):
/ / : n e t / m i n d v i e w / u t i l / T e x t F i 1e . ja v a
/ / S t a t i n e f u n k c i j e za u p i s i v a n j e i i t a n j e t e k s t u a l n i h d a t o t e k a u o b l i k u
/ / jednog znakovnog n i z a , i t r e t i r a n j e d a t o t e k e kao je d n e A r r a y L i s t l i s t e .
/ / x je d n e A r r a y L i s t l i s t e .
package n e t . m i n d v i e w . u t i l ;
im p o rt j a v a . i o . * ;
im p ort j a v a . u t i l . * ;
o u t.c1o se ();
}
} c a tc h (IO E x c e p tio n e) {
throw new R u n t im e E x c e p t io n ( e ) ;
}
}
/ / U i t a j d a t o t e k u , i z d e l j e n u na r e i pomou b i l o koje g reg u la rn o g i z r a z a :
p u b l i c T e x t F i l e ( S t r i n g imeDa toteke , S t r i n g podela) {
s uper(A rrays.asLi s t( r e a d ( im e D a t o t e k e ) . s p lit ( p o d e la ) ) ) ;
/ / Zbog podele metodom s p lit ( ) p o m o u r e g u la rn o g i z r a z a , na
/ / p r v o j p o z i c i j i e sto o s t a j e prazan znakovni n i z :
i f ( g e t (0) . e p u a l s C " 1) ) remove(O);
}
/ / Obino se i t a red po re d :
p u b l i c T e x t F i l e ( S t r i n g imeDatoteke) {
t h is ( i m e D a t o t e k e , " \ n " ) ;
}
p u b l i c v o id w r i t e ( S t r i n g im eDatoteke) {
try {
P r i n t W r i t e r o u t = new P r i n t W r i t e r (
new F i 1e ( i m e D a t o t e k e ) . g e t A b s o lu t e F i1e ( ) ) ;
try {
f o r ( S t r i n g stavka : t h i s )
o u t.p rin tln (s ta v k a );
) fin a lly {
o u t.c lo s e ();
}
} c a t c h (IO E xce p ti on e) {
th ro w new R u n tim e E x c e p tio n ( e ) ;
}
}
/ / Jednostavna p ro v e r a :
p u b l i c s t a t i c v o id m ain ( S t r i n g [ ] args) {
S t r i n g d a to te k a = r e a d ( " T e x t F i 1e . j a v a " ) ;
w r i t e ( " t e s t . t x t " , da tote ka );
T e x t F i l e t e k s t = new T e x t F i l e C t e s t . t x t " ) ;
te k s t.w rite C te s t2 .tx t");
/ / Podela na je d i n s t v e n e r e i u ureenoj l i s t i :
T re e S e t< S trin g > r e c c i = new T re e S e t< S tr in g > (
new T e x t F i 1e ( " T e x t F i 1e . j a v a " , " \ \ W + " ) ) ;
/ / P r i k a i r e i s v e l i k i m poetnim slovom:
S y s t e m . o u t . p r i n t l n ( r e c c i . headSet( " a " ) ) ;
}
} / * Is p is :
[0 , A r r a y L i s t , A r r a y s , Break, Buffe red Re a d e r, B u f f e r e d W r i t e r , Clean, F i l e ,
F ile R e a d e r, F i l e W r i t e r , IO Exce p tio n , Jednostavn a, Obino, O u tp ut, P r i k a i ,
P r i n t W r i t e r , Read, R e g u la r, Ru ntim eExce ptio n, S t a t i c , S t r i n g , S t r i n g B u i l d e r ,
System, T e x t F i l e , T o o ls , Tre eSet, W, W r it e ]
* ///:-
748 Misliti na Javi
Metoda re a d () objektu tipa StringBuilder dodaje svaki red i zatim znak za prelazak u
novi red, jer se oni uklanjaju tokom itanja. Potom ona kao svoj rezultat vraa znakovni
niz koji sadri celu datoteku. Metoda w rite () otvara tekstualni znakovni niz i upisuje ga
u datoteku.
Vodite rauna o tome da svaki program koji otvara neku datoteku uva njen poziv me-
tode clo se() unutar bloka finaUy, da bi datoteka bila zajemeno zatvorena.
Konstruktor pretvara datoteku u znakovni niz pomou metode re a d (), zatim poziva
S tring.split() da bi taj rezultat podelio na redove (uz znakove za prelazak u novi red kao
graninike; ako ovu klasu esto upotrebljavate, mogli biste da prepravite taj konstruktor
tako da bude delotvorniji). Naalost, ne postoji odgovarajua metoda ,,spajanja redova u
znakovni niz, pa nestatinom m etodom w rite () moramo da ispisujemo red po red runo.
Poto je ova klasa napisana zato da bi do krajnosti pojednostavila postupak itanja i
pisanja datoteke, svi IOException izuzeci pretvoreni su u RuntimeException izuzetke,
kako korisnik ne bi morao da upotrebljava try-catch blokove. Meutim, moda ete mo-
rati da napiete drugu verziju koja IOException izuzetke prosleuje pozivaocu.
U metodi m a in () obavlja se elementarna provera ispravnosti rada spomenutih metoda.
Nije trebalo mnogo koda da bi se napisala ova usluna klasa, a ona e nam utedeti
mnogo vremena i olakati ivot, u ta ete se uveriti u nekima od narednih primera u
ovom poglavlju.
Problem s itanjem tekstualnih datoteka moe se reiti i na drugi nain, klasom ja-
va.util.Scanner uvedenom u Javu SE5. Medutim, ona slui samo za itanje datoteka, ne i
za pisanje u njih. Ta alatka (koja nije stavljena u paket java.io) prvenstveno je namenjena
za pravljenje analizatora programskih jezika (engl. scanners) ili malih jezika.
Veba 17: (4) Pomou klase TextFile i mape M ap<Character,Integer> napiite program
koji prebrojava znakove u datoteci. (Dakle, ako u nekoj datoteci ima 12 primeraka slova
a, 12 treba da sadri objekat tipa Integer pridruen objektu tipa Character koji sari a u
mapi).
Veba 18: (1) Izmenite program TextFile.java tako da izuzetke IOExceptions prosleduje
pozivaocu.
p u b l i c c la s s Bin a rn a D a to te ka {
p u b l i c s t a t i c b y t e [ ] r e a d ( F i l e bDatoteka) throws IO Exceptio n{
B u f f e r e d ln p u t S t r e a m bD = new B u ffe r e d In p u tS tr e a m (
new F i 1e ln p u tS t r e a m ( b D a t o t e k a ) ) ;
try {
Poglavlje 18: Javin ulazno-izlazni sistem 749
b y t e [ ] data = new b y t e [ b D . a v a i l a b l e ( ) ] ;
b D .re a d (d ata );
r e t u r n d a ta ;
} fin a lly {
b D .c lo s e ();
}
}
p u b lic s t a t ic b yte [ ]
r e a d ( S t r i n g bDa toteka) throws IOExce ptio n {
r e t u r n read(new F ile ( b D a t o t e k a ) . g e t A b s o l u t e F i l e O ) ;
}
} III--
Jedna preldopljena metoda prima argument tipa File; druga prima argument tipa
String, to je ime te datoteke. Obe vraaju rezultujui niz tipa byte.
Metodom available() pravi se niz odgovarajue veliine, a ba ova verzija preklopljene
metode re a d () popunjava taj niz.
Veba 19: (2) Pomou klase BinarnaDatoteka i mape Map<Byte,Integer> napiite pro-
gram koji prebrojava razliite bajtove u datoteci.
Veba 20: (4) Pomou metode Direktorijum .prolazak( ) i klase BinarnaDatoteka, do-
kaite da sve .class datoteke u stablu direktorijuma poinju heksadecimalnim kodovima
znakova CAFEBABF.
/ / : u i/E h o .ja v a
/ / Kako se i t a sta n d a rd n i u la z n i t o k .
/ / {RunByHand}
im p o r t j a v a . i o . * ;
p u b l i c c la s s Eho {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
throws IO Exce ptio n {
Buffe redReader s t d i n = new B u fferedReader{
new InputStre am Reader(S ystem.i n ) ) ;
S t r i n g s;
w h i l e ( ( s = s t d i n . r e a d L i n e ( ) ) != n u l l && s . 1e n g th ( ) != 0)
S y s te m .o u t.p rin tln (s );
/ / Program zavra va prazan red i l i C t r l - Z
}
> III--
Razlog za specifikaciju izuzetka u metodi m a in () jeste to to metoda readL ine() moe
da generie izuzetak IOException. Vodite rauna o tome da System.in obino treba da
bude baferisan, kao i veina tokova.
Veba 21: (1) Napiite program koji prima standardan ulaz, pretvara sva primljena
slova u velika, a zatim rezultate alje na standardan izlaz. Preusmerite u ovaj program
sadraj neke datoteke. (Postupak preusmeravanja se menja u zavisnosti od operativnog
sistema.)
p u b l i c c la s s OmotavanjeSystemOut {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) {
P r i n t W r i t e r o u t = new P r i n t W r i t e r ( S y s t e m . o u t , t r u e ) ;
o u t.p rin tln ("Z d ra v o , s v e te ");
}
} / * Is p is :
Zdravo , sv ete
* ///-.-
Vano je da se koristi verzija konstruktora 7,a klasu PrintW riter koja ima dva argu-
menta i da drugi argument bude true, da bi se omoguilo automatsko pranjenje izlaznih
bafera, inae se izlaz nee prikazivati red po red.
Poglavlje 18: Javin ulazno-izlazni sistem 751
/ / : u i/ P r e u s m e r a v a n je . ja v a
/ / P r ik a z u je standardno U / I preusmeravanje.
im p o r t j a v a . i o . * ;
c l a s s Preusmeravanje {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
thro ws IO Exception {
P r in t S t r e a m ko nzola = Syste m .o ut;
B u ff e r e d ln p u t S t r e a m i n = new B u ffe r e d In p u tS tr e a m (
new F i 1e I n p u tS tre a m (" P re u s m e ra v a n je .j a v a " ) ) ;
P r in t S t r e a m o u t = new P r in tS tr e a m (
new B u fferedO utputStre am (
new F i 1e O u t p u t S t r e a m ( " t e s t . o u t " ) ) ) ;
S y s te m .s e tln (in );
S y s te m .s e tO u t( o u t ) ;
S y s te m .s e tE rr(o u t);
Bu fferedReader b r = new BufferedReader(
new I n p u tS tre a m R e a d e r(S y s te m .in )) ;
S t r i n g s;
w h i l e ( ( s = b r . r e a d L i n e ( ) ) != n u l l )
S y s te m .o u t.p rin tln (s );
o u t . c l o s e ( ) ; / / Ne z a b o r a v it e ovo!
S y s t e m . s e tO u t ( k o n z o la ) ;
}
1 ///:-
Ovaj program povezuje datoteku na standardni ulaz i preusmerava standardni izlaz i
standardni tok za greke u drugu datoteku. Obratite panju na to da se na poetku pro-
grama skladiti referenca prvobitnog System.out objekta i da se na kraju standarni izlaz
vraa tom objektu.
U/I preusmeravanje radi s tokovima bajtova, a ne s tokovima znakova, pa se koriste
klase InputStream i O utputStream umesto klasa Reader i VVriter.
Upravljanje procesima
esto ete biti u prilici da iz Jave pokreete druge programe operativnog sistema i da
upravljate ulazom i izlazom tih programa. Javina biblioteka ima klase za takve operacije.
Uobiajen zadatak je pokretanje programa i slanje rezultujueg izlaza na konzolu.
U ovom odeljku napisaemo uslunu klasu koja e pojednostaviti taj zadatak.
U ovoj uslunoj klasi mogu nastati dve vrste greaka: uobiajene greke koje prouzro-
kuju izuzetke - za njih emo samo ponovo generisati RuntimeException - i greke pri
izvravanju samog procesa. Te greke emo prijavljivati posebnim izuzetkom:
/ / : n e t / m i n a v i e w / u t i 1/ O S I z v r s e n j e . j a v a
/ / Iz v r a v a komandu o p e ra t iv n o g s is te m a i i z l a z a l j e na k onzolu .
package n e t . m i n d v i e w . u t i l ;
im p o rt j a v a . i o . * ;
p u b l i c c la s s O SIzvrsenje {
p u b l i c s t a t i c v o id komanda(String komanda) {
boolean greska = f a l s e ;
try {
Process proces =
new Pr'ocessBui 1der(komanda. spl i t (" " ) ) . p o c e t a k ( ) ;
BufferedReader r e z u l t a t i = new Buffe red Re a d e r(
new I n p u t S t r e a m R e a d e r ( p r o c e s , g e t ln p u t s t r e a m ( ) ) ) ;
S t r i n g s;
w h i l e ( ( s = r e z u l t a t i . r e a d L i n e ( ) ) != n u l l )
S y s te m .o u t.p rin tln (s );
BufferedReader greske = new Buffe red Re a d e r(
new I n p u t S t r e a m R e a d e r ( p r o c e s . g e t E r r o r S t r e a m ( ) ) ) ;
/ / Ako ima problema, p r i j a v i g re ke i pozivajue m
/ / procesu v r a t i v re d n o s t r a z l i i t u od n u le :
w h i l e ( ( s = g r e s k e . r e a d L i n e O ) != nul 1) {
S y s te m .g re s k a .p r i n t l n ( s ) ;
greska = t r u e ;
}
} c a t c h (E x c e p t io n e) {
/ / Zbog Windowsa 2000, k o j i g e n e r i e
/ / iz u z e t a k za podrazumevani s a d r a j komandne l i n i j e :
Poglavlje 18: Javin ulazno-izlazni sistem 753
/ / ; u i/ P r i m e r O S I z v r s e n j a . ja v a
/ / P r ik a z u je standardno preusmeravanje U / I .
im p o r t n e t . m i n d v i e w . u t i l . * ;
/ ' / : u i/ D a j K a n a l . ja v a
/ / P r a v l j e n j e kanala od tokova
im p o rt j a v a . n i o . * ;
im p o rt j a v a . n i o . c h a n n e l s . * ;
im p o r t j a v a . i o . * ;
p u b l i c c la s s DajKanal {
p r i v a t e s t a t i c f i n a l i n t VELBAF = 1024;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exce p tio n {
/ / I s p i i datotekU:
FileChannel f c =
new F i 1e O u tp u tS tre a m ("p o d a c i. t x t " ) .getChannel ( ) ;
f c . w r i t e ( B y t e B u f f e r . w r a p ( Nekakav t e k s t " . g e t B y t e s ( ) ) ) ;
fc .c lo s e ();
/ / Dodaj na k r a j d a to te k e :
fc =
new RandomAccessFi1e ( " p o d a c i . t x t " , " r w " ) .getChannel ( ) ;
f c . p o s i t i o n ( f c . s i z e ( ) ) ; / / Prei na k r a j
f c . w r i te (B yte B u ffer.w ra p("Jo m alo",g e tB yte s( ) ) ) ;
fc .c lo s e ();
/ / i t a j d a to te k u :
f c = new F i l e I n p u t S t r e a m ( " p o d a c i . t x t " ) . g e t C h a n n e l ( ) ;
B y t e B u f f e r b a f = B y t e B u f f e r . a l 1ocate(VELBAF);
fc .re a d (b a f);
baf . f l i p ( ) ;
w h ile (b a f.h a s R e m a in i n g ( ) )
Poglavlje 18: Javin ulazno-izlazni sistem 755
Metoda getC hannel() za svaku prikazanu klasu tokova pravi objekat tipa FileChan-
nel. Kanal je prilino jednostavan: moe m u se predati objekat tipa ByteBuffer radi i-
tanja ili pisanja, i delove datoteke moete zakljuati, odnosno ostvariti iskljuivo pravo
pristupanja (to e biti opisano u nastavku).
Jedan od naina smetanja bajtova u ByteBuffer jeste da ih neposredno umetnete u
njega nekom od put metoda, i tako upiete jedan ili vie bajtova ili vrednosti prostih tipo-
va. Meutim, iz programa vidite da metodom w ra p () moete postojei niz tipa byte da
omotate objektom tipa ByteBuffer. Kada to uradite, pripadajui niz se ne kopira, nego
koristi kao skladite za generisani ByteBuffer. Kaemo da je taj ByteBuffer poduprt ni-
zom.
Datoteku podaci.txt ponovo otvara klasa RandomAccessFile. Vodite rauna o tome
da FileChannel moete premetati po datoteci; ovde sam ga premestio na kraj, tako da se
novi upisi dodaju na kraj postojeih (engl. append).
Kada primenjujete pristup samo za itanje, memorijski prostor za ByteBuffer morate
eksplicitno dodeliti statinom metodom allo cate(). Svrha nio klasa je brzo premetanje
velikih koliina podataka, pa nije nevano koju veliinu bafera ByteBuffer zadate - za-
pravo, ovde e vam 1 K verovatno mnogo manje znaiti nego inae (moraete da ekspe-
rimentiete s tekuom aplikacijom da biste odredili najbolju veliinu bafera).
U potrazi za jo veom brzinom, mogli biste metodom allocateD irect() umesto me-
todom allocate() napraviti direktan bafer koji je jo tenje spregnut sa operativnim siste-
mom. Meutim, reijski trokovi takve dodele su vei, a njena realizacija se menja u
zavisnosti od operativnog sistema, pa ete opet morati da eksperimentiete s tekuom ap-
likacijom da biste odredili donose li vam direktni baferi ikakvo ubrzanje.
Nakon to pozovete read( ) da biste kanalu FileChannel saoptili da upie bajtove u
ByteBuffer, morate pozvati metodu flip( ) za taj bafer kako biste mu saoptili da se pri-
premi za vaenje bajtova iz njega. (To jeste malo nezgrapno, ali ne zaboravite da se radi o
veoma niskom nivou i da se tako postie maksimalna brzina). A kada bismo taj bafer
upotrebili za jo neku operaciju re a d (), pre svakog uitavanja saraja u bafer morali bi-
smo da pozovemo metodu clear( ) kao pripremu. To vidite u ovom jednostavnom pro-
gramu za kopiranje datoteka:
/ / : u i/ K o p ir a n je K a n a lo m . ja v a
/ / K o p ir a n je d a to te k e pomou kanala i b a f e r a
/ / { A rg s: K o p ir a n je K a n alom .ja v a t e s t . t x t }
im p o r t j a v a . n i o . * ;
im p o r t j a v a . n i o . c h a n n e l s . * ;
im p o rt j a v a . i o . * ;
p u b l i c c la s s KopiranjeKanalom {
p r i v a t e s t a t i c f i n a l i n t VELBAF = 1024;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exce p tio n {
756 Misliti na Javi
if(a rg s .le n g th != 2) {
S y s te m .o u t.p rin tln ("a rg u m e n ti: d a tiz v o r d a to d re d is te ");
S y s te m .e x it(l);
}
FileCh annel
u la z = new F i l e I n p u t S t r e a m ( a r g s [ 0 ] ) . g e t C h a n n e l ( ) ,
i z l a z = new F i l e O u t p u t S t r e a m ( a r g s [ l ] ) . g e t C h a n n e l ( ) ;
B y t e B u f f e r b a f e r = B y t e B u f f e r . a l lo c a t e ( V E L B A F ) ;
w h i l e ( u l a z . r e a d ( b a f e r ) != -1) {
b a f e r . f l i p ( ) ; / / P rip re m i za p is a n je
iz la z .w r ite (b a fe r) ;
b a f e r . c l e a r ( ) ; / / Prip rem i za i t a n j e
}
}
} ///= -
Jedan FileChannel otvorili smo za itanje, a drugi za pisanje. Objektu tipa ByteBuffer
dodeljuje se memorija, i kada metoda FileChannel.read( ) vrati -1 (nema sumnje, ta
vrednost je zaostatak iz Unixa i C-a), to znai da smo oli do kraja ulaza. Nakon svakog
poziva metode re a d () koja u bafer smeta podatke, flip () priprema bafer da bi metoda
w rite () mogla da vadi podatke iz njega. Podaci ostaju u baferu i nakon itanja metodom
w rite (), i tek metoda c le a r() resetuje sve interne pokazivae tako da bafer postaje spre-
man da od metode re a d () primi nove podatke.
Prethodni program nije idealan za obavljanje te vrste operacija. Postoje posebne me-
tode transferT o() i tran sferF ro m () za neposredno povezivanje jednog kanala s drugim:
/ / : u i / T r a n s f e r T o . ja v a
/ / P o ve z iv a n je kanala metodom t r a n s f e r T o ( )
/ / { A r g s : T r a n s f e r T o . ja v a T r a n s f e r T o . t x t }
im p o r t j a v a . n i o . c h a n n e l s . * ;
im p o r t j a v a . i o . * ;
p u b l i c c la s s T ra n s fe rT o {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) throws Exce p tio n {
i f ( a r g s . l e n g t h != 2) {
S y s te m .o u t.p rin tln ("a rg u m e n ti: d a tiz v o r d a to d re d is te ");
S y s te m .e x it(l);
}
F i 1eChannel
u la z = new F ile l n p u t S t r e a m ( a r g s ) . g e t C h a n n e l ( ) ,
i z l a z = new F i 1e O u t p u t S tr e a m ( a rg s ) .g e tC h a n n e l( ) ;
u la z .tra n s fe rT o (0 , u l a z . s i z e ( ) , i z l a z ) ;
//III:
// i z l a z . t r a n s f e r F r o m ( u l a z , 0, u l a z . s i z e O ) ;
}
} ///:-
Ovako neto retko e vam trebati, ali dobro je to znati.
Poglavlje 18: Javin ulazno-izlazni sistem 757
Konverzija podataka
Ako se osvrnete na program DajKanal.java, videete da prilikom ispisivanja datoteke
podatke vadimo bajt po bajt, pa svaki byte zasebno pretvaramo u char. To je primitivno
- proitajte dokumentaciju klase java.nio.CharBuffer i videete da se u njoj za metodu
to S trin g () kae: Vraa znakovni niz koji sadri znakove bafera. Poto se ByteBuffer na-
kon obrade metodom asC harB uffer() moe smatrati baferom CharBuffer, zato ne bis-
mo upotrebili njega? Kao to vidite iz prvog reda ispisa rezultata sledeeg programa, to
ipak ne radi kako smo oekivali:
/ / : u i/B a fe rU T e kst.ja va
/ / K o n v e r z ija t e k s t a u B y t e B u f f e r i i z njega
im p o r t j a v a . n i o . * ;
im p o r t j a v a . n i o . c h a n n e l s . * ;
im p o r t j a v a . n i o . c h a r s e t . * ;
im p o r t j a v a . i o . * ;
p u b l i c c la s s BaferLITekst {
p r i v a t e s t a t i c f i n a l i n t VELBAF = 1024;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) throws Exce p tio n (
File Channel f c =
new Fi 1e 0 u tp u t S t r e a m ( " p o d a c i2 . t x t " ) . g e t C h a n n e l ( ) ;
fc .w rite (B y te B u ffe r.w ra p ("N e k i te k s t".g e tB y te s ( ) ) ) ;
fc .c lo s e O ;
f c = new Fi l e I n p u t S t r e a m C p o d a c i 2 . t x t " ) .getChannel ( ) ;
B y t e B u f f e r b a f = B y t e B u f f e r . a l lo c a t e ( V E L B A F ) ;
fc .re a d (b a f);
b a f. f l ip ( ) ;
/ / Ne r a d i :
S ystem .out. p ri n tln ( b a f.a s C h a rB u ffe r ( ) ) ;
/ / D e k o d ira j po podrazumevanoj emi k o d ir a n ja ovog sis tem a:
b a f.re w in d ();
S t r i n g k o d i r a n j e = S y s t e m . g e t P r o p e r t y ( " f i 1e . e n c o d i n g " ) ;
S y s t e m . o u t . p r i n t l n ( " D e k o d i r a n o po emi " + k o d i r a n j e + : "
+ C h a r s e t . forName(kodi r a n j e ) . d e c o d e ( b a f ) ) ;
/ / I I i da kodiramo po emi k o ja se moe o d ta m p a ti:
f c = new F i 1e 0 u tp u tS tr e a m ( " p o d a c i2 . t x t " ) . g e t C h a n n e l ( ) ;
f c . w r i t e ( B y t e B u f f e r . w r a p ( " N e k i t e k s t " . g e tB y te s ("U T F -1 6 B E ")) ) ;
fc .c lo s e O ;
/ / Sada ponovo p o k u a jte da i t a t e :
f c = new Fi 1e I n p u t S t r e a m C p o d a c i 2 . t x t " ) .getChannel ( ) ;
b a f.c le a r();
fc .re a d (b a f);
b a f. f l ip ( ) ;
S y s te m .o u t.p rin tln (b a f.a s C h a rB u ffe r());
/ / Pisaemo kroz C h a rB u ffe r :
f c = new F ile 0 u t p u t S t r e a m C p o d a c i 2 . t x t " ) .getChannel ( ) ;
b a f = B y t e B u f f e r . a l l o c a t e ( 2 4 ) ; / / Vie nego t o j e potrebno
b a f . asCharB uff e r ( ) . p u t ( " Neki t e k s t " ) ;
f c . w r ite (b a f);
758 Misliti na Javi
fc .c lo s e ();
/ / ita n je i p rik a z iv a n je :
f c = new F i l e I n p u t S t r e a m ( " p o d a c i 2 . t x t ) . g e t C h a n n e l( ) ;
b a f.c le a rO ;
fc .re a d (b a f);
b a f.fl ip ( ) ;
S y s te m .o u t.p rin tln (b a f .a s C h a rB u ffe rO );
)
} /* Is p is :
????
Dekodirano po emi Cpl252: Neki t e k s t
Neki t e k s t
Neki t e k s t
* ///:-
Bafer sadri sirove bajtove, i da bismo njih pretvorili u znakove, moramo ih kodirati
prilikom stavljanja unutra (da bi neto znaili kada ih izvadimo iz bafera) ili dekodirati
prilikom vaenja iz bafera. To se moe postii klasom java.nio.charset.Charset koja
obuhvata alatke za kodiranje po raznim emama:
/ / : u i/D o s tu pn e S em e K o d ir a nja.ja v a
/ / P r ik a z u je eme k o d i r a n j a i n ji h o v e a l i j a s e
im p o r t j a v a . n i o . c h a r s e t . * ;
im p o r t j a v a . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s DostupneSemeKodir a n ja {
p u b l i c s t a t i c v o id m a in ( S t r i n g [] a r g s ) {
S o r te dM a p < S tring ,C h a rs e t> semeKodiranja =
Ch arset . a v a i l a b l e C h a r s e t s O ;
I t e r a t o r < S t r i n g > i t = semeKodir a n j a . ke y S e t( ) . i t e r a t o r ( ) ;
w h i1e ( i t ,h a s N e x t( ) ) {
S t r i n g imeSemeKodiranja = i t . n e x t ( ) ;
p r i ntnb(imeSemeKodi r a n j a ) ;
Ite ra to r a lija s i =
semeKodi r a n j a . g e t (imeSemeKodi r a n j a ) . a l i a s e s ( ) . i t e r a t o r ( ) ;
i f ( a l i j a s i .h a s N e x t( ) )
p rin tn b (": " );
w h i1e ( a l i j a s i . hasN ext( ) ) {
p rin tn b (a lija s i,n e x t());
i f ( a l i j a s i .h a s N e x t( ) )
p rin tn b C ', ");
}
pri nt ();
}
}
} / * Is p is :
B ig 5 : csBig5
Big5-HKSCS: b i g 5 - h k s c s , b ig 5 h k , b i g 5 - h k s c s : u n ic o d e 3 .0 , big 5 h ks cs , Big5_HKSCS
Poglavfje 18: Javin ulazno-izlazni sistem 759
* ///:-
Vratimo se na BaferUTekst.java. Ako bafer ,,premotate metodom rew in d () (da biste
se vratili na poetak podataka) i zatim za dekodiranje podataka metodom decode( )
upotrebite podrazumevanu emu kodiranja te platforme, dobiete CharBuffer koji se
lepo ispisuje na konzoli. Za pronalaenje podrazumevane eme kodiranja pozovite me-
todu System.getProperty("file.encoding") koja proizvodi znakovni niz s imenom te
eme kodiranja. Prosledite to metodi Charset.forN am e() i dobiete objekat tipa Charset
kojim se taj znakovni niz moe dekodirati.
Druga mogunost je da (metodom encode()) kodirate po emi kodiranja koja e dati
rezultat koji se moe tampati nakon itanja datoteke, kao to vidite u treem delu pro-
grama BaferUTekst.java. Tu je za pisanje teksta u datoteku upotrebljena ema kodirania
UTF-16BE, pa nakon itanja samo morate da je konvertujete u CharBuffer koji e dati
oekivani tekst.
Najzad, vidite ta se deava ako piete u ByteBuffer preko CharBuffer bafera (o tome
e jo biti rei). Baferu ByteBuffer dodelili smo 24 bajta. Poto svaki znak (char) zahteva
dva bajta, to je dovoljno za 12 znakova, ali Neki tekst ih ima samo 10. Preostali bajtovi
s nulama ipak se vide u prikazu CharBuffer bafera koji proizvodi njegova metoda
to S trin g (), kao to vidite iz ispisa rezultata.
Veba 23: (6) Napravite i ispitajte uslunu metodu koja tampa sadraj CharBufferbafera
sve do mesta od kojega se njegovi znaci vie ne mogu odtampati.
/ / : u i / D a jP o d a t k e . ja v a
/ / Tumaenje b a jt o v a i z B y te B u ffe ra na r a z l i i t e naine
im p o r t j a v a . n i o . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s DajPodatke {
p r i v a t e s t a t i c f i n a l i n t VELBAF = 1024;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) {
B y t e B u f f e r bb = B y t e B u f f e r . a l 1ocate(VELBAF);
// B y t e B u f f e r se automatski puni nulama im mu se d o d e li memorija:
i n t i = 0;
w h i 1e ( i + + < b b . 1 i m i t ())
760 Misliti na Javi
i f ( b b . g e t ( ) != 0)
p r in t( " n ije n u la ");
p rin t("i = " + i) ;
b b .re w in d ();
/ / U p i i i p r o i t a j n i z t i p a ch a r:
b b .a s C h a rB u ffe r().p u t("Z d ra v o !" ) ;
c h a r c;
w h i ! e ( ( c = b b . g e t C h a r ( ) ) != 0)
p rin tn b (c + " " );
p rin t();
b b .re w in d ();
/ / U p i i i p r o i t a j b r o j t i p a s h o r t :
b b .asS h o rtB u ffe r(),p ut((sho rt)4 7 1 1 4 2 );
p rin t(b b .g e tS h o rt());
b b .re w in d ();
/ / U p i i i p r o i t a j b r o j t i p a i n t :
b b .asIn tB u ffe r().p u t(9 9 4 7 1 1 4 2 );
p rin t(b b .g e tln t());
b b .re w in d ();
/ / U p i i i p r o i t a j b r o j t i p a lo n g :
bb.asLo n g B u ffe r().pu t(9 9 47 1 142);
p rin t(b b .g e tL o n g ());
b b .re w in d ();
/ / U p i i i p r o i t a j b r o j t i p a f l o a t :
b b .a s F lo a tB u ffe r().p u t(9 9 4 7 1 1 4 2 );
p rin t(b b .g e tF lo a t());
b b .re w in d ();
/ / U p i i i p r o i t a j b r o j t i p a do u ble:
b b . a s D o u b le B u f f e r ( ) . p u t (99471142) ;
p r i n t ( b b . g e t D o u b le ( ) ) ;
b b . rewi n d ( ) ;
}
} / * Is p is :
i = 1025
Z d r a v o !
12390
99471142
99471142
9 . 9471144E7
9 . 9471142 E7
* ///.-
Nakon doele memorije objektu tipa ByteBuffer, proverili smo da li su njegove vred-
nosti automatski postale nula - i jesu. Proitane su sve 1024 vrednosti (do kraja bafera
koji daje metoda lim it()), i sve su bile nula.
Vrednosti prostih tipova najlake je umetnuti u ByteBuffer pomou odgovarajuih
,,prikaza tog bafera koje daju metode asC harB uffer(), asShorlB uffer() itd., i zatim tre-
ba upotrebiti metodu p u t( ) tog prikaza. Upravo taj postupak smo primenili za sve proste
tipove podataka. Meu svim tim metodama, jedino je udna metoda p u t( ) za ShortBuf-
fer koja zahteva eksplicitnu konverziju tipa (a ona odseca i menja rezultujuu vrednost).
Nijedan od ostalih prikaza bafera u svojoj metodi p u t ( ) ne zahteva konverziju tipa.
Poglavlje 18: Javin ulazno-izlazni sistem 761
Baferi prikaza
Bafer prikaza omoguuje da ByteBuffer u pozadini posmatrate kroz prozor odreenog
prostog tipa. ByteBuffer je i dalje jedino skladite koje ,,podupire taj prikaz, pa se sve iz-
mene koje napravite u prikazu odraavaju u izmenama podataka u ByteBuffer baferu.
Kao to ste videli u prethodnom primeru, na raspolaganju su vam pomone metode za
umetanje prostih tipova u ByteBuffer. Prikaz omoguuje i itanje vrednosti prostih tipo-
va iz ByteBuffer bafera, bilo jednu po jednu (to ByteBuffer dozvoljava) bilo u grupama
(kao nizove). Evo primera kako se pomou klase IntBuffer radi s celim brojevima (int) u
ByteBuffer baferu:
p u b l i c c la s s I n t B u f f e r P r i m e r {
p r i v a t e s t a t i c f i n a l i n t VELBAF = 1024;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
B y t e B u f f e r bb = B y t e B u f f e r . a l 1ocate(VELBAF);
In tB u ffe r ib = b b .a s In tB u ffe r ( ) ;
/ / U s k l a d i t i n iz c e l i h b r o je v a :
i b . p u t ( n e w i n t [ ] { 11, 42, 47, 99, 143, 811, 1016 } ) ;
/ / i t a n j e i p is a n je sa /u a p s o lu tn e l o k a c i j e :
S y s te m .o u t.p rin tln (ib .g e t(3 ));
i b . p u t (3, 1811);
/ / Zadavanje novog k r a j a b a fe ra pre " p r e m o t a v a n ja " .
ib .fl ip ( ) ;
w h i1e (ib . h a s R e m a in in g ( ) ) {
in t i = ib .g e t();
S y s te m .o u t. p r i n t l n ( i ) ;
}
}
} /* Is p is :
99
11
42
47
1811
143
811
1016
* ///:-
odreeni tip proste vrednosti. U narednom prim eru se ista sekvenca bajtova redom tu-
mai kao broj tipa short, int, float, long i double, tako to se proizvode odgovarajui
baferi prikaza za isti ByteBuffer:
p u b l i c c la s s B a f e r i P r i k a z a {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
B y t e B u f f e r bb = B y t e B u f f e r . w r a p (
new b y t e [ ] { 0, 0, 0, 0, 0, 0, 0, ' a ' } ) ;
b b .re w in d ();
p rintn b ("B yte B u ffer " );
w h ile ( b b . h a s R e m a in in g ( ))
p r i n t n b ( b b . p o s i t i o n ( ) + " -> " + b b . g e t ( ) + " , " ) ;
p rin t();
C h a rB u ffe r cb =
( (B y te B u ffe r)b b .re w in d ()). a s C h a rB u ffe r();
p rintn b ("C h a rB u ffe r " ) ;
w h i1e(cb.hasRemai ni n g ( ) )
p r i n t n b ( c b . p o s i t i o n ( ) + " -> " + c b . g e t ( ) + " , " ) ;
p rin t();
F lo a tB u ffe r fb =
( ( B v t e B u f f e r ) b b . rewi n d ( ) ) . a s F l o a t B u f f e r ( ) ;
p rin tn b ("F lo a tB u ffe r " ) ;
w h i1e(fb .h a sR e m a in i n g ( ) )
p r i n t n b ( f b . p o s i t i o n ( ) + " -> " + f b . g e t ( ) + " , " ) ;
p rin t();
In tB u ffe r ib =
( (B y te B u ffe r)b b .re w in d ()) , a s I n tB u f fe r ( ) ;
p rin tn b ( " In tB u ffe r ");
w h i l e ( ib . h a s R e m a in in g ( ) )
p r i n t n b ( i b . p o s i t i o n ( ) + " -> " + i b . g e t ( ) + " , " ) ;
p rin t();
L o n g B u ffe r l b =
( ( B y t e B u f f e r ) b b . r e w i nd( ) ) . asLongBuff e r ( ) ;
p rin tn b ("L o n g B u ffe r " ) ;
w h i1e ( l b . hasRemaining ( ) )
p r i n t n b (1b . p o s i t i o n ( ) + " -> " + l b . g e t ( ) + " , ) ;
p rin t();
S h o r t B u f f e r sb =
((B y te B u ffe r)b b .re w in d ()).a s S h o rtB u ffe r();
p rintn b ("S h ortB u ffe r " ) ;
w h i1e(sb.hasRemai ni n g ( ) )
p r i n t n b ( s b . p o s i t i o n () + " -> " + s b . g e t ( ) + " , ) ;
p rin t();
D o u b le B u ffe r db =
((B y te B u ffe r)b b .re w in d ()) .a s D o u b le B u ffe r();
p rin tn b ("D o u b le B u ffe r " ) ;
Poglavlje 18: Javin ulazno-izlazni sistem 763
w h ile ( d b .h a s R e m a in in g ( ))
p r i n t n b ( d b . p o s i t i o n ( ) + 11 -> " + d b . g e t ( ) + " , ");
}
} /* Is p is :
B y t e B u f f e r 0 -> 0, 1 -> 0, 2 -> 0, 3 -> 0, 4 -> 0, 5 -> 0, 6 -> 0 , 7 -> 97,
C h a rB u ffe r 0 -> , 1 -> , 2 -> , 3 -> a,
F l o a t B u f f e r 0 -> 0 . 0 , 1 -> 1.36E-43,
I n t B u f f e r 0 -> 0, 1 -> 97,
L o n g B u ffe r 0 -> 97,
S h o r t B u f f e r 0 -> 0, 1 -> 0, 2 -> 0 , 3 - > 97,
D o u b le B u ffe r 0 -> 4.8E-322,
* ///:-
ByteBuffer je proizveen omotavanjem osmobajtnog niza tipa byte koji se zatim pri-
kazuje putem bafera prikaza svih prostih tipova. U narednom dijagramu prikazana su
razliita tumaenja istih bitova kada se itaju iz razliitih vrsta bafera:
Ovo odgovara ispisu rezultata programa.
0 0 0 0 0 0 0 97 bytes
a chars
0 0 0 97 shorts
0 97 ints
97 longs
4.8E-3 22 d oubles
Veba 24: (1) Izmenite program IntBufferPrimer.java tako da se koriste brojevi tipa
double.
Endiani
Podaci se na raznim raunarima skladite na razliite naine. Na big endian plat-
formama, najznaajniji bajt se smeta na najniu memorijsku adresu, dok se na little en-
dian platformama najznaajniji bajt smeta na najviu memorijsku adresu. Kada
skladitite vrednost veu od jednog bajta, kao to su int, float itd., morate uzeti u obzir re-
dosled bajtova. ByteBuffer skladiti podatke u big endian obliku, a tako se podaci uvek
alju i preko mree. Redosled smetanja bajtova podataka u ByteBufferu moete prome-
niti metodom order( ), uz argument ByteOrder.BIG_ENDIAN ili ByteOr-
der.LITTLE_ENDIAN.
764 Misliti na Javi
bl b2
/ / : u i/E n d ia n i.ja v a
/ / R a z lik e izmeu endiana i s k l a d i t e n j e podataka.
im p o r t j a v a . n i o . * ;
im p o r t j a v a . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s Endiani (
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) (
B y t e B u f f e r bb = B y t e B u ffe r .w ra p ( n e w b y te [ 1 2 ] ) ;
bb .asC ha rB u ffe r().pu t("ab cd e f");
p rin t(A rra y s .to S trin g (b b .a rra y ()) ) ;
b b .re w i n d ( ) ;
bb.ord e r(B y te O rd er.B IG _ E N D IA N );
b b .a sC ha rB u ffe r().pu t("ab cd e f" ) ;
p rin t(A rra y s . to S trin g (b b .a rra y ( ) ) ) ;
b b .re w in d ();
bb.ord e r(B y te O rd er.L ITT L E _ E N D IA N );
b b .a s C h a rB u ffe r().p u t("a b c d e f" ) ;
p rin t(A rra y s .to S trin g (b b .a rra y ()));
}
} / * Is p is :
[ 0 , 97, 0, 98, 0, 99, 0, 100, 0 , 101, 0 , 102]
[ 0 , 97, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102]
[9 7, 0, 98, 0, 99, 0, 100, 0, 101, 0, 102, 0]
* ///:-
ByteBuffer je dobio dovoljno prostora da sve bajtove uva u ni/.u znakova (charAr-
ray) kao spoljnom baferu, tako da se moe pozvati metoda array( ) da bi prikazala sve
bajtove. Metoda a rra y () je neobavezna i moete je pozvati za bafere poduprte nizom; u
protivnom, dobiete U nsupportedO perationException.
Pomou prikaza CharBuffer umee se charA rray u ByteBuffer. Nakon prikazivanja
svih bajtova uveriete se da je podrazumevani redosled jednak kasnijem eksplicitno po-
zvanom poretku big endian, dok redosled little endian zamenjuje bajtove.
Poglavlje 18: Javin ulazno-izlazni sistem 765
g e tC h a n n e l()
,w rite (B yte B u ffe r)
F ile C h a n n e l <- B yteB u ffer
rea d (By te B u ffe r)
~K\
m ap(F ileC hannel. M a p M o d e , position, size)
M a p p e d B y te B u ffe r
Detaljno o baferima
Bafer se sastoji od podataka i etiri indeksa za pristupanje tim podacima i delotvoran rad
s njima: marker, poloaj, kraj i kapacitet. Postoje metode za postavljanje vrednosti tih in-
deksa, za njihovo resetovanje i za ispitivanje njihovih vrednosti.
Ove indekse auriraju metode koje umeu i vade podatke iz batera. Tako indeksi
odraavaju izmene sprovedene u baferu.
U narednom primeru upotrebljen je veoma jednostavan algoritam (zamena susednih
znakova) da bi se ispreturali i ponovo vratili na mesta znakovi u CharBufferu:
//: u i/ U p o t r e b a B a f e r a . ja v a
im p ort j a v a . n i o . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s UpotrebaBafera {
p r i v a t e s t a t i c v o id s i m e t r i c n o P r e t u r a n j e ( C h a r B u f f e r b a f e r ) {
w hile (b afe r.h asR e m a in in g ()) {
b a fe r.m a rk();
ch ar c l = b a f e r . g e t ( ) ;
ch a r c2 = b a f e r . g e t ( ) ;
b a fe r.re s e tO ;
b a fe r.p u t(c 2 ).p u t(c l);
Poglavlje 18: Javin ulazno-izlazni sistem 767
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
c h a r [ ] podaci = " U p o t r e b a B a f e r a " . t o C h a r A r r a y ( ) ;
B y t e B u f f e r bb = B y t e B u f f e r . a l 1o c a t e ( p o d a c i .1 ength * 2 ) ;
C h a rB u ffe r cb = b b . a s C h a r B u f f e r ( ) ;
cb .p u t(p o d a c i);
p rin t(c b .re w in d ());
s im e tric n o P re tu ra n je (c b );
p rin t(c b .re w in d ());
s im e tri cn o P re tu ra n je (c b );
p rin t(c b .re w in d ( ) ) ;
}
} / * Is p is :
UpotrebaBafera
pUtoera baBefa r
UpotrebaBafera
* ///:-
Iako se CharBuffer moe napraviti neposredno metodom w ra p () od niza tipa char,
umesto toga smo memoriju dodelili ByteBufferu, a CharBuffer je napravljen kao prikaz
toga ByteBuffera. Time se istie da je cilj uvek koristiti ByteBuffer, poto on radi nepo-
sredno s kanalom.
Evo kako izgleda bafer na ulazu u metodu sim etricnoP returanje():
rwi
J
u p o t r e b a B a f e r a
i -i i
1ndeks poloaja pokazuje na prvi element bafera, a indeksi kapacitet i kraj na posiednji.
U metodi simetricnoPreturanjef ), petlja while iterira dok indeks poloaja ne doe do
vrednosti kraj. Indeks (tekueg) poloaja bafera se menja kada se pozovu relativne funk-
cije g e t( ) ili p u t( ) (pozivi bez argumenata). Moete pozivati i apsolutne metode g e t() i
p u t( ), sa indeksom poloaja elementa kao argumentom koji odreduje mesto na kojem se
odigrava vadenje (metodom g e t()) odnosno umetanje (metodom p u t()). Te (apsolutne)
metode ne menjaju vrenost indeksa poloaja bafera.
Kada kontrola ude u petlju while, vrednost indeksa m arker biva zadata pozivom me-
tode m a rk (). Tada je stanje bafera:
I m ,!r | 1 M -) 1
/ s/
U p O t r e b a B a f e r a
I ferai I
768 Misliti na Javi
Dva poziva relativne metode g e t() smetaju vrednost prva dva znaka u promenljive cl i
c2. Nakon ta dva poziva, bafer izgleda ovako:
I mar I I kap |
\/ \/
u p O t r e b a B a f e r a
/
1gg I I krai I
I mar I j kap |
N,/ s
u p o t r e b a B a f e r a
I Pol I I k ra j |
\/ \
p u o t r e b a B a f e r a
\
T
Tokom sledee iteracije petlje, indeksu marker se zadaje tekua vrednost indeksa po-
loaja:
\/ \/
P U o t r e b a B a f e r a
\
Postupak se nastavlja do prolaska kroz ceo bafer. Na kraju petlje vvhile, indeks poloaja
pokazuje na kraj bafera. Kada ispiete sadraj bafera, ispisuju se samo znakovi izmeu po-
loaja i kraja. Dakle, da biste ispisali ceo sadraj bafera, indeksu poloaja morate me-
todom rew in d () zadati vrednost poetka bafera. Evo stanja bafera nakon poziva metode
rew in d () (vrednost indeksa marker postaje nedefinisana):
Poglavlje 18: Javin ulazno-izlazni sistem 769
I tap I
\/
p u t o e r a b a B e f a r
/ \
I pol I I kraj |
Kada se ponovo pozove metoda sim etricn o P retu ranje(), CharBuffer se podvrgava
istom postupku i vraa u svoje prvobitno stanje.
/ / : u i / V e l i k e P r e s lik a v a n e D a to te k e .ja v a
/ / P r a v l j e n j e veoma v e l i k e d a tote ke pomou p r e s l i k a v a n j a .
/ / {RunByHand}
im p o rt j a v a . n i o . * ;
im p o r t j a v a . n i o . c h a n n e l s . * ;
im p o r t j a v a . i o . * ;
im p o rt s t a t i c n e t . m i n d v i ew.u t i 1 . P r i n t . * ;
p u b l i c c la s s V e lik e P re s lik a v a n e D a t o te k e {
s t a t i c i n t duzina = 0x8FFFFFF; / / 128 MB
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exce p tio n {
MappedByteBuffer i z l a z =
new R a n d o m A c c e s s F ile C t e s t . d a t " , " r w " ) .getChannel ()
,map(FileChannel.MapMode.READ_WRITE, 0, d u z in a ) ;
f o r ( i n t i = 0; i < d u z in a ; i++)
iz la z .p u t((b y te )' x ' );
p r i n t ( " P is a n je zavreno");
f o r ( i n t i = d u z in a /2 ; i < d u z in a /2 + 6; i+ + )
p rin tn b ((c h a r)iz la z .g e t(i) );
}
} III--
Da bismo obraili i itanje i pisanjc, poinjemo tako to pravimo (objekat tipa) Ran-
domAccessFile, pribavimo kanal za tu datoteku, i zatim pozovemo metodu n ia p () koja
proizvodi objekat tipa MappedByteBuffer, to je posebna vrsta direktnog bafera. Obra-
tite panju na to da moete zaati poetnu taku i duinu oblasti u datoteci koju elite da
preslikate; to znai da imate mogunost da preslikavate manje oblasti velikih datoteka.
MappedByteBuffer je izvedena iz klase ByteBuffer, pa ima sve njene metode. Ovde su
prikazane samo veoma jednostavne primene metoda p u t( ) i g e t(), ali na raspolaganju su
vam i metode kao asC harB uffer() itd.
770 Misliti na Javi
Performanse
Iako su performanse ,,starog U/I sistema zasnovanog na tokovima poboljane realizaci-
jom pomou nio klasa, obino se jo mnogo bre pristupa datotekama preslikanim u me-
moriju. U narednom programu uporeene su njihove performanse (na veoma
jednostavan nain):
I n t B u f f e r i b = fc .m a p (
FileChannel ,MapMode.READ_WRITE, 0, f c . s i z e O )
.a s In tB u ffe r();
ib .p u t(O );
f o r ( i n t 1 = 1; i < b r o j l lp is a U B a f e r ; i+ +)
ib .p u t( ib .g e t(i - 1 ));
fc .c lo s e ();
}
}
};
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) {
fo r(T e ste r te s t : is p itiv a n ja )
te s t.ru n T e s t();
}
} / * I s p i s : (90% podudaranja)
U p is iv a n je u t o k : 0.56
U p is iv a n je u p r e s l i k a n u : 0.12
i t a n j e t o k a : 0.80
i t a n j e p r e s l i k a n e : 0.07
i t a n j e i z t o k a / p i s a n j e u t o k : 5.32
i t a n j e i z p r e s l i k a n e / p i s a n j e u p r e s l i k a n u : 0.0 2
* ///:-
Kao to ste videli u prethodnim primerim a iz ove knjige, metoda runTest( ) je upo-
trebljena u projektnom obrascu Template M ethod (ablonska metoda) za pravljenje
strukture za ispitivanje raznih realizacija metode te s t( ) defmisanih u anonimnim unu-
tranjim potklasama. Svaka od tih potklasa obavlja jednu vrstu ispitivanja, pa te metode
te s t() predstavljaju i prototip za obavljanje raznih U/I operacija.
Premda izgleda kao da se za pisanje u preslikanu datoteku upotrebljava tok FileOut-
putStream, sav izlaz preslikanih datoteka mora upotrebljavati klasu RandomAccessFile,
ba kao itanje/pisanje u prethodnom kodu.
Obratite panju na to da te s t() metode obuhvataju i vreme za inicijalizaciju raznih U/I
objekata. Priprema preslikanih datoteka ume da bude skupa, ali je sveukupni dobitak
znaajan kada se uporedi sa stanjem pri korienju U/I sistema zasnovanih na toku.
Veba 25: (6) Napravite eksperiment tako to ete u primerima iz ovog poglavlja naredbu
ByteBuffer.aIlocate( ) promeniti u ByteBuffer.aIlocateDirect( ). Pokaite razlike u per-
formansama, i proverite da li se prim etno menja trajanje pokretanja programa.
Veba 26: (3) Izmenite program strings/JGrep.java tako da koristi Java nio datoteke
preslikane u memoriju po elovima.
Zakljuavanje datoteka
Zakljuavanje datoteka omoguuje sinhronizovanje pristupa datoteci kao deljenom re-
sursu. Medutim, dve niti koje se takmie za istu datoteku mogu biti u razliitim JVM-ovi-
ma ili jedna moe biti Java nit, a druga nit operativnog sistema. Zakljuavanje datoteka
vide ostali procesi operativnog sistema zato to se zakljuavanje Java datoteka direktno
preslikava u uslunu metodu operativnog sistema za zakljuavanje.
Poglavlje 18: Javin ulazno-izlazni sistem 773
/ / : u i/ Z a k l j u c a v a n j e D a t o t e k a . j a v a
im p o r t j a v a . n i o . c h a n n e l s . * ;
im p o r t j a v a . u t i l . c o n c u r r e n t . * ;
im p o r t j a v a . i o . * ;
p u b l i c c la s s Z a k lju c a v a n je D a t o t e k a {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exceptio n {
F ile O u tp u tS tre a m fos= new F i l e O u t p u t S t r e a m ( " d a t o t e k a . t x t " ) ;
F ile L o c k f l = f o s . g e t C h a n n e l( ) . t r y L o c k ( ) ;
i f ( f l != n u l 1) {
S yste m .o u t.p rin tln ("Z a k lju a n a d a to te k a ");
Timellnit.MILLISECONDS.sl e e p (lO O );
f l ,re le a s e ();
S y s t e m . o u t . p r i n t l n ( " O t k l ju a n a d a t o t e k a " ) ;
}
fo s .c lo s e O ;
}
} / * Is p is :
Z a k lju a n a d a tote k a
O t k lju a n a d a tote k a
* ///:-
Bravu (objekat tipa FileLock) cele datoteke dobijate pozivom metoda tryLock( ) ili
lock( ) za objekat tipa FileChannel. (SocketChannel, D atagram Channel i ServerSoc-
ketC hannel ne treba zakljuavati, poto su to po svojoj prirodi entiteti jednog procesa; po
pravilu se mrena utinica ne deli izmeu dva procesa.) tryL ock() je neblokirajua me-
toda. Ona e pokuati da prigrabi bravu za sebe, ali ako u tome ne uspe (kada neki drugi
proces ve ima tu bravu, a ona nije deljena), vratie se bez rezultata. Metoda lo c k () blo-
kira sve dok ne pribavi bravu (engl. lock), ili dok nit koja je pozvala lo c k () ne bude pre-
kinuta, ili dok se ne zatvori kanal za koji je metoda lock( ) pozvana. Brava se oslobaa
(preputa drugima) metodom FileLock.release().
Moe se zakljuati i deo (oblast) datoteke, i to pozivom:
ili
Podrku za iskljuive (engl. exclusive lock) ili deljene brave mora dati operativni sistem.
Ukoliko operativni sistem ne podrava deljene brave, a primi zahtev da napravi jednu
takvu, bie upotrebljena iskljuiva brava umesto deljene. Vrstu brave (deljena ili iskljui-
va) moete saznati kad pozovete metodu FileLock.isShared().
p u b l i c c la s s Z a k lj u c a v a n je P r e s lik a n ih D a t o t e k a {
s t a t i c f i n a l i n t DUZINA = 0x8FFFFFF; / / 128 MB
s t a t i c FileChannel f c ;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws E x ce p tio n {
fc =
new R a n d o m A c c e s s F ile ( " t e s t . d a t , " r w " ) .g e t C h a n n e l( ) ;
MappedByteBuffer i z l a z =
fc.map(FileChannel.MapMode.READ_WRITE, 0 , DUZINA);
f o r ( i n t i = 0; i < DUZINA; i+ + )
i z l a z . p u t ( ( b y t e ) ' x 1) ;
new Z a k l j u c a j l P r o m e n i ( i z l a z , 0, 0 + DUZINA/3);
new Z a k l j u c a j l P r o m e n i ( i z l a z , DUZINA/2, DUZINA/2 + DUZINA/4);
}
p r i v a t e s t a t i c c la s s Z a k lj u c a jl P r o m e n i extends Thread {
p r iv a te B yteB uffer baf;
p r i v a t e i n t po ce ta k, k r a j ;
Z a k l j u c a j l P r o m e n i ( B y t e B u f f e r mbb, i n t p o c e ta k , i n t k r a j ) {
t h i s . p o c e t a k = poceta k;
th is .k ra j = k ra j;
mbb.1i m i t ( k r a j ) ;
m b b .p o s itio n (p o c e ta k );
b a f = m b b . s li c e ( ) ;
p o c e ta k();
}
publ i c v o id r u n ( ) {
try {
/ / I s k l j u i v a brava bez p r e k la p a n ja :
F ile L o c k f l = f c . l o c k ( p o c e t a k , k r a j , f a l s e ) ;
S y s t e m . o u t . p r i n t l n ( " Z a k l ju c a n o : "+ pocetak +" do "+ k r a j ) ;
/ / Obavi izmene:
w h i l e ( b a f . p o s i t i o n ( ) < b a f . l i m i t ( ) - 1)
Poglav[je 18: Javin ulazno-izlazni sistem 775
b a f . p u t ( (by t e ) ( b a f . g e t ( ) + i ) ) ;
f l .re le a s e ();
S y s te m .o u t.p rin tln ("O tk lju c a n o : "+ pocetak +" do + k r a j ) ;
} c a t c h ( I 0 E x c e p t io n e) (
th ro w new R u n tim e E x c e p tio n ( e ) ;
}
}
}
} lll--~
Klasa niti ZakljucajlProm eni priprema oblast bafera i metodom slice() pravi odseak
(engl. slice) koji e biti izmenjen, a u metodi r u n ( ) pribavlja se brava za kanal datoteke (ne
moete pribaviti bravu bafera, nego samo kanala). Metoda lo ck () poziva se veoma slino
pribavljanju zakljuane niti objekta - sada imate kritinu sekciju sa iskljuivim pristu-
pom tom delu datoteke.5
Brave se otkljuavaju automatski kada JVM izae iii kada se zatvori kanai za koji je
brava pribavljena, ali za otkljuavanje objekta tipa FileLock moete i eksplicitno da po-
zovete metodu release() kao to je uraeno u prethodnom programu.
Komprimovanje
Javina U/I biblioteka sadri klase koje podravaju itanje i upisivanje tokova u kompri-
movanom formatu. Te klase treba omotati oko postojeih U/I klasa.
Ove klase nisu izvedene iz klasa Reader i Writer, ve su deo hijerarhija klasa Input-
Streain i O utputStream . Razlog je to to biblioteka za komprimovanje radi s bajtovima,
a ne sa znacima. Ipak, ponekad ete biti prim orani da kombinujete ove dve vrste tokova.
(Zapamtite da za jednostavnu konverziju izmeu ova dva tipa moete koristiti klase In-
putStream Reader i OutputStreamReader.)
Iako postoje mnogi algoritmi za komprimovanje, Zip i GZIP se verovatno najee ko-
riste. Zbog toga s komprimovanim podacima moete lako da radite pom ou brojnih alat-
ki za itanje i upisivanje u pomenutim formatima.
p u b l i c c la s s GZIPKomprimovanje {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
throvvs IO Exception {
i f ( a r g s . l e n g t h == 0) {
S y s t e m . o u t . p r i n t l n(
"U potreba: \nGZIPKomprimovanje d a t o t e k a \ n " +
" \ t U p o t r e b l ja v a GZIP komprimcvanje da bi komprimovao " +
" d a to te k u u t e s t . g z " ) ;
S y s te m .e x it(l);
}
Buffe redReader i n = new BufferedReaderf
new F i l e R e a d e r ( a r g s [ 0 ] ) ) ;
Bu ffe red O u tp u tS tre a m o u t = new B u fferedO utputStre am (
new GZIPOutputStream(
new F ile O u t p u t S t r e a m ( t e s t . g z " ) ) ) ;
S y s te m .o u t.p rin tln ("U p is u d a to te k u ");
i n t c;
w h i l e ( ( c = i n . r e a d ( ) ) != -1)
o u t.w ri-te (c );
in .c lo s e O ;
o u t.c lo s e O ;
S y s te m .o u t.p rin tln ("C ita n je d a to te k e ");
B u fferedReader in 2 = new Buffe red Reader(
new InputStreamReader(new GZIPInputStream(
new F i l e I n p u t S t r e a m ( " t e s t . g z " ) ) ) ) ;
S t r i n g s;
w h i l e ( ( s = i n2 . r e a d L i n e ( ) ) != n u l l )
S y s te m .o u t.p rin tln (s );
}
} /* ( P o k r e n it e da b i s t e v i d e l i re z u lta te ) *///:-
/ / : u i/ Z ip K o m p r im o v a n je . ja v a
/ / K o r i s t i fo rm a t Z ip za komprimovanje p r o i z v o l j n o g
/ / b r o j a d a to te k a k o j i se z adaje na komandnoj l i n i j i .
/ / ( A r g s : Zip K o m p rim ova n je .ja va }
im p o r t j a v a . i o . * ;
im p o r t j a v a . u t i l
im p o r t j a v a . u t i l . z i p . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s ZipKomprimovanje {
p u b l i c s t a t i c vo id m a i n ( S t r i n g [ ] args)
thro ws IOExce ption {
Fi 1eOutputStream f = new F i l e O u t p u t S t r e a m C t e s t . z i p " ) ;
CheckedOutputStream csum =
new Ch eckedOutp utStream (f, new A d l e r 3 2 ( ) ) ;
Z i pOutputStream zos = new Z ipO utputStream (csum );
Buffe red O u tp u tStre a m o u t = new B u ff e r e d O u t p u t S t re a m (z o s ) ;
zos.setComment("Proba pakovanja u fo rm a tu Z i p " ) ;
/ / Ip a k , nema odgovaraju e metode getComment().
f o r ( S t r i n g arg : args) {
p r i n t ( " U p i s u d a to te k u " + a r g ) ;
BufferedReader in =
new Buffe red Reader(
new F i 1e R e a d e r(a rg )) ;
z o s . p u t N e x t E n t r y (new Zi p E n t r y ( a r g ) ) ;
in t c;
w h i l e ( ( c = i n . r e a d ( ) ) != -1)
out.w ri t e ( c ) ;
i n .c lo se ();
o u t . f l ush( ) ;
}
o u t.c lo s e O ;
/ / K o n t r o l n i z b i r j e vaei tek po z a t v a r a n ju d a to t e k e !
p rin t(" K o n tro ln i z b ir: " + cs u m .g e tC h e c k s u m ().g e tV a lu e ()) ;
774 Misliti na Javi
Podrku za iskljuive (engl. exclusive lock) ili deljene brave mora dati operativni sistem.
Ukoliko operativni sistem ne podrava deljene brave, a primi zahtev da napravi jednu
takvu, bie upotrebljena iskljuiva brava umesto deljene. Vrstu brave (deljena ili iskljui-
va) moete saznati kad pozovete metodu FileLock.isShared().
p u b l i c c la s s Z a k lj u c a v a n je P r e s lik a n ih D a t o t e k a {
s t a t i c f i n a l i n t DUZINA = 0x8FFFFFF; / / 128 MB
s t a t i c FileChannel f c ;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws E x ce p tio n {
fc =
new R a n d o m A c c e s s F ile ( " t e s t . d a t" , " r w " ) . g e t C h a n n e l ( ) ;
MappedByteBuffer i z l a z =
f c . m a p ( F i 1eChannel.MapMode.READ_WRITE, 0, DUZINA);
f o r ( i n t i = 0; i < DUZINA; i+ + )
i z l a z.p u t((b yte ) x ' );
new Z a k lju c a j I P r o m e n i ( i z l a z , 0, 0 + DUZINA/3);
new Z a k l j u c a j l P r o m e n i ( i z l a z , DUZINA/2, DUZINA/2 + DUZINA/4);
}
p r i v a t e s t a t i c c la s s Z a k lj u c a jl P r o m e n i extends Thread {
p r iv a te B yteB uffer baf;
p r i v a t e i n t po ce ta k, k r a j ;
Z a k l j u c a j I P r o m e n i ( B y t e B u f f e r mbb, i n t p o ce ta k , i n t k r a j ) {
t h i s . p o c e t a k = po ce ta k;
th is .k ra j = k ra j;
mbb.1imi t ( k r a j ) ;
m b b .p o sitio n (p o ce ta k);
b a f = m b b . s li c e ( ) ;
p o c e ta k ();
}
p u b l i c vo id r u n ( ) {
try {
/ / I s k l j u i v a brava bez p re k la p a n ja :
F ile L o c k f l = f c . l o c k ( p o c e t a k , k r a j , f a l s e ) ;
S y s t e m . o u t . p r i n t l n ( " Z a k l ju c a n o : + poce tak +" do "+ k r a j ) ;
/ / Obavi izmene:
w h i l e ( b a f . p o s i t i o n ( ) < b a f . l i m i t ( ) - 1)
Poglavlje 18: Javin ulazno-izlazni sistem 775
Komprimovanje
Javina U/I biblioteka sadri klase koje podravaju itanje i upisivanje tokova u kompri-
movanom formatu. Te klase treba omotati oko postojeih U/I klasa.
Ove klase nisu izvedene iz klasa Reader i Writer, ve su deo hijerarhija klasa Input-
Streain i O utputStream . Razlog je to to biblioteka za komprimovanje radi s bajtovima,
a ne sa znacima. Ipak, ponekad ete biti prim orani da kombinujete ove dve vrste tokova.
(Zapamtite da za jednostavnu konverziju izmeu ova dva tipa moete koristiti klase In-
putStream Reader i OutputStreamReader.)
Iako postoje mnogi algoritmi za komprimovanje, Zip i GZIP se verovatno najee ko-
riste. Zbog toga s komprimovanim podam a moete lako da radite pomou brojnih alat-
ki za itanje i upisivanje u pom enutim formatima.
p u b l i c c la s s GZIPKomprimovanje {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s)
throws IOException {
i f ( a r g s . l e n g t h == 0) {
System. out. . p r i n t l n (
"Up otreba: \nGZIPKomprimovanje d a t o t e k a \ n " +
" \ t U p o t r e b l ja v a GZIP komprimovanje da bi komprimovao " +
" d a to te k u u t e s t . g z " ) ;
S y s te m .e x it(l);
}
Buffe redReader i n = new Buffe red Re a d e r(
new F ile R e a d e r ( a r g s [ 0 ] ) ) ;
B u ffe red O u tp u tS tre a m o u t = new B u fferedO utputStre am (
new GZIPOutputStream(
new F i l e O u t p u t S t r e a m ( " t e s t . g z " ) ) ) ;
S y s te m .o u t.p rin tln ("U p is u d a to te k u ");
i n t c;
w h i l e ( ( c = i n . r e a d ( ) ) != -1)
o u t.w ri-te (c );
in .c lo s e O ;
o u t.c lo s e ();
S y s t e m . o u t . p r i n t l n ( "C i t a n j e d a t o t e k e " ) ;
BufferedReader in 2 = new Buffe red R e a d e r(
new InputStreamReader(new GZIPInputStreamf
new F i 1e l n p u t s t r e a m ( " t e s t . g z " ) ) ) ) ;
S t r i n g s;
w h i l e ( ( s = i n 2 . r e a d L i n e ( ) ) != n u l l )
S y s te m .o u t.p rin tln (s );
}
} /* ( P o k r e n it e da b i s t e v i d e l i re z u lta te ) *///:-
/ / : u i/Z ip K o m p r im o v a n je .ja v a
/ / K o r i s t i fo rm a t Z ip za komprimovanje p r o i z v o l j n o g
/ / b r o j a d a to te k a k o j i se zadaje na komandnoj l i n i j i .
/ / { A rg s : Z ip K om prim ovanje .ja va)
im p o r t j a v a . i o . * ;
im p o r t j a v a . u t i l . * ;
im p o r t j a v a . u t i l . z i p . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s ZipKomprimovanje {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args)
thro ws IO Exception {
Fi 1eOutputStream f = new F i l e O u t p u t S t r e a m C t e s t . z i p " ) ;
CheckedOutputStream csum =
new Check edOutputStream ff, new A d l e r 3 2 ( ) ) ;
Z ipOutputStream zos = new Z ipO utputStream (csum );
BufferedO utputStre am o u t = new B u ff e r e d O u t p u t S t re a m (z o s ) ;
zos.setComment("Proba pakovanja u form atu Z i p " ) ;
/ / Ip a k , nema odgovarajue metode getComment().
f o r ( S t r i n g arg : args) {
p r i n t ( " U p i s u d a to te k u " + a r g ) ;
BufferedReader i n =
new Buffe redReader(
new F i l e R e a d e r ( a r g ) ) ;
z o s .p u tN e x tE n try (n e w Z i p E n t r y ( a r g ) ) ;
i n t c;
w h i l e ( ( c = i n . r e a d ( ) ) != -1)
out.w ri t e ( c ) ;
in .c lo s e ();
o u t . flu s h ( ) ;
}
o u t.c lo s e O ;
/ / K o n t r o l n i z b i r j e vaei te k po z a t v a r a n ju d a t o t e k e !
p r i n t ( " K o n t r o l n i z b i r : " + csu m .g e tC h e c k su m ().g e tV a lu e ()) ;
778 Misliti na Javi
Metodi putN extE ntry( ) m orate da prosledite objekat klase ZipEntry za svaku datote-
ku koja se doaje u arhivu. Takav objekat sadri obim an interfejs koji om oguuje itanje i
zadavanje svih podataka o datom elem entu Zip datoteke; ime, kom prim ovana i nekom -
prim ovana veliina, datum , kontrolni zbir, dodatna polja podataka, komentar, rnetoda
kompresije i da li se radi o stavki direktorijum a. M edutim , Javina biblioteka ne podrava
uvoenje lozinke iako je form at Zip om oguuje. Pored toga, mada klase C lieckedlnput-
Stream i CheckedOutputStream podravaju oba tipa kontrolnih zbirova (Adler32 i
CRC32), klasa ZipEntry podrava sam o interfejs za kontrolni zbir tipa CRC. To ogranie-
nje nam ee form at Zip, ali zbog toga se ne moe koristiti bri algoritam Adler32.
Klasa Z ipInputStream ima m etodu getN extE ntry( ) za raspakivanje arhive. Ta meto-
da vraa sledei objekat klase ZipEntry ako on postoji. Postoji i kraa varijanta - proi-
tajte datoteku pom ou klase ZipFile koja im a m etodu en trie s( ), a ona vraa objekat tipa
Enum eration u kojem su nabrojani objekti klase ZipEntries.
Da biste proitali kontrolni zbir, m orate na neki nain da obezbedite pristup odgova-
rajuem objektu klase Checksum. Pri tom se zadrava referenca na objekte tipa Checke-
dO utputStream i CheckedlnputStream , ali m oete da se oslonite i na referencu na
objekat tipa Checksum.
Z bunjujua m etoda u Zip tokovim a je setC om m ent( ). Kao to je pokazano u gornjem
prim eru, prilikom upisivanja u datoteku m oete da stavite komentar, ali ne postoji nain
Poglavlje 18: Javin ulazno-izlazni sistem 779
O pcije su sam o zbirka slova (nisu neophodne crtice ili neki drugi pom oni znaci). Ko-
risnici Unixa/Linuxa prim etie slinost s alatkom tar. Opcije su:
Ako spisak datoteka koje treba arhivirati sadri poddirektorijum , taj poddirektorijum
se autom atski arhivira sa svim svojim poddirektorijum im a itd. uvaju se i inform acije o
putanji.
780 Misliti na Javi
Evo nekih tipinih naina za korienje program a jar. Sledea kom anda pravi JAR ar-
hivu mojaJarDatoteka.jar koja sadri sve datoteke s klasam a u tekuem direktorijum u,
kao i autom atski generisanu m anifest datoteku:
Sledea kom anda radi isto to i p reth o d n i prim er, ali ukljuuje i korisniki napravljenu
manifest datoteku mojManifest.mf:
N aredna kom anda daje sadraj arhive m ojaJarD atoteka.jar u obliku liste datoteka:
j a r t f m ojaJarD atoteka.jar
Ako napravite JAR datoteku korienjem opcije o (nula), moi ete da je stavite u pu-
tanju klasa:
CL AS SP AT H= "1 ib l. ja r;l ib 2. ja r;
Nakon toga Java moe da trai datoteke s klasama u bibliotekam a lib l.jar i lib2.jar.
Alatka jar nije toliko korisna kao usluni program zip. Na prim er, ne m oete da doda-
jete ili aurirate datoteke u postojeoj JAR arhivi, tj. ovakve arhive m orate da pravite ,,od
nule. Takode, datoteke ne moete da prem etate u JAR arhivu i da ih nakon prem etanja
briete. M eutim , JAR datoteku, koja je napravljena u jednoj platform i, moi e da pro-
ita alatka ja r na bilo kojoj drugoj platform i, to je problem koji ponekad mui uslune
program e zip.
Kao to ete videti u poglavlju Grafika korisnika okruenja , JAR arhive se koriste i za
pakovanje zrna Jave.
Serijalizovanje objekata
Kada napravite objekat, on postoji onoliko dugo koliko vam je potreban, ali ni pod kojim
okolnostim a ne moe postojati kada program prestane da se izvrava. Koliko god da to
isprva im a smisla, lm a situacija u kojim a bi bilo izvanredno korisno kada bi objekat
m ogao da postoji i sauva svoje inform acije ak i kada se program ne izvrava. Tada bi ob-
jekat postojao i kada se program pokrene sledei put, i sadrao bi iste inform acije koje je
imao i kada se program izvravao pretho dn i put. Naravno, to m oete postii upisivanjem
inform acija u datoteku ili bazu podataka, ali u duhu politike da sve treba da bude objekat,
Poglavlje 18: Javin ulazno-izlazni sistem 781
bilo bi veom a pogodno deklarisati da je odredeni objekat ,,trajan, a da se Java p ri tom au-
tom atski pobrine za sve pojedinosti.
Serijalizovanje objekata u Javi om oguuje pretvaranje svakog objekta koji realizuje in-
terfejs Serializable u niz bajtova iz kojeg se taj objekat kasnije moe p o tp u n o rekonstru-
isati. To vai ak i u m ream a, to znai da m ehanizam serijalizovanja autom atski
kom penzuje razlike izm eu operativnih sistema. Dakle, m oete da napravite neki objekat
na raunaru koji radi pod W indow som , serijalizujete ga i poaljete preko mree na Unix
raunar gde e on biti pravilno rekonstruisan. Ne m orate da brinete o predstavljanju
objekata na razliitim raunarim a, redosledu bajtova niti o drugim detaljima.
Samo po sebi, serijalizovanje objekata je zanimljivo zato to om oguuje realizovanje
lake trajnosti (engl. lightw eight persistence). Setite se da trajnost znai kako ivotni vek
objekta nije odreen izvravanjem program a, ve objekat ivi i izm e u izvravanja pro-
grama. Efekat trajnosti moete da postignete upisivanjem serijalizovanog objekta na disk
i njegovim rekonstruisanjem pri ponovnom pozivanju program a. Epitet laka potie otud
to ne m oete da definiete objekat p om ou neke rezervisane rei za trajnost i da prepu-
stite sistem u da brine o detaljim a (iako e i to m oda jednog dana biti m ogue). Umesto
toga, m orate eksplicitno da serijalizujete i deserijalizujete objekat u program u. Ukoliko
vam treba ozbiljniji m ehanizam trajnosti, razm otrite alatku H ibernate ( h ttp ://h ib ern a -
te.sourceforgc.net). Vie inform acija o njoj potraite u knjizi T hin king in Enterprise Java,
koja se m oe preuzeti sa adrese w w w .M in d V iew .n et.
Serijalizovanje objekata je odato u jezik radi podrke dvema vanim funkcijama. Ja-
vino daljinsko pozivanje m etoda (engl. reniote m eth o d invocation, R M I) om oguuje objek-
tim a na drugim raunarim a da se ponaaju kao da se nalaze na vaem raunaru. Pri slanju
poruka udaljenim objektim a, serijalizovanje je neophodno da bi se preneli argum enti i
povratne vrednosti. Daljinsko pozivanje m etoda objanjeno je u knjizi T h in kin g in Enter-
prise Java.
Serijalizovanje objekata je neophodno i za zrna Jave, o em u e biti rei u poglavlju
Grafika korisnika okruenja. Kada se koristi zrno, inform acije o njegovom stanju po pra-
vilu se podeavaju ve tokom projektovanja. O ne se m oraju sauvati i rekonstruisati ka-
snije, kada se program pokrene. Taj zadatak obavlja serijalizovanje objekata.
Serijalizovanje objekta je prilino jednostavno, pod uslovom da on realizuje interfejs
Serializable (ovaj interfejs je sam o indikator i nem a m etode). Kada je serijalizovanje do-
dato u jezik, m noge klase standardne biblioteke prom enjene su da bi ga podrale, uklju-
ujui i om otae za proste tipove, sve kontejnerske klase i m noge druge. Mogu se
serijalizovati ak i objekti klase Class.
Da bi se objekat serijalizovao, treba napraviti neku vrstu izlaznog toka i om otati ga unu-
tar objekta klase ObjectOutputStream. Nakon toga treba sam o pozvati m etodu write-
Object( ) i objekat e biti serijalizovan i poslat u izlazni tok. (Serijalizovanje objekata je
binarno orijentisano i zbog toga koristi hijerarhije klasa InputStream i O utputStream .)
Za ob rn u t postupak, objekat klase InputStream se om otava u n u tar objekta tipa Object-
InputStream i poziva se m etoda readO bject( ). Kao i obino, dobija se referenca na obje-
kat klase Object, pa je neophodna konverzija nanie u ispravan tip.
Posebno pam etno reenje prim enjeno u serijalizovanju objekata jeste to to se pored
uvanja slike objekta prate i sve reference koje on sadri, a uvaju se i ti objekti, prate se
782 Misliti na Javi
njihove reference itd. Ovaj princip se ponekad naziva m rea objekata povezana s jed-
nim objektom , i ona sadri niz referenci na objekte i njihove lanove. Kada biste m orali da
odravate sopstvenu em u za serijalizovanje, bilo bi preteko napisati kod koji bi pratio
sve veze. Izgleda da serijalizovanje objekata u Javi om oguuje da se to postigne bez po
muke, verovatno korienjem optim izovanog algoritm a koji krstari po mrei objekata. U
sledeem prim eru testira se m ehanizam serijalizovanja pravljenjem ,,crva od povezanih
objekata, pri em u svaki pokazuje na sledei segm ent crva i sadri niz referenci na objekte
drugaije klase, nazvane Podatak:
//: ui/Crv.java
// Prikazuje serijalizaciju objekata.
import java.io.*;
import j a v a . u t i l .*;
import static ne t. mi nd vi ew .u ti l.Print.*
rezultat.append(sledeci);
return rezultat.toString( );
}
public static void main(String[] args)
throws ClassNotFoundException, IOException {
Crv w = new Crv(6, 'a');
pri nt("w = " + w);
ObjectOutputStream out = new ObjectOutputStream(
new Fi le Ou tputStreamC'crv.out"));
ou t. wr iteObject("Pamcenje cr v a \ n " ) ;
o u t. wr it eO bj ec t( w);
out.close(); // Prelazi u sledeci red
ObjectlnputStream in = new ObjectInputStream(
new Fi leInputStream("crv.out"));
String s = (String)in.readObject();
Crv w2 = (Crv)in.readObject();
pri nt(s + "w2 = " + w 2 ) ;
By teArrayOutputStream bout =
new By te Ar ra yO ut pu tS tr eam ();
ObjectOutputStream out2 = new O b j e ct Ou tp ut St re am (bo ut );
out2.write0bject("Pamcenje c r va \n ");
out2 .w ri te 0b je ct (w );
o u t 2 . f l u s h ();
ObjectlnputStream in2 = new ObjectInputStream(
new ByteArrayI np ut St re am( bo ut.t o B y t e A r r a y ()));
s = (Strin g ) in 2 .re ad Ob je ct();
Crv w3 = (Crv)in 2. re ad Ob je ct();
print(s + "w3 = " + w 3 ) ;
}
} /* Ispis:
Konstruktor crva: 6
Konstruktor crva: 5
Konstruktor crva: 4
Konstruktor crva: 3
Konstruktor crva: 2
Konstruktor crva: 1
w = :a (8 53):b(119):c (802) :d (788):e(199):f(881)
Pamcenje crva
w2 = :a (853):b (119):c(802):d(788):e (199):f(881)
Pamcenje crva
w3 = : a ( 8 5 3 ) :b(1 1 9 ) : c ( 8 0 2 ) : d ( 7 8 8 ) : e ( 1 9 9 ) : f (8 8 1 )
* ///:-
Pronalaenje klase
Moda se pitate ta je potrebno da bi se objekat rekonstruisao iz serijalizovanog stanja. Na
prim er, pretpostavim o da ste serijalizovali objekat i poslali ga nekoin drugom raunaru
kao datoteku ili preko mree. Da li bi program na drugom raunaru mogao da rekonstru-
ie objekat sam o na osnovu sadraja datoteke?
Najbolji nain da se odgovori na ovo pitanje jeste, kao i obino, da se proba. Sledea
datoteka treba da se smesti u poddirektorijum ovoga poglavlja:
//: ui/Zeleni.java
// Klasa koja se moe serijalizovati.
import java.io.*;
public class Zeleni implements Serializable {} ///:-
Datoteka koja pravi i serijalizuje objekat klase Zeleni nalazi se u istom direktorijum u:
//: ui/ZamrzavanjeZelenog.java
// Pravi serijalizovanu izlaznu datoteku.
import java.io.*;
izlaz.writeObject(zorcon);
}
} ///= -
Um esto da hvata i obrauje izuzetke, ovaj program ih iz m etode m a in ( ) prosleuje na
konzolu.
Kada prevedete i pokrenete program , on e dobijenu datoteku dosije.X sm estiti u di-
rektorijum ui. U njegov p oddirektorijum dosijex stavite sledei listing:
//: ui/dosijex/MaliZeleni.java
// Pokuaj da se serijalizovana datoteka rekonstruie
// bez klase objekata uskladitenih u toj datoteci.
// {RunByHand}
import java.io.*;
Upravljanje serijalizovanjem
Kao to vidite, podrazum evani m ehanizam serijalizovanja lako se koristi. M eutim , ta
ako im ate specijalne potrebe? Moda posebno brinete o bezbednosti i zato ne elite da se-
rijalizujete delove objekta, ili m oda nem a smisla da se neki podobjekat serijalizuje ako e
m orati ponovo da se pravi kada se objekat bude rekonstruisao.
Postupak serijalizovanja moete da kontroliete realizovanjem interfejsa Externaliza-
ble um esto interfejsa Serializable. Interfejs Externalizable proiruje interfejs Serializa-
ble i dodaje m u dve m etode, writeExternal( ) i readExternal( ), koje se autom atski
pozivaju tokom serijali/ovanja i deserijalizovanja objekta, da bi omoguile izvravanje
specijalnih operacija.
Sledei prim er prikazuje jednostavne realizacije m etoda interfejsa Externalizable.
Klase Blipl i Blip2 su skoro iste, a malu razliku izm eu njih prim etiete ako prouite kod:
786 Misliti na Javi
//: ui/Blipovi.java
// Jednostavno korienje interfejsa Externa1izable i jedna zamka.
import java.io.*;
import static net.mindview.util.Print.*;
//: u i / B 1 i p 3 .java
// Rekonstruisanje objekta externalizable.
import java.io.*;
import static net. mi nd vi ew .u ti1 .P r i n t .*;
throws IOException {
print("Bl ip3.wri teExternal11) ;
// Ovo morate da uradite:
out.writeObject(s);
out.writeInt(i);
}
public void readExternal(Objectlnput in)
throws IOException, ClassNotFoundException {
print("Blip3.readExternal");
// Ovo morate da uradite:
s = (String)in.readObject();
i =in.readlnt();
}
public static void main(String[] args)
throws IOException, ClassNotFoundException {
print("Pravljenje objekata:");
Blip3 b3 = new B1 ip3( tekst 11 , 47);
print(b3);
ObjectOutputStream o = new ObjectOutputStream(
new FileOutputStream("Bli p3.out"));
print("Snimanje objekta:");
o.wri te0bject(b3);
o. c los e O;
// Sada ga vraamo:
ObjectlnputStream in = new ObjectInputStream(
new FileInputStream("Blip3.out"));
print("Rekonstruisanje b3:");
b3 = (Blip3)in.readObject();
print(b3);
}
} /* Ispis:
Pravljenje objekata:
Blip3(String x, int a)
tekst 47
Snimanje objekta:
B1ip3.writeExternal
Rekonstruisanje b3:
Konstruktor za B1ip3
B1ip3.readExternal
tekst 47
* ///:-
Da bi sve radilo kako treba, znai da, pored upisivanja vanih podataka iz objekta to-
kom izvravanja m etode w riteE xternal( ) (ne postoji podrazum evano ponaanje kojim
se upisuju bilo koji lanovi objekta interfejsa Externalizable), m orate i da rekonstruiete
te podatke u m etodi readE xternal( ). To isprva m oe da zbuni zato to bi ponaanje pod-
razum evanog konstruktora objekta Externalizable m oglo stvoriti pogrean utisak da se
neka vrsta pam enja i rekonstruisanja deava autom atski. To se ne deava.
Veba 28: (2) U program u Blipovi.java kopirajte datoteku i preim enujte je u ProveraBli-
pova.java. Preimenujte i klasu Blip2 u ProveraBlipova (prepravite je u javnu, a ispred kla-
se Blipovi uklonite oznaku public) . U klonite oznake //! iz datoteke i izvrite novi program .
Potom postavite znakove za kom entar ispred podrazum evanog konstruktora za klasu Pro-
veraBlipova. Izvrite program i objasnite zato radi. O bratite panju na to da nakon pre-
voenja m orate da izvrite program sa java Blipovi" zato to se m etoda m a in ( ) i dalje
nalazi u klasi Blipovi.
Veba 29: (2) U program u Blip3.java, pretvorite u kom entar po dva reda iza reenica
Ovo m orate da uradite: i pokrenite program . O bjasnite rezultat i zato se on razlikuje
od sluaja kada su ta dva reda u program u.
Rezervisana re transient
Ako upravljate serijalizovanjem, m oda neete eleti da Javin m ehanizam serijalizovanja
autom atski snim a i rekonstruie neki podobjekat. To je esto sluaj kada se u podobjektu
uvaju poverljive inform acije koje ne elite da serijalizujete, npr. lozinka. ak i ako je ta-
kva inform acija u objektu privatna, nakon serijalizovanja neko bi mogao da je proita iz
datoteke ili da je presretne prilikom prenosa preko mree.
Jedan nain za spreavanje serijalizovanja osetljivih delova objekta jeste da se klasa re-
alizuje kao Externalizable, kao to je upravo pokazano. Na taj nain nita se ne serijali-
zuje autom atski, to jest moete eksplicitno da serijalizujete sam o neophodne delove
u n u tar m etode w riteE x te rn a I().
M eutim , ako radite sa objektom tipa Serializable, serijalizacija se obavlja autom at-
ski. Da biste to kontrolisali, serijalizovanje bilo kog elem enta m oete da iskljuite rezer-
visanom reju tran sien t, koja kae: Nemoj da se trudi da ovo rekonstruie - ja u se
postarati za to.
Na prim er, posm atrajm o objekat P rijavljivanje koji uva inform acije o odreenom
prijavljivanju na sistem. Pretpostavim o da nakon provere ispravnosti prijavljivanja elite
da snim ite podatke, ali bez lozinke. To je najlake uraditi tako to se im plem entira (reali-
zuje) interfejs Serializable a polje lozin ka oznai kao tra n sie n t. Evo kako to izgleda:
S take gledita program iranja, ovo je prilino udno. Prvo m oete pom isliti da te me-
tode, poto nisu deo osnovne klase ili interfejsa Serializable, treba da b u d u definisane u
sopstvenim interfejsima. O bratite panju na to da su one definisane kao privatne, to zna-
i da treba da ih pozivaju sam o drugi lanovi iste klase. M eutim , njih ne pozivaju drugi
lanovi klase, ve m etode writeObject( ) i readO bject( ) klasa ObjectO utputStream i
ObjectlnputStream . (Izuzetno se trudim da se ne uputam u iscrpljujuu raspravu o
istim im enim a m etoda. Objanjenje: sam o bih vas zbunio.) M oda se pitate kako objekti
klasa ObjectO utputStream i O bjectlnputStream im aju pistup privatnim m etodam a
vae klase. M oemo sam o pretpostaviti da je to deo maginog postupka serijalizovanja.6
U svakom sluaju, sve to se definie u interfejsu podrazum evano je javno, pa ako meto-
de w riteO bject( ) i readO bject( ) m oraju da budu privatne, one ne m ogu biti deo interfejsa.
Poto m orate tano da se pridravate potpisa, uinak je isti kao da realizujete interfejs.
Izgleda kao da se posle poziva m etode O bjectO utputStream .w riteObject( ) objekat
interfejsa Serializable koji joj prosleujete ispituje (bez sum nje, korienjem refleksije)
kako bi se ustanoviio cia li realizuje sopstvenu m etodu w riteO b ject( ). Ako je tako, pre-
skae se uobiajeni postupak serijalizacije i poziva nam enska m etoda w riteO bject( ). Isto
vai i za m etodu readO bject( ).
Postoji jo jedna zakoljica. U nutar m etode w riteO bject( ) koju piete moete da izve-
dete podrazum evanu akciju upisivanja objekta pozivom m etode defaultW riteO bject( ).
Slino, unutar m etode readO bject( ) moete da pozovete m etodu defaultR eadO bject( ).
Evo jednostavnog prim era koji pokazuje kako m oete da upravljate uvanjem i rekon-
struisanjem objekta koji realizuje interfejs Serializable:
private String a;
private transient String b;
public Ko nt ro laSerijalizovanja(String aa, String bb) {
a = "Nije transient; " + aa;
b = "transient: " + bb;
}
public String t o S t r i n g O { return a + \n" + b; }
private void w r it eO bj ec t( Ob je ct Out pu tS tr ea m tok)
throws IOException {
t o k . de fa ul tW ri te Ob jec t( );
t o k. wr it e O b j e c t ( b ) ;
}
private void re ad Ob je ct (ObjectInputStream tok)
throws IOException, Cl assNotFoundException {
t o k. de fa ul tR ea dO bj ect ();
b = (Str in g) to k. re ad Ob jec t( );
}
public static void main(String[] args)
throws IOException, C1 assNotFoundException {
KontrolaSerijalizovanja sc = new Ko ntrolaSerijal izovanja("Testl",
"T e s t 2 " ) ;
System.out.println("Pre:\n" + sc);
By te Ar ra yO ut pu tS tr eam buf = new B y te Ar ra yO ut pu tS tr eam ();
Obje ct Ou tp ut St re am o = new Ob j e c t O u t p u t S t r e a m ( b u f ) ;
o. wr i t e O b j e c t ( s c ) ;
// Sada ga vraamo:
Object ln pu tS tr ea m in = new ObjectInputStream(
new By t e A r r a y In pu tS t r e a m ( b u f .t o B y t e A r r a y ()));
KontrolaSerijalizovanja sc2 = (KontrolaSerijalizovanja)
in.readObjectO;
Sy st em .o ut.println("Posle:\n" + sc2);
}
} /* Ispis:
Pre:
Nije transient: Testl
transient: Test2
Posle:
Nije transient: Testl
transient: Test2
* ///:-
U ovom p rim eru jedno polje tipa String je obino, a drugo je oznaeno kao transient
kako bi se dokazalo da m etoda defaultW riteO bject( ) snim a i rekonstruie polje koje nije
transient, a da se transient polje snim a i rekonstruie eksplicitno. Polja se inijalizuju n
konstruktoru, a ne prilikom definisanja, kako bi se dokazalo da se ne inicijalizuju nekim
autom atskim m ehanizm om tokom deserijalizovanja.
Ako nam eravate da koristite podrazum evani m ehanizam za upis delova objekta koji
nisu oznaeni sa transient, m orate da pozovete m etodu efaultW riteObject( ) kao prvu
operaciju u m etodi w riteO bject( ), odnosno m etodu defaultReadObject( ) kao prvu ope-
raciju u m etodi readO bject( ). To su udni pozivi metoda. Izgledalo bi, na primer, kao da
Poglavlje 18: Javin ulazno-izlazni sistem 793
o.writeObject(sc);
Zadavanje verzije
M oda ete hteti da prom enite verziju klase koja se m oe serijalizovati (na prim er, objekti
originalne klase m ogu biti uvani u bazi podataka). To je podrano u favi, ali ete to raditi
sam o u specijalnim sluajevima, a pri tom m orate bolje razum eti problem , to ovde nee-
mo razm atrati. HTM L dokum entacija razvojnog paketa za Javu koja se m oe preuzeti
s lokacije http:lljava.sun .co m , detaljno obrauje ovu temu.
U ovoj dokum entaciji uoiete m noge kom entare koji poinju sa:
U pozorenje: Serijalizovani objekd ove klase nee biti ko m p a tib iln i s buduim verzijam a
Svvinga. T renutna podrka serijalizaciji pogodna je za kratkotrajno uvanje m etoda koje se
pozivaju daljinski u raznim aplikacijam a...
Ovo upozorenje stoji zato to je m ehanizam dodeljivanja verzije previe jednostavan
da bi pouzdano radio u svim situacijam a, naroito sa zrnim a Jave. Radi se na ispravci pro-
jekta, o em u upravo i govori ovo upozorenje.
Korienje trajnosti
Tehnika serijalizovanja je prilino privlana za uvanje stanja nekog program a da bi se on
kasnije m ogao lako vratiti nazad. M eutim , pre toga, m ora se odgovoriti na neka pitanja.
ta e se desiti ako se serijalizuju dva objekta, a svaki od njih sadri referencu na trei
objekat? Kada rekonstruiete ta dva objekta iz serijalizovanog stanja, da li e se trei obje-
kat pojaviti sam o jednom ? ta e se desiti ako se dva objekta serijalizuju u zasebne dato-
teke, a potom deserijalizuju u razliitim delovima koda?
Evo prim era koji prikazuje ovaj problem:
//: ui/MojSvet.java
import java.io.*;
import j a v a . u t i 1.*;
import static n e t .mindview.uti1 .P r i n t .*;
794 Misliti na Javi
//: ui/PamcenjeCADStanja.java
// Pamenje stanja nazovi-CAD sistema.
import java.io.*;
import j a v a . u t i l .*;
796 Misliti na Javi
Klasa Oblik realizuje interfejs Serializable, pa se sve to se izvodi iz klase Oblik auto-
matski m oe serijalizovati. Svaki objekat klase Oblik sadri podatke, a svaka klasa izvede-
na iz klase Oblik sadri statiko polje koje odreuje boju svih figura izvedenog tipa.
(Stavljanje statikog polja u osnovnu klasu dalo bi samo jedno polje, poto se statika
polja ne dupliraju u izvedenim klasama.) M etode osnovne klase se m ogu redefinisati da bi
se zadala boja razliitih tipova oblika (za statike m etode se ne prim enjuje dinam iko po-
vezivanje, tj. radi se o obinim m etodam a.) M etoda slucajnoG enerisanje( ), kad god se
pozove, pravi razliit objekat tipa Oblik tako to nasum ino bira tip oblika.
Klase Krug i Kvadrat jednostavna su proirenja klase Oblik; razlikuju se sam o po
tom e to se u klasi Krug boja inicijalizuje tokom definisanja, a u klasi Kvadrat - u kon-
struktoru. O dloiem o razm atranje klase Linija.
U funkciji m a in ( ) koristi se jedna lista tipa ArrayList za uvanje objekata tipa Class i
jo jedna za uvanje oblika.
R ekonstrukja objekata je prilino jednostavna:
//: ui /R ekonstruisanjeCADStanja.java
// Rekonstruisanje stanja nazovi-CAD sistema.
// {RunFirst: PamcenjeCADStanja}
import java.io.*;
import j a v a . u t i l .*;
Vidi se da se vrednosti xPos, yPos i dim uspeno snim aju i rekonstruiu, ali neto nije
u redu sa rekonstruisanjem statikih informacija. Sve tri ulaze, ali ne izlaze neprom enje-
ne. Krugovi im aju vrednost 1 (CRVENA, po definiciji), a kvadrati im aju vrednost 0 (se-
tite se da su inicijalizovani u konstruktoru). Izgleda kao da se statika polja uopte nisu
serijalizovala! To je tano: iako klasa Class moe da se serijalizuje, ona ne radi ono to se
oekuje. Znai, ako elite da serijalizujete statike podatke, to m orate da uradite sami.
U tu svrhu slue statike m etode serijalizujStaticke( ) i deserijalizujStaticke( ) klase
Linija. V idite da se one eksplicitno pozivaju u postup ku snim anja i rekonstruisanja.
(O bratite panju na to da m ora biti odran redosled upisivanja i itanja iz datoteke za se-
rijalizaciju.) Dakle, da bi ovi program i radili ispravno, m orate da:
1 . D odate m etode serijalizujStaticke() i deserijalizujStaticke() u sve klase oblika.
2. U klonite listu tipo viO b lika i kod koji je povezan s tom listom.
3. U oblike dodate pozive novih statikih m etoda za serijalizovanje i deserijalizovanje.
Bezbednost je jo jedna tem a o kojoj bi valjalo razmiljati, poto se serijalizovanjem
uvaju i privatni p o d a . Ako imate problem s bezbednou, ta polja treba da oznaite kao
tra n sie n t. M edutim , tada m orate da smislite bezbedan nain za uvanje poverljivih in-
form acija tako da prilikom rekonstruisanja m oete da vratite privatne prom enljive u pr-
vobitno stanje.
Veba 30: (1) Popravite program CA D Stanje.java kako je opisano u tekstu.
XML
Vano ogranienje serijalizovanja objekata jeste njihova iskljuiva upuenost na Javu:
takve objekte m ogu da deserijalizuju samo Java program i. Konverzijom podataka u for-
m at XML dobilo bi se interoperabilnije reenje koje bi mogle da koriste razne platform e
i jezici.
Zbog rairenosti XML-a postoji zbunjujue velik broj opcija za program iranje koje ga
proizvode; m eu njim a su i biblioteke javax.xm l.,<' koje se isporuuju uz razvojni paket
)ave. O dluio sam da upotrebim biblioteku otvorenog izvornog koda XOM (preuzim anje
i dokum entacija na w w w .xo tn .m i ) - autor je Elliotte Rusty Harold. Izgleda mi da je to naj-
jednostavniji nain da se XML proizvodi i m enja u Javi. Pored toga, XOM proizvodi veo-
ma ispravan XML kod.
Prim era radi, pretpostavim o da imate objekte tipa O soba i u njim a im ena i prezim ena
koja elite da serijalizujete u form atu XML. Naredna klasa O soba ima m etodu getX M L ()
koja pom ou XOM-a proizvodi podatke o klasi O soba konvertovane u XML Elem ent,
i konstruktor koji prim a Elem ent i vadi odgovarajue podatke o klasi O soba (obratite
panju na to da su XML primeri u sopstvenom poddirektorijum u):
//: x m l / O s o b a .java
// Upotreba biblioteke X0M za pisanje i itanje XML-a
// {Zahteva: nu.xom.Node; Morate instalirati
// biblioteku X0M sa http://www.xom.nu }
800 Misliti na Javi
import nu.xom.*;
import java.io.*;
import ja v a . u t i 1.*;
} /* Ispis:
[Dr. Bunsen Honeydew, Gonzo The Great, Phillip J. Fry]
<?xml version="1.0" encoding="IS0-8859-l"?>
< 1judi>
<osoba>
<im>Dr. Bunsen</im>
<prez>Honeydew</prez>
</osoba>
<osoba>
<im>Gonzo</im>
<prez>The Great</prez>
</osoba>
<osoba>
<im>Phi11ip J.</im>
<prez>Fry</prez>
</osoba>
</ljudi>
* ///:-
XOM m etode su jasne same po sebi, a mogu se nai i u XOM dokum entaciji.
XOM sadri i klasu S erializer koja je u m etodi f o r m a t( ) upotrebljena za pretvaranje
XML-a u itljiviji oblik. Ukoliko sam o pozovete to X M L (), dobiete sve baeno na gomi-
lu, pa je S erializer podesna alatka.
Jednostavno je i deserijalizovanje objekata tipa O soba iz XML datoteka:
//: x m l / L J u d i .java
// {Zahteva: nu.xom.Node; Morate instalirati
// biblioteku X0M sa http://www.xom.nu }
// {RunFirst: Osoba}
import nu.xom.*;
import j a v a . u t i l .*;
K onstruktor klase Ljudi otvara i ita datoteku XOM-ovom m etodom B u ild er.b u ild (),
a m etoda g etC h ild E lcm e n ts() proizvodi listu Elem ents (to nije standardna Javina lista,
nego objekat koji im a samo m etode s iz e () i g e t( ) - Harold nije eleo da natera korisnike
802 Misliti na Javi
da upotrcbljavaju Javn SE5, ali je ipak eleo da ima kontejner koji om oguuje bezbedan
rad s tipovim a). Svaki Element u toj listi predstavlja objekat tipa Osoba, pa se predaje
drugom k onstrukto ru klase Osoba. Vodite rauna o tom e da m orate unapred znati struk-
tu ru svoje XML datoteke, ali ba to je esto sluaj u ovoj vrsti problem a. Ako ta struktura
ne odgovara onom e to oekujete, XOM e generisati izuzetak. Svakako da m oete pisati
i sloeniji kod koji e ispitati XML d o k um en t um esto da o njem u ita pretpostavlja, u
sluajevima kada im ate m anje konkretne inform acije o dolaznoj XML strukturi.
Da bi ovi prim eri mogli da se prevedu, m oraete da stavite JAR datoteke iz XOM dis-
tribucije u svoju putan ju klasa.
Ovo je bio sam o kratak uvod u XML program iranje na Javi i s bibliotekom XOM; vie
inform acija potraite na adresi w w w .xo m .n u .
Veba 31: (2) Program im a Osoba.java i Ljudi.java dodajte odgovarajue podatke o adresi.
Veba 32: (4) Koristei M ap<String,Integer> i uslunu klasu net.mindview. util.TextFi-
le, napiite program koji prebrojava rei u datoteci (kao drugi argum ent u konstruktoru
klase TextFile upotrebite "\\W +"). Rezultate sauvajte u obliku XML datoteke.
Preferences
Interfejs za program iranje aplikacija (API) Preferences m nogo je blii konceptu trajnosti
nego serijalizovanju objekata, zato to inform acije autom atski skladiti i vadi iz skladita.
M eutim , m oe se prim enjivati sam o na oreene male skupove podataka - na proste
tipove i znakovne nizove (objekte tipa S tring), a svaki uskladiten znakovni niz ne sme
biti dui od 8 K (nije ba da je siuno, ali nije za ozbiljne poslove). Kao to mu ime go-
vori, API Preferences slui za skladitenje i vadenje param etara koje je izabrao korisnik i
postavki konfiguracije program a.
Poeljni param etri i postavke sm etaju se u skupove klju - vrednost (kao m ape), us-
kladitene u hijerarhiji vorova. lako se u hijerarhiji vorova mogu napraviti sloene
strukture, obino se pravi sam o jedan vor nazvan po klasi o kojoj se inform acije skladite
u njem u. Evo jednostavnog prim era:
//: ui/PrimerZaPreferences.java
import java.util.prefs.*;
import static net.mi nd vie w .u t i 1 .P r i n t .*;
U n orm aln om sluaju treba da zadate razum nu podrazum evanu vrednost. Zapravo,
ovo je jedan od tipinih idioma:
Na taj nain, U sageC ount e biti nula kada program pokrenete prvi put, ali e u kas-
nijim pokretanjim a biti razliit od nule.
Kada pokrenete PrimerZaPreferences.java, videete da se UsageCount zaista povea-
va za jedan svaki put kada pokrenete program . Ali gde se taj broj uva? Nema lokalne da-
toteke koja bi se pojavila nakon prvog pokretanja program a. API Preferences za
obavljanje tog svog posla koristi odgovarajue sistemske resurse, a oni se m enjaju u zavis-
nosti od operativnog sistema. U Windovvsu se za to upotrebljava registar (poto je on io-
nako hijerarhija vorova s parovim a klju - vrednost). Poenta je sledea: inform acije se
autom atski skladite, a mi ne m oram o da brinem o o tom e kako se to obavlja u bilo kojem
pojedinanom sistemu.
804 Misliti na Javi
API Preferences um e vie nego to je ovde prikazano. Dalje pojedinosti o tom e po-
traite u dokum entaciji razvojnog paketa JDK, koja je prilino razumljiva.
Veba 33: (2) Napiite program koji prikazuje tekuu vrednost direktorijum a nazvanog
osnovni direktorijum i trai od vas njegovu novu vrednost. Za skladitenje te vrednosti
upotrebite API Preferences.
Saetak
Javina biblioteka U/I tokova zadovoljava osnovne zahteve: om oguuje itanje sa konzole i
upisivanje u nju, u datoteke, u m em orijske blokove, ak i preko Interneta. Pom ou nasle-
ivanja moete da napravite nove vrste ulaznih i izlaznih objekata. Moete ak i da izmc-
nite nain na koji tokovi rade sa objektim a tako to ete redefinisati m etodu to S trin g ()
koja se automatski poziva kada objekat prosledite m etodi iji je argum ent tipa String (Ja-
vina ograniena autom atska konverzija tipa).
U dokum entaciji i projektu biblioteke U /I tokova, neka pitanja su ostala nedoreena.
Na prim er, bilo bi lepo kada biste mogli da generiete izuzetak pri pokuaju pisanja preko
postojee datoteke tokom njenog otvaranja; neki program erski sistemi om oguuju da za-
date otvaranje izlazne datoteke, ali sam o ako ona ve ne postoji. Izgleda da u Javi treba ko-
ristiti objekat klase File kako bi se odredilo da li datoteka postoji, zato to e se ta datoteka
uvek menjati ako je otvarate kao FileOutputStream ili FileVVriter.
Biblioteka U/I tokova izaziva oprena oseanja; ipak, radi dosta toga i prenosiva je.
Ukoliko ne razum ete projektni obrazac Decorator, njen projekat nije intuitivan pa je po-
treban dodatni napor da se ona objasni i razum e. Istovrem eno, biblioteka nije zaokrue-
na: na prim er, ne bi trebalo da ja m oram da piem uslune klase kao to je TextFile (nova
(SE5) Javina klasa PrintVVriter predstavlja korak u pravom sm eru, ali to je tek deliinino
reenje). Java SE5 je donela veliko poboljanje: najzad je dodato form atiranje izlaza kakvo
oduvek podravaju gotovo svi ostali jezici.
Kada shvatite dekoratorski projektni obrazac i ponete da upotrebljavate ovu bibliote-
ku tam o gde je potrebna njena prilagodljivost, uvideete da je korisna i tada vam nekoliko
dodatnih redova koda vie nee predstavljati problem .
R eenja o d a b ra n ih vebi d a ta su u e le k tro n sk o m d o k u m e n tu The Thinking in Java A naotated Soln-
tion Guide, koji se m o e k u p iti na W eb lokaciji w ww.M iiuiView .net.
Nabrojani tipovi
R ezervisana re e n u m slui zapravljenje novog tipa od ogranienogskupa itnenovanih vred-
nosti; zhog tije se te vrednosti tretiraju kao p u tiopravne kotnponenteprogratna. Ispostavlja se
d a je to veom a ko risn o .1
//: nabrojani/KlasaEnum.java
// Mogunosti klase Enum
import static ne t, mindview.uti1 .Print.*;
}
} /* Ispis:
MORE rednibroj: 0
-1 false false
class Odmor
MORE
PLANINA rednibroj: 1
0 true true
class Odmor
PLANINA
BANJA rednibroj: 2
1 false false
class Odmor
BANJA
BANJA
PLANINA
MORE
* ///:-
M etoda o rd in al( ) proizvodi ceo broj koji pokazuje redosle deklarisanja svake enum
instance, poev od nule. enum instance uvek moete bezbedno porediti operatorom ==, i
metode equals( ) i hashC ode( ) bivaju autom atski napravljene. Klasa Enuni realizuje inter-
fejs Comparable, stoga ima svoju m etodu com pareTo( ), a realizuje i interfejs Serializable.
Pozivom m etode getD eclaringClass( ) za enum instancu, dobiete obuhvatajuu
enum klasu.
M etoda n am e( ) daje ime tano onako kako je bilo deklarisano, a isto to dobijate i me-
todom to S trin g ( ). valueO f( ) je statini lan klase Enum i proizvodi enum instancu koja
odgovara znakovnom nizu koji joj je prosleen ili baca izuzetak ukoliko takav niz ne
moe da pronae.
//: nabrojani/LJutina.java
package nabrojani;
LJutina degree;
public P1jeskavica(LJutina stepen) { this.stepen = stepen;}
public String toString() { return "Pljeskavica je "+ stepen;}
public static void main(String[] args) {
System.out.println(new P1 je sk av ic a( NE ));
System.out.println(new Pljeskavica(SREDNJE)) ;
System.out.println(new P1 je sk av ic a( MN OG O) );
}
} /* Ispis:
Pljeskavica je NE
Pljeskavica je SREDNJE
Pljeskavica je MNOGO
* ///:-
static im port uvodi sve identifikatore enum instanci u lokalni prostor im ena, pa oni
ne m oraju biti po tp un i (kvalifikovani). Da li je to dobro ili je bolje biti izriit i navesti
potpu na im ena svih enum instanci? To verovatno zavisi od sloenosti koda. Prevodilac si-
gurno nee dopustiti da se upotrebi pogrean tip, pa sam o treba da se postarate da kod
bude razum ljiv itaocu. U m nogim situacijam a e i n epotpuna im ena biti dovoljno razu-
mljiva, ali se to moe prosuditi samo od sluaja do sluaja.
Vodite rauna o tom e da ovu tehniku nije m ogue koristiti ako je enum definisan u
istoj datoteci ili podrazum evanom paketu. (Kao da je u kom paniji Sun bilo razliitih
miljenja o tom e treba li to dozvoliti.)
//: na br ojani/VesticalzOza.java
// Vetice iz Oza.
import static net.mind vi ew .u ti l.Print.*;
this.opis = opis;
}
public String getDescription() { return opis; }
public static void main(String[] args) {
for(VesticaIzOza vestica : V e s t i c a l z O z a . v a l u e s O )
print(vestica + 11 + vestic a. ge tD es cr ip tio n( ));
}
} /* Ispis:
WEST: Gospoica Gal, poznata i kao zla vetica sa zapada
NORTH: Glinda, dobra vetica sa severa
EAST: Zla vetica sa istoka, nosilac crvenih papuica, koju je smrvila Doro-
tina kua
SOUTH: Verovatno dobra, ali je nema
* ///:-
Ukoliko nam eravate da definiete m etode, sekvencu enum instanci m orate zavriti
znakom taka i zarez. Takoe, Java nas prisiljava da u nabrojanom tipu (enum ) najpre
definiemo instance. Izazvaete greku u vrem e prevoenja ako pokuate da ih definiete
nakon neke od m etoda ili polja.
K onstruktor i m etode im aju isti oblik kao u uobiajenim klasama, zato to ovo i jeste
obina klasa uz nekoliko ogranienja. Dakle, s nabrajanjim a m oete raditi gotovo sve to
poelite (iako ete se verovatno tru diti da ostanu prilino jednostavna).
M ada je u prethodnom prim eru konstruktor privatan, ne bi bilo velike razlike i da ste
prim enili neki drugi pristup - ko n struktor se moe upotrebiti samo za pravljenje enuin
instanci koje ste deklarisali u n u tar definicije nabrojanog tipa; prevodilac nee dozvoliti da
ga upotrebite za pravljenje novih instanci nakon zavretka te definicije.
//: nabrojani/SvemirskiBrod.java
public enum SvemirskiBrod {
IZVIDJAC, T E R E T N I , TRANSPORTNI, KRSTARICA, BOJNIBROD, M A T I C N I ;
public String toString() {
String id = n a m e ( ) ;
String mala = i d .s u b s t r i n g ( 1 ).t o Lo we rC as e( );
return id.charAt(O) + mala;
}
public static void main(String[] args) {
fo r(SvemirskiBrod s : v a l u e s O ) {
System.out.pri ntln (s);
}
}
} /* Ispis:
Izvi djac
Teretni
Poglavlje 19: Nabrojani tipovi 809
Transportri
Krstarica
Bojnibrod
Maticni
* ///:-
M etoda to S trin g ( ) pribavlja ime klase SvemirskiBrod pozivanjem m etode n a m e ( ), a
njen rezultat m enja tako da je sam o prvo slovo veliko.
//: nabrojani/Semafor.java
// Nabrojani tipovi u naredbama switch.
import static n e t. mi nd vi ew .u ti l.Print.*;
} /* Ispis:
Na semaforu je CRVENO
Na semaforu je ZELENO
Na semaforu je ZUTO
Na semaforu je CRVENO
Na semaforu je ZELENO
Na semaforu je ZUTO
Na semaforu je CRVENO
* ///:-
Prevodilac se ne ali da unu tar naredbe switch nem a naredbe default, ali ne zato to je
uoio da za svaku instancu klase Signal im ate naredbe case. Nee se aliti ni ako jednu od
naredaba case pretvorite u kom entar. Znai, sam i m orate paziti na to da definiete sve mo-
gue sluajeve. S druge strane, ukoliko iz naredbe case pozivate return, prevodilac e se a-
liti ako nem ate default - ak i ako ste definisali sve mogue vrednosti tog nabrojanog tipa.
Veba 1: (2) Izmenite Semafor.java pom ou uvoza statinih lanova tako da ne m orate
navoditi p otpuna imena enum instanci.
//: nabrojani/Refleksija.java
// Analiza nabrojanih tipova pomou refleksije.
import java.lang.reflect.*;
import ja v a . u t i l .*;
import net.mindview.util.*;
import static ne t. mi nd vi ew .u ti l.Print.*;
Dakle, odgovor je da je v alu es( ) statina m etoda koju je odao prevodilac. I m etoda
valu eO f( ) je dodata klasi Istrazi dok se pravio enuin. To pom alo zbunjuje, zato to
postoji i m etoda valueO f( ) koja je deo klase Enum, ali ona ima dva argum enta, a dodata
m etoda sam o jedan. M etoda interfejsa Set ovde je upotrebljena samo za pronalaenje
im ena m etoda, ne i njihovih potpisa, pa posle poziva Istrazi.removeAll(Enum) preostaje
sam o niz [values].
Iz rezultata vidite da je prevodilac klasu Istrazi oznaio sa final, pa od nje ne moete
izvoditi potklase. Tu je i statina oreba za inicijalizaciju koja se moe redefinisati
(pokazau to kasnije).
812 Misliti na Javi
Zbog brisanja (opisanog u poglavlju Generiki tipovi), dekom pajler nem a p u n u infor-
m aciju o nabrojanom tipu (Enurn), pa prikazuje da je natklasa od Istrazi sirovi Enum,
um esto stvarne Enum <Istrazi>.
Poto je valu es( ) statina m etoda koju je u definiciju enum u m etn u o prevodilac, ako
neki od enum tipova svedete navie na Enum, m etoda values( ) nee biti dostupna.
M edutim , im ajte u vidu da u klasi Class postoji m etoda getE num C onstants( ), pa ak i
ako m etoda v alu es( ) nije deo interfejsa od Enum, enum instance ipak m oete dobiti po-
m ou Class objekta:
//: nabrojani/SvodjenjeEnumaNavise.java
/ / Kada se nabrojan tip svede navie,
// metoda va1ues() postaje nedostupna
Poto m etoda getE num C onstants( ) pripada klasi Class, moete je pozvati i za klase
koje nem aju nabrojane tipove:
//: nabrojani/NijeEnum.java
M etoda vraa null, pa ete dobiti izuzetak kada pokuate da upotrebite njen rezultat.
Poglavlje 19: Nabrojani tipovi 813
Realizuje, ne nasleuje
Rckao sam da su svi nabrojani tipovi izvedeni iz klase java.lang.Enum . Poto Java ne
podrava viestruko nasleivanje, to znai da nabrojan tip ne m oete napraviti preko na-
sleivanja:
M eutim , mogue je napraviti nabrojan tip koji realizuje jedan ili vie interfejsa:
//: nabrojani/crtaci/EnumRealizacija.java
// Nabrojani tip moe da realizuje interfejs
package na br oj an i. cr ta ci;
import ja v a . u t i l .*;
import net.mindview.util.*;
enum LiklzCrtaca
implements Generator<LikIzCrtaca> {
FUCA, GRDA, TIBA, BLESA, SKOKA, LUDA, BOBA;
private Random slucajan = new Random(47);
public LiklzCrtaca next() {
return v a l u e s ()[slucajan.nextlnt(values().1e n g t h ) ] ;
}
Rezultat je malo neobian, poto m orate im ati instancu nabrojanog tipa da biste za nju
mogli pozvati m etodu. M edutim , L iklzC rtaca sada m oe da prihvati svaka m etoda koja
prim a G enerator, na prim er, m etoda p r in tN e x t().
Veba 2: (2) Umesto da reali/.ujete interfejs, napravite n e x t( ) statinom m etodom . Koje
su prednosti i m ane tog pristupa?
814 Misliti na Javi
Nasumian izbor
U m nogim prim erim a u ovom poglavlju neophodan je nasum ian izbor enum instanci,
kao to ste videli u m etodi LikIzCrtaca.next( ). To m oem o uoptiti pom ou generikih
tipova i rezultat sm estiti u zajedniku biblioteku:
/ / : n e t/ mi nd vi ew /u ti l/ Nab ro ja ni Ti po vi.java
package net.mindview.util;
import java.util
Prilino neobina sintaksa <T extends E n u m < T opisuje T kao instancu nekog
nabrojanog tipa. O bjekat te klase inim o dostupnim tako to prosleujem o Class<T>, i
zato se m oe napraviti niz enum instanci. Preklopljena m etoda ra n d o m ( ) treba da zna
sam o to da dobija T[], poto ne m ora da obavlja Enum operacije; ona sam o nasum ino
bira neki elem ent niza. Povratni tip je tano taj nabrojan tip.
Evo iednostavne provere m etode ra n d o m ( ):
//: na br ojani/ProveraMetodeRandom.java
import net.mindview.util.*;
//: nabrojani/jelovnik/Hrana.java
// Potkategorizacija nabrojanih tipova unutar interfejsa.
package na b r o j a n i .jelovnik;
/ / : nabrojani/jelovnik/VrstaHrane.java
package nabrojani.jelovnik;
import static n a b r oj an i.jelovnik.Hrana.*;
Svoenje navie na klasu H rana funkcionie za svaki enum tip koji realizuje interfejs
H rana, pa su svi oni tipovi klase H rana.
M eutim , za rad sa skupom tipova interfejs nije toliko upotrebljiv kao enum. Ukoliko
elite da im ate nabrojan tip drugih nabrojanih tipova, m oete napraviti obuhvatajudi
enum s po jedn om instancom za svaki enum u klasi Hrana:
//: na br oj ani/jelovnik/VrstaJela.java
package nabrojani.jelovnik;
import net.mindview.util.*;
Svaki od gorenavedenih nabrojanih tipova prim a odgovarajui objekat tipa Class kao
argum ent konstruktora od kojega m etodom g e tE n u m -C o n sta n ts() moe da izvue i
uskladiti sve en u m instance. Te instance kasnije koristi m etoda ra n d o m S e le c tio n (), pa
sada m oem o da napravim o nasum ino generisan obrok tako to em o izabrati po jednu
stavku klase H ra n a iz svakog tipa V rstajela:
SUPA
Poglavlje 19: Nabrojani tipovi 817
SARMA
VOCE
CAJ
SALATA
PLJESKAVICA
VOCE
CAJ
SALATA
PLJESKAVICA
KARAMEL_KREM
KAFA_S_MLEKOM
SUPA
PLJESKAVICA
TIRAMISU
ESPRESSO
* ///:-
U ovom sluaju, svrha pravljenja nabrojanog tipa nabrojanih tipova jeste iteracija kroz
sve tipove V rstajela. Kasnije, u prim eru A utom atZ aM aloprodaju.java, videete drugaiji
pristup kategorizaciji odreen drugaijim ogranienjim a.
Drugaiji, kom paktniji pristup problem u kategorizacije jeste ugnedivanje nabrojanih
tipova u n u ta r drugih nabrojanih tipova, to se radi ovako:
//: nabrojani/KategorijeVrednosnihPapira.java
// Saetija potkategorizacija nabrojanih tipova.
import net.mindview.util.*;
enum KategorijeVrednosnihPapira {
DEONICE(Vrednosni Papi ri.Deoni ca . c l a s s ) , OB VEZNICE(Vrednosni-
P a p i r i .O bv ez ni ca .c la ss );
V r e d n o s n i P a p i r i [] vrednosti;
KategorijeVrednosnihPapira(Class<? extends Vred no sn iPapiri> vrsta) {
vrednosti = vr st a. ge tE nu mC on st ant s( );
I
interface Vred no sn iP ap iri {
enum Deonica implements VrednosniPapiri { KRATKOROCNE, DUGOROCNE,
JEMSTVENE }
en u m Obveznica implements VrednosniPapiri { GRADSKE, RAZNE }
}
public VrednosniPapiri randomSelection() {
return Nabrojani Ti p o v i .ra nd om(vrednosti) ;
}
public static void m a i n ( S t r i n g [] args) {
for(int i = 0; i < 10; i++) {
KategorijeVrednosnihPapira kategorija =
Nabrojani Ti p o v i .random(KategorijeVrednosni hPapi ra.cla s s ) ;
Sy st em.out.println(kategorija + " +
818 Misliti na Javi
kategorija.randomSelectionO);
}
}
} /* Ispis:
OBVEZNICE: GRADSKE
OBVEZNICE: GRADSKE
DEONICE: JEMSTVENE
DEONICE: JEMSTVENE
OBVEZNICE: RAZNE
DEONICE: KRATKOROCNE
DEONICE: DUGOROCNE
OBVEZNICE: GRADSKEDEONICE: DUGOROCNE
OBVEZNICE: RAZNE
* ///:-
//: nabrojani/jelovnik/0brok2.java
package nabrojani.jelovnik;
import net.mindview.util.*;
Na kraju sm o dobili praktino isti kod, ali reorganizovan. U nekim sluajevima, tim e
se dobija jasnija struktura.
Veba 3: (1) Dodajte nov tip Vrstajela u Vrstajela.java i pokaite da to radi u program u
Obrok.java.
Veba4: (1) Ponovite p rethodnu vebu za Obrok2.java.
Veba 5: (4) Izmenite program kontroIa/SamoglasnicilSuglasnici.java (iz etvrtog pogla-
vlja) tako da koristi tri nabrojana tipa: SAMOGLASNIK, PONEKAD SAMOGLASNIK i
SUGLASNIK. K onstruktor nabrojanog tipa treba da prim a sva slova koja ine odgovara-
juu kategoriju. Uputstvo: upotrebite argum ente promenljive duine i ne zaboravite da oni
autom atski prave niz.
Veba 6: (3) Daje li ugneivanje tipova Predjelo, Glavnojelo, Desert i Kafa unutar in-
terfejsa H rana ikakve prednosti nad sluajem kada bism o ih deklarisali kao samostalne
nabrojane tipove koji sluajno svi realizuju interfejs Hrana?
Elementi skupa EnumSet m oraju poticati iz istog nabrojanog tipa. U n arednom pri-
m eru im am o enum svih m esta u zgradi na kojim a je ugraen alarm ni senzor:
//: nabrojani/AlarmneTacke.java
package n a b r oj an i;
public enum AlarmneTacke {
STEPENISTEl, STEPENISTE2, HODNIK, K A N C EL AR IJ Al, KANCELARIJA2,
KANCELARIJA3, KANCELARIJA4, KUPATILO, SALA, KUHINJA
} ///= -
//: nabrojani/SkupEnumSet.java
// Operacije na skupu tipa EnumSet
package n a b r oj an i;
import j a va .u ti1
import static nabrojani.A1armneTacke.*;
import static net.mind vi ew .u ti l.Print.*;
ve i jed n a m etoda o f ( ) sa argum entim a prom enljive duine, ali bi to bilo neto m anje
efikasno nego kada su argum enti zadati eksplicitno. Dakle, ako m eto d u o f ( ) pozovete sa
od dva o d pet argum enata, dobiete eksplicitne (neto bre) m etode, ali ukoliko je pozo-
vete s jednim ili s vie od pet argum enata, dobiete vararg verziju od o f ( ). O bratite panju
na sledee: ukoliko je pozovete s jednim argum entom , prevodilac nee praviti vararg niz,
pa pozivanje te verzije s jednim argum entom nee poveati reijske trokove.
EnumSet se pravi povrh podupirueg broja tipa long, long im a 64 bita, a svaka enum
instanca zahteva jedan bit za inform aciju ukljueno/iskljueno ili postojanje/neposto-
janje. To znai da EnumSet za jedan enum od najvie 64 elem enta troi sam o jedan broj
tipa long. ta se deava ako u nabrojanom tipu im ate vie od 64 elementa?
//: nabrojani/VelikiEnumSet.java
import java.util
//: nabrojani/MapeEnumMap.java
// Osnove rada s mapama EnumMap.
package n a b r oj an i;
import java.util
import static nabrojani.AlarmneTacke.*;
import static net.mi nd vi ew .u ti l.Print.*;
Kao u skupu Enum Set, redosle elem enata u m api E num M ap odreen je redosledom
njihovog definisanja u odgovarajuem nabrojanom tipu.
Poslednji deo m etode m a in ( ) pokazuje da u m api za svaki nabrojani tip uvek postoji
stavka klju, ali je njena vrednost n u ll ukoliko za taj klju niste pozvali p u t ( ).
Jedna od prednosti m ape E num M ap nad m etodnm a koje sc m enjaju u znvisnosti od
konstante (nabrojanog tipa) jeste to to je u E num M ap dozvoljeno m enjanje objekata
vrednost, dok m etode koje se m enjaju u zavisnosti od konstante bivaju fiksirane u vreme
prevoenja.
Poglavlje 19: Nabrojani tipovi 823
Kao to ete videti u nastavku poglavlja, m apam a EnumMap m oemo obavljati viekrat-
no otkrivanje tipa u situacijama gde vie nabrojanih tipova ulazi u m eusobnu interakciju.
//: nabrojani/MetodeKojeSeMenjajuUZavisnostiOdKonstante.java
import java.util
import java.text.*;
//: nabrojani/NisuKlase.java
// {Pokretanje: javap -c KaoKlase}
import static net.mindview.util .Print.*;
enum KaoKlase {
NAMIGNUTI { void ponasanje() { pr i n t ( " P o n a s a n j e l " ) ; } },
TREPNUTI { void ponasanje() { pr in t( " P o n a s a n j e 2 " ) ; } },
KLIMNUTI { void p o n a s a n j e O { pr i n t ( " P o n a s a n j e 3 " ) ; } };
abstract void ponasanje();
}
* ///:-
//: nabrojani/RedefinisanjeMetUZavOdK.java
import static net.mind vi ew .u ti l.Print.*;
napravim o vie ne-DA instanci, pa e vam definicije nabrojanih tipova spoetka izgledati
malo udno.
U klasi Posiljka videete m etodu nasum icnaPosiljka( ) koja pravi nasum ine prim er-
ke prob nih poiljki. M etoda g en erato r( ) proizvodi objekat koji realizuje interfejs Itera-
ble i m etodom nasum icnaPosiIjka( ) proizvodi vie poiljki, po jednu za svaki poziv
m etode n e x t( ) putem iteratora. Takva konstrukcija om oguuje jednostavno pravljenje
foreach petlje pozivom m etode P osiljka.generator( ):
//: nabrojani/Posta.java
// Modelovanje pote.
import j a va .u ti1
import net.mindview.util.*;
import static n e t . mi nd vi ew .u ti l.Print.*;
class Posiljka (
Tipovi NE su tu da bi se smanjila verovatnoa nasuminog izbora:
enum OpstaDostava {DA,NE1,NE2,NE3,NE4,NE5}
enum MozeSeSkenirati {N E M O ZE SE SK EN IR AT I,D A 1,D A 2 ,D A 3 ,D A 4 }
enum Citljivo {NECITLJIV0,DA1,DA2,DA3,DA4}
en um Adresa {NETACNA,0K1,0K2,0K3,0K4,0K5,0K6}
enum PovratnaAdresa {NEDOSTAJE,OK1,OK2,OK3,OK4,OK5}
OpstaDostava opstaDostava;
Moze Se Sk en irati moze Se Sk en ir a t i ;
Citljivo citljivo;
Adresa adresa;
PovratnaAdresa povratnaAdresa;
static long brojac = 0;
long id = brojac++;
public String toString() { return "Poiljka " + id; }
public String details() {
return t o S t r i n g O +
", Opta dostava: " + opstaDostava +
", Adresa se moze skenirati: " + MozeSeSkenirati +
", itljivost adrese: " + Citljivo +
", Adresa Adresa: 11 + adresa +
", Povratna adresa: " + povratnaAdresa;
}
// Generisanje probne Poiljke:
public static Posiljka nasumicnaPosiljka() {
Posiljka p = new Posiljka();
p.opstaDostava= Na br oj an iT ip ov i.rand om (O ps ta Do st av a.c la ss );
p.MozeSeSkeni rati = N a b r o j an iT ip ov i.ra nd om (M oz eS eS ke ni rat i. cl as s);
p.Citljivo = Na br oj an iT ip ov i.ra nd om(Citljiv o . c l a s s ) ;
p.adresa = Nabr oj an iT ip ov i. ra ndo m( Ad re sa .c la ss );
p.povratnaAdresa = NabrojaniTi p o v i .r a nd om (P ov ra tn aA dr esa .c la ss );
return p;
}
public static Iterable<Posiljka> generator(final int broj) {
return new Iterable<Posi1jka>() {
int n = b r o j ;
public Iterator<Posi1jka> iterator() {
828 Misliti na Javi
},
VIZUELNIPREGLED {
boolean ob ra da (Posiljka p) {
switch(p.Citljivo) {
case NECITLJIVO: return false;
default:
switch(p.adresa) {
case NETACNA: return false;
default:
print(p + " : isporui obino");
return true;
}
}
Poglavlje 19: Nabrojani tipovi 829
}
},
VRATI_POSILJAOCU {
boolean obrada{Posiljka p) {
switch(p.povratnaAdresa) {
case NEDOSTAJE: return false;
default:
print(p + " : vrati p o i 1j a o c u " ) ;
return true;
}
}
};
abstract boolean obrada(Posiljka p);
}
static void o b ra da (P os i1jka p) {
for(PrZaObraduPoste przaobradu : PrZaObraduPoste.values())
i f(przaobradu.obrada(p))
return;
print(p + " se ne moe uruiti");
}
public static void main(String[] args) {
for(Posiljka posiljka : Po si1jka.gene ra to r( lO )) {
pr in t( po si lj ka .d et ails( ) );
obrada(posilj k a ) ;
p r i n t C 1* * * * * " ) ;
}
}
} /* Ispis:
Poiljka 0, Opta dostava: NE2, Adresa se moze skenirati: N E MO ZE SE SK EN IR AT I,
Adresa itljiva: DA3, Adresa Adresa: OKl, Povratna adresa: OKl
Poiljka 0 : isporui obino
*****
Poiljka I, Opta dostava: NE5, Adresa se moze skenirati: DA3, Adresa
itljiva: NECITLJIVO, Adresa Adresa: 0K5, Povratna adresa: OKl
Poiljka 1 : isporui automatski
*****
* ///:-
Chain o f Responsibility je izraen u nabrojanom tipu P rZ aO b rad u P o ste, a redosled
en u m definicija odreuje redosled isprobavanja strategija na svakoj poiljci. Isprobava se
svaka strategija redom dok jedna ne uspe ili dok sve ne propadnu - u tom sluaiu poiljka
se ne m oe uruiti.
Veba 8: (6) Izm enite program Posta.java tako da poiljke moe da prosleuje (s jedne na
drugu adresu).
Veba 9: (5) Izm enite klasu P osta tako da koristi Enum M ap.
P rojekat:2 Na specijalizovanim jezicima kao to je Prolog ovakvi problem i se reavaju
ulanavanjem u n a za d (engl. backw ard chaining). Uz Posta.java kao nadahnue, prouite
takve jezike i napiite program koji om oguava lako oavanje novih pravila" sistemu.
Projekti su predlozi koji se m ogu koristiti (recim o) za sem inarske radove. Vodi s reenjim a ne sari
reenja p rojekata.
Poglavlje 19: Nabrojani tlpovi 831
//: nabrojani/Ulaz.java
package nabrojani;
import j a v a . u t i l .*;
//: nabrojani/AutomatZaMaloprodaju.java
// { A r g u m e n t i : UlazUAutomatZaMaloprodaju.txt}
package n a b r o j a n i ;
import j a v a . u t i l .*;
import net.mindview.util.*;
import static n a b r o j a n i .U1az.*;
import static ne t. mi nd vi ew .u ti1 .P r i n t .*;
enum Kategorija {
NOVAC(PETOPARAC, DESETOPARAC, FRTA LJ, DINAR),
IZBOR_ARTIKLA(ZUBNAPASTA, CIPS, SOK, S A P U N ) ,
PREKINI TRANSAKCIJU(ODUSTANI OD TRANSA KC IJ E),
832 Misliti na Javi
U6ASI(STOP);
private Ulaz[] vr e d n o s t i ;
Kategorija(Ulaz... tipovi) { vrednosti = tipovi; }
private static En umHap<Ulaz,Kategorija> kategorije =
new EnumMap<Ul a z ,Kategorija>(Ul a z .cl a s s ) ;
static {
for(Kategorija c : Kategorija.class.getEnumConstants())
for(Ulaz type : c.vrednosti)
kategorije.put(type, c);
}
public static Kategorija kategorizuj(Ulaz ulaz) {
return ka te go rije.get(ulaz);
}
}
case UGASI:
stanje = TERMINAL;
default:
}
}
},
O B R A CU N( Tr aj an je St anj a.PROLAZNO) {
void next() {
print("uzmite kupljeno: " + izbor);
iznos -= izbor. iz no s( );
stanje = VRACANJEJOJSURA;
}
}.
VRACAN JE _K US UR A( Tr aja nj eS ta nj a.PROLAZNO) {
void next() {
if(iznos > 0) {
print("Va kusur: " + iznos);
iznos = 0;
}
stanje = MIRUJE;
}
},
TERMINAL { void output() { p r in t( "Z au st av lj en "); } };
private boolean stanjeProlazno = false;
Stanjef) {}
Stanje(TrajanjeStanja trans) { stanjeProlazno = true; }
void next(Ulaz ulaz) {
throw new RuntimeException("Pozivajte " +
"next(Ulaz ulaz) samo za neprolazna stanja");
}
void next() {
throw new Ru ntimeException("Metodu next() pozivajte za " +
"stanja Trajan je St an ja .P RO LAZ NO ");
}
void output() { p r i n t( iz no s); }
}
static void run(Generator<Ulaz> gen) {
while(stanje != Stanje.TERMINAL) {
st an je .n ex t( ge n. ne xt( ));
while(stanje.stanjeProlazno)
st an je .n ex t( );
st a n j e .o ut pu t( );
25
35
Va kusur: 35
0
25
35
Nedovoljno novca za S0K
35
60
70
75
Nedovoljno novca za S0K
75
Va kusur: 75
0
Zaustavljen
* ///:-
Poto se enu m instanca najee bira pom ou naredbe svvitch (obratite panju na do-
datni trud uloen u to da se naredba sw itch moe lako upotrebljavati s nabrojanim tipovi-
ma), jedno od najeih pitanja u vezi sa upotrebom nabrojanih tipova jeste: ,,Po kojem
Poglav[je 19: Nabrojani tipovi 835
osnovu da biram? U navedenom prim eru je najlake krenuti unazad od klase AutomatZa-
Maloprodaju. U svakom stanju treba izabrati jednu od osnovnih kategorija ulaznog dej-
stva: prim anje novca, izbor artikla, odustajanje od transakcije, i iskljuenje maine.
M eutim , unutar tih kategorija imate razliite novane apoene koje kupac moe ubaciti u
m ainu i razliite artikle koje moe izabrati. Nabrojani tip Kategorija grupie razliite tipo-
ve ulaza tako da m etoda kategorizuj( ) moe u nutar naredbe switch da proizvede odgova-
rajuu kategoriju. Ta m etoda delotvorno i bezbedno obavlja pretraivanje pom ou m ape
EnumMap.
Ako prouite klasu AutomatZaM aloprodaju, videete da se sva stanja razlikuju i da
drugaije reaguju na ulaze. O bratite panju i na dva prelazna stanja; u m etodi r u n ( )
m aina eka na neki Ulaz i ne prestaje da m enja stanja dok ne izae iz prelaznog stanja.
Autom atZaM aloprodaju m oem o ispitati na dva naina, pom ou dva razliita
objekta tipa Generator. Random lnputG enerator stalno proizvodi nove ulaze, sve sem
ulaza UGASI. Ukoliko dovoljno dugo izvravate takav program , donekle ete proveriti
ispravnost, tj. videete da li je maina sklona da odluta u loe stanje. FilelnputG enerator
prim a datoteku koja u tekstualnom obliku opisuje ulaze, pretvara ih u instance nabroja-
nog tipa i pravi objekte tipa Ulaz. Evo tekstualne datoteke koja proizvodi p rethodno
prikazane rezultate:
//:! nabrojani/lllazUAutomatZaMaloprodaju.txt
FRTALJ; FRTALJ; FRTALJ; CIPS;
DINAR; DINAR; ZUBNAPASTA;
F R T A L J ; DESETOPARAC; ODUSTANI_OD_TRANSAKCIJE;
F R T A L J ; DESETOPARAC; SOK;
F R T A L J ; DESETOPARAC; PETOPARAC; SOK;
ODUSTANI_OD_TRANSAKCIJE;
STOP;
///:-
Jedno od ogranienja ovog dizajna jeste to to polja klase Autom atZaM aloprodaju
kojima pristupaju instance nabrojanog tipa Stanje m oraju biti statina, to znai da
moete imati sam o jednu instancu klase AutomatZaM aloprodaju. To vas nee m nogo
zabrinuti ako pom islite na stvarnu (ugraenu Java) realizaciju, poto ete verovatno imati
samo jednu aplikaciju po autom atu.
Veba 10: (7) Izmenite (samo) klasu AutomatZaM aloprodaju koristei EnumMap, tako
da program moe imati vie instanci klase AutomatZaM aloprodaju.
Veba 11: (7) U pravom autom atu za m aloprodaju trebalo bi da se m ogu lako dodavati i
menjati vrste artikala koji se prodaju, pa su ogranienja koja nabrojan tip nam ee na Ulaz
nepraktina (poto enum definie konaan i neprom enljiv skup tipova). Izmenite pro-
gram AutomatZaM aloprodaju.java tako da artikle koji se prodaju predstavlja klasa um e-
sto to su deo Ulaza, i pom ou tekstualne datoteke inicijalizujte ArrayList tih objekata.
(U potrebite net.mindview.utiI.TextFile.)
Projekat: Projektujte m eunarodni autom at za m aloprodaju (koristei intern a o n ali-
zaciju ), tako da se ista maina moe lako prilagoditi za razliite zemlje.
836 Misliti na Javi
//: nabrojani/Ishod.java
package n a b r o j a n i ;
public enum Ishod { POBEDA, PORAZ, NERESENO } ///:-
//: n a b r oj an i/ Ro Sh am Bo l.java
// Primer viekratnog otkrivanja tipa.
package na b r o j a n i ;
import java.util
import static n a b r o j a n i .Ishod.*;
interface Stavka {
Ishod takmicenje(Stavka st);
Ishod izrc(Papir p ) ;
Ishod izrc(Makaze m ) ;
Ishod izrc(Kamen k ) ;
}
//: nabrojani/RoShamBo2.java
// Izbor konstante jednog nabrojanog tipa
// korienjem drugog u naredbi svvitch.
package n a b r oj an i;
import static na br oj an i.Ishod.*;
Nakon to m etoda takm icenje( ) otkrije oba tipa, jedino dejstvo je vraanje rezul-
tujueg objekta tipa Ishod. M eutim , mogli biste pozvati i neku drugu m etodu, ak (na
prim er) preko objekta tipa C o m m a n d dodeljenom u konstruktoru.
RoShamBo2.java je m nogo manji i jednostavniji od prvobitnog prim era, te ga je lake
i pratiti. Vodite rauna o tom e da i dalje koristim o dva otkrivanja tipa da bism o utvrdili
tip oba objekta. U program u RoShamBol.java oba otkrivanja su obavljena preko
virtuelnih poziva m etoda, ali ovde je virtuelni poziv m etode upotrebljen sam o u prvom
otkrivanju tipa. U drugom otkrivanju tipa upotrebljen je switch, ali sve je bezbedno zato
to enum ograniava broj izbora u naredbi switch.
840 Misliti na Javi
Kod koji upravlja nabrojanim tipom tako je ralanjen da ga m oem o koristiti u drugim
prim erim a. Prvo, interfejs Takmicar definie tip koji se takmii s drugim Takmicarom:
/ / : n a b r o ja n i/ T a k m ic a r . ja v a
/ / I z b o r k o n s tan te je dnog nabrojanog t i p a
/ / k o ri e n je m drugog u naredbi s w it c h .
package n a b r o j a n i ;
Z atim definiemo dve statine m etode (statine zato da ne bism o m orali eksplicitno
zadati param etarski tip). Prvo m a tc h ( ) poziva takm icenje( ) za jedan objekat tipa Tak-
m icar protiv drugog, pa vidite kako je u ovom sluaju dovoljno da param etarski tip bude
Takmicar<T>. Ali u m etodi ig ra j( ), param etarski tip m ora biti Enum<T> jer se koristi
u m etodi N abrojaniT ipovi.random ( ), i Takmicar<T>, zato to se prosleuje m etodi
m a tc h ():
//: nabrojani/RoShamBo.java
// Zajednike alatke za RoShamBo primere.
package n a b r oj an i;
import net.mindview.util.*;
one savreno reenje za viekratno otkrivanje tipa. Ali iako n a taj nain m ogu dobiti
drugaija ponaanja, enum instance nisu tipovi, pa ih ne m oete koristiti kao argum ente
tipova u potpisim a metoda. U ovom prim eru upotrebljavate naredbu svvitch, i to je naj-
vie to se m oe uraditi:
/ / : nabrojani/Ro ShamBo3.java
/ / K o r i e n je metoda k o je se menjaju u z a v i s n o s t i od k o n s ta n te
/ / (nabroja nog t i p a ) .
package n a b r o j a n i ;
im p o r t s t a t i c n a b r o j a n i . I s h o d . * ;
Iako ovo radi, a nije ni glupo, reenje u program u RoSham Bo2.java kao da zahteva
m anje koda za dodavanje novog tipa, te izgleda jednostavnije.
M eutim , RoSham Bo3.java m oem o pojednostaviti i saeti:
/ / : nabrojani/RoShamBo4.java
package n a b r o j a n i ;
Ovde se rugo otkrivanje tipa obavlja verzijom m etode takm icenje( ) s dva argum en-
ta; m etoda obavlja niz poreenja i stoga radi slino naredbi switch. Program je manji, ali
i m anje jasan. U velikom sistem u ta nejasnost moe imati strane posledice.
//: na brojani/RoShamBo5.java
// Viekratno otkrivanje tipa pomou mape EnumMap
// iji su lanovi drugi objekti tipa EnumMap.
package nabrojani;
import j a v a . u t i l .*;
Poglavlje 19: Nabrojani tipovi 843
//: nabrojani/RoShamBo6.java
// Nabrojani tipovi i "tabele" umesto
// viekratnog otkrivanja tipa.
package nabrojani;
import static nabrojani.Ishod.*;
Saetak
Iako nabrojani tipovi sami po sebi nisu previe sloeni, ovo poglavlje sam pom erio u dru-
gi deo knjige zbog onoga to se m oe uraditi kom binacijom nabrojanih tipova i polim or-
fizma, generikih tipova i refleksije.
M ada znatno sofisticiraniji nego u jezicim a C i C + + , nabrojani tipovi i dalje pred-
stavljaju ,,malu m ogunost, neto bez ega je jezik opstajao (pom alo nezgrapno) mnogo
godina. Ovo poglavlje pokazuje kako m oe biti vaan doprinos ,,male m ogunosti - kat-
kada nam daje ba onu polugu kojom problem m oem o reiti elegantno i jasno, a u celoj
knjizi sam isticao koliko je elegancija vana. Jasnoa m oe biti inilac koji odreuje da li
je reenje uspeno ili nije dobro zato to ostali ne m ogu da ga razum eju.
to se tie jasnoe, Java 1.0 je proizvela zbrku zbog korienja term ina ,,enum eration
um esto uobiajenog i prihvaenog term ina iterator" za objekat koji bira svaki element
neke sekvence. U nekim jezicim a ak se i nabrojani tipovi nazivaju ,,enum erators! Ta
greka je ispravljena u Javi, ali interfejs E n u m e ra tio n nisu smeli sam o tako da izbace, pa
se jo via u starim (a ponekad i u novim !) program im a, biblioteci i dokum entaciji.
R eenja o d a b r a n ih vebi d a ta su u e le k tro n sk o m d o k u m e n tu Thc Thinking in Java Annotatcd Sola-
tion Guide, koji se m o e k u p iti n a lok aciji www.MindView.com.
Anotacije
A notacije (ili m etapodaci) fo rm a lizo va n su nain dodavanja inform acija kodu, to olakava
kasniju upotrebu tih p o d a ta k a .'
prave jezike konstrukcije, im aju stru k tu ru , a njihovi tipovi se proveravaju u vrem e pre-
voenja. Kod je elegantniji i lake se odrava ukoliko su sve inform acije zadrane u
izvornom kodu, a ne u kom entarim a. K orienjem i nasleivanjem API-ja i alatki za
anotacije, Oi pom ou spoljnih biblioteka za rad s bajtkodom koje ete upoznati u ovom
poglavlju, moete obaviti dalekosenu proveru i o brad u izvornog koda i bajtkoda.
Osnovna sintaksa
U donjem prim eru, m etoda p ro b n o Iz v rse n je () im a anotaciju @Test. Sama po sebi ona
ne radi nita, ali e prevodilac proveriti im ate li deftniciju anotacije @Test u putanji au-
tom atskog prevoenja i pakovanja (builda). Kao to ete videti u nastavku poglavlja,
pom ou refleksije m oete napraviti alatku koja e tu m etodu izvravati.
//: anotacije/MozeSeTestirati.java
package anotacije;
import net.mindview.atunit.*;
Definisanje anotacije
Sledi definicija gornje anotacije. Videete da definicije anotacija mogo lie na definicije
interfejsa. Zapravo, prevodilac od njih pravi datoteke klasa kao od svakog drugog Java in-
terfejsa:
OTarget(ElementType.METHOD)
@Retenti on(RetentionPol icy.RUNTIME)
public Ointerface Test {} ///:-
Sem simbola definicija oznake @Test lii na prazan interfejs. Definicija anotacije
zahteva i m etaanotacijc @Target i @ Retention. @Target definie gde se anotacija moe
prim eniti (recimo, ispred m etode ili polja). @ Retention definie da li e anotacija biti
dostupna u izvornom kodu (SOURCE), u datotekam a klasa (CLASS) ili u vreme izvr-
avanja (RUNTIME).
Poglavlje 20: Anotacije 847
Anotacije najee sadre elcm enie za zadavanje vrednosti u anotacijama korisnika. Pro-
gram ili alatka m ogu upotrebljavati te param etre prilikom obrade anotacije korisnika. Ele-
m enti lie na m etode interfejsa, sem to im moete definisati podrazum evane vrednosti.
A notaciju bez elem enata, kao to je @Test, nazivam o m arker anotacija.
Sledi jednostavna anotacija koja prati sluajeve upotrebe u projektu. Program eri ano-
tiraju svaku m etodu ili skup m etoda koje zadovoljavaju zahteve odreenog sluaja
upotrebe. Kad prebroji realizovane sluajeve upotrebe, rukovodilac projekta moe stei
uvid u napredovanje projekta, a program eri koji odravaju projekat lako pronalaze slua-
jeve upotrebe kada treba da auriraju poslovna pravila u sistem u ili da otkriju i otklone
greke u njima.
/ / : a n o t a c i j e / S l u c a j l l p o t r e b e . ja v a
im p o r t j a v a . l a n g . a n n o t a t i o n . * ;
@Target(ElementType.METHOD)
@ R e te n tio n ( R e te n tio n P o li c y . RUNTIME)
p u b l i c @ in te rfa c e S lu c a jU p o tre b e (
publ i c i n t i d ( ) ;
p u b l i c S t r i n g o p i s ( ) d e f a u l t "nema o p i s a " ;
} ///:-
/ / : a n o ta c ij e /U s lu z n e M e to d e Z a L o z in k e .ja v a
im p o r t j a v a . u t i 1 . * ;
p u b l i c c la s s UsluzneMetodeZaLozinke {
@ SlucajU potrebe(id = 47, o p is =
"L o z in k a mora s a d r a t i barem jednu b r o j k u " )
p u b l i c boolean p r o v e r i L o z i n k u ( S t r i n g l o z i n k a ) {
retu rn (lo z in k a .m a tc h e s ( " \\w * \\d \\w * " )) ;
}
@S1ucajUpotrebe(id = 48)
p u b lic S trin g s if r ir a jL o z in k u ( S t r in g lo z in k a ) {
r e t u r n new S t r i n g B u i 1d e r ( l o z i n k a ) . r e v e r s e ( ) - t o S t r i n g ( ) ;
}
@S1ucajUpotrebe(id = 49, o p is =
"Nova lo z in k a ne moe b i t i je dnaka p re th o d n im ")
p u b l i c boolean p ro v e r a N e p o n a v lja n ja L o z in k e (
L i s t < S t r i n g > p re th o d n e Lo z in k e , S t r i n g l o z i n k a ) {
r e tu rn !p re th o d n e L o z in k e .c o n ta in s (lo z in k a );
}
} ///:-
848 Misliti na Javi
V rednosti elem enata anotacije izraene su kao parovi im e-vrednost u zagradam a iza
deklaracije anotacije @SlucajUpotrebe. Anotaciji m etode sifrirajLozinku( ) ovde nije
bila prosleena vrednost za elem ent opis, pa e se podrazum evana vrednost definisana u
@interface SlucajUpotrebe pojaviti kada ta klasa prode kroz procesor anotacija.
Ovakav sistem bi m ogao ,,skicirati stru k tu ru vaeg sistema, s tim to bi m u trebalo
dodati jo neke funkcije.
Metaanotacije
U jeziku Java tren u tn o postoje sam o tri (prethodno opisane) standardne anotacije i etiri
definisane m etaanotacije. Ovo su m etaanotacije za anotiranje anotacija:
Uglavnom ete sami definisati svoje anotacije i pisati sopstvene procesore koji e ih
obraivati.
/ / : a n o t a c ij e / P r a c e n je S lu c a je v a U p o t r e b e . ja v a
iraport j a v a . l a n g . r e f l e c t . * ;
im p o r t j a v a . u t i l . * ;
Poglavlje 20: Anotacije 849
p u b l i c c la s s P ra ce n je S lu c a je v a llp o tre b e {
p u b l i c s t a t i c v o i
p r a t i S l u c a j e v e U p o t r e b e ( L i s t < I n t e g e r > s l u c a je v iU p o t r e b e , Class<?> c l ) {
f o r(M e th o d m : c l.g e t D e c la r e d M e t h o d s ( ) ) {
Slu c a jU p o tre b e su = m . g e t A n n o t a t i o n ( S l u c a j U p o t r e b e . c l a s s ) ;
i f ( s u != n u l l ) {
S y s t e m . o u t . p r in t ln ( ''P r o n a e n s l u a j u p o tr e b e : " + s u . i d ( ) +
" " + s u .o p is O );
s lu c a je v iU p o tre b e .re m o v e (n e w I n t e g e r ( s u . i d ( ) ) ) ;
}
}
f o r ( i n t i : s l u c a je v iU p o t r e b e ) {
S y s t e m . o u t . p r i n t l n ( " U p o z o r e n j e : n e d o s ta je s l u a j u p o tr e b e - " + i ) ;
}
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
L i s t < I n t e g e r > s lu c a je v iU p o t r e b e = new A r r a y L i s t < I n t e g e r > ( ) ;
C o l l e c t i o n s . a d d A l l ( s l u c a j e v i U p o t r e b e , 47, 48, 49, 5 0 );
p ra t iS 1 u c a je v e U p o t re b e ( s l u c a je v iU p o t re b e , Usl uzneMetodeZa
L o z in k e .c la s s );
}
} / * Is p is :
Pronaen s l u a j upo tre b e :47 Lozinka mora s a d r a t i barem jednu b r o jk u
Pronaden s l u a j u p o tr e b e :4 8 nema opisa
Pronaen s l u a j u p o tr e b e :4 9 Nova l o z i n k a ne moe b i t i je dnaka p re thodnim
Upozore nje : n e d o sta je s l u a j u p otrebe-5 0
* ///:-
Elementi anotacija
O znaka @SlucajUpotrebe definisana u program u SlucajUpotrebe.java sadri int ele-
inent id i String element opis. Ovo su dozvoljeni tipovi elem enata anotacija:
Svi prosti tipovi (int, float, boolean itd.)
String
Class
N abrojani tipovi
Anotacije
Nizovi svih prethodnih tipova
850 Misliti na Javi
Prevodilac e prijaviti greku ako pokuate da upotrebite neki rugi tip. Vodite rauna
0 tom e da ne smete koristiti om otake klase, ali zbog autom atskog pakovanja to zapravo
1nije ogranienje. Dozvoljeni su i elem enti koji su sami anotacije. Kao to ete videti malo
kasnije, ugnedene anotacije m ogu veom a dobro da poslue.
/ / : a n o t a c i j e / S i m u l a c i j a N u l 1 . ja v a
im p o rt j a v a . 1a n g .a n n o t a t io n
@Target(E1ementType.METHOD)
@Retenti o n ( R e t e n t io n P o li c y . RUNTIME)
p u b l i c @ in te rfa c e S i m u l a c i j a N u l l {
p u b lic i n t id ( ) d e fa u lt -1;
p u b l i c S t r i n g o p i s () d e f a u l t
) / / / =-
anotacija, sve te inform acije zadrali biste u izvornoj datoteci zrna Jave. Za to bi vam bile
potrebne anotacije koje definiu im e tabele baze podataka pridruene tom zrnu, kolone i
SQL tipove za preslikavanje svojstava zrna.
Sledi anotacija zrna koja procesoru anotacija kazuje da napravi tabelu baze podataka:
/ / : a n o t a c ije / b a z a p o d a t a k a / T a b e la B P . ja v a
package a n o t a c ij e . b a z a p o d a t a k a ;
im p o r t j a v a . l a n g . a n n o t a t i o n . * ;
Svaki ElementType koji specificirate u anotaciji @Target jeste ogranienje koje prevo-
diocu kazuje da se ta anotacija moe prim eniti sam o na taj odreeni tip. Za nabrojani tip
ElementType m oete specificirati jednu vrednost ili listu proizvoljnih kom binacija vred-
nosti razdvojenih zarezima. Ako anotaciju elite da prim enite na svaki ElementType,
m oete p o tp u n o da izostavite anotaciju @Target, mada to nije uobiajeno.
O bratite panju na to da @TabelaBP im a elem ent im e ( ), tako da anotacija moe dati
ime tabele baze podataka koju e procesor napraviti.
Evo anotacija za polja ovog zrna Jave:
/ / : a n o ta c ij e / b a z a p o d a t a k a / O g r a n ic e n ja . ja v a
package a n o ta c ije . b a z a p o d a t a k a ;
im p o r t j a v a . l a n g . a n n o t a t i o n . * ;
@Target(ElementType.FIELD)
@ R e te n tio n(R e te n ti onPoli c y . RUNTIME)
p u b l i c @ in te rfa c e O g ra n ic e n ja {
boolean p rim a r n iK L J u c () d e f a u l t f a l s e ;
boolean d o z v o li N u l1 () d e f a u l t t r u e ;
boolean j e d i n s t v e n o ( ) d e f a u l t f a l s e ;
} ///:-
/ / : a n o ta c ij e / b a z a p o d a t a k a / S Q L S t r in g . ja v a
package a n o t a c i j e . bazapodataka;
im p o r t j a v a . l a n g . a n n o t a t i o n . * ;
@Target(ElementType.FIELD)
@Retenti o n ( R e t e n t i o nPoli c y . RUNTIME)
p u b l i c @ in te rfa c e SQLString {
i n t v r e d n o s t O d e f a u l t 0;
S t r i n g ime() d e f a u l t
O g ra n ic e n ja o g r a n i c e n j a ( ) d e f a u l t @0granicenja;
) ///:-
852 Misliti na Javi
/ / : a n o t a c ij e / b a z a p o d a t a k a / S Q L I n t e g e r . ja v a
package a n o t a c ije . b a z a p o d a t a k a ;
im p o r t j a v a . l a n g . a n n o t a t i o n . * ;
/ / : a n o ta c ije / b a z a p o d a t a k a / J e d i n s t v e n o s t . ja v a
/ / Primer ugneenih a n o t a c i j a
package a n o ta c ije . b a z a p o d a t a k a ;
p u b l i c @ in te rfa c e J e d in s t v e n o s t {
O g ra n ic e n ja o g ra n ic e n ja O
d e f a u l t @ O gra nic enja (je di n s t v e n o = t r u e ) ;
} ///:-
/ / : a n o ta c ij e / b a z a p o d a t a k a / C la n . ja v a
package a n o ta c ije . b a z a p o d a t a k a ;
@TabelaBP(ime = "CLAN")
p u b l i c c la s s Clan {
@SQLString(30) S t r i n g li c n o l m e ;
@SQLString(50) S t r i n g prezlm e;
@SQLInteger I n t e g e r s t a r o s t ;
@SQLString(value = 30,
Poglav|je 20: Anotacije 853
o g r a n ic e n ja = @ O g r a n ic e n ja ( p r im a r n iK lju c = t r u e ) )
S trin g id e n t if ik a to r ;
s t a t i c i n t b ro jC la n o v a ;
p u b lic S trin g d a j I d e n t i f i k a t o r ( ) { re tu rn i d e n t i f i k a t o r ; )
p u b l i c S t r i n g d a jL ic n o Im e ( ) { r e t u r n l i c n o l m e ; )
p u b l i c S t r i n g d a jP re z Im e () { r e t u r n pre z lm e ; }
p u b lic S trin g to S trin g O { re tu rn id e n ti f i ka to r; }
p u b lic In te ge r d a jS ta ro s t() { re tu rn s ta ro s t; }
} ///= -
A notaciji @TabelaBP klase data je vrednost CLAN koja e biti upotrebljena kao im e
tabele. Svojstva zrna licnolm e i prezlm e an o tirana su pom ou @SQLStringova i imaju
vrednosti 30 odnosno 50. Te anotacije su zanimljive iz dva razloga: prvo, koriste
podrazum evanu vrednost ugneene anotacije @Ogranicenja, i drugo, koriste krai ob-
lik pisanja. Ako anotacija im a sam o jedan elem ent i vi m u date im e value, ne m orate da
piete parove im e-vrednost; dovoljno je da specificirate sam o vrednost (engl. value) u za-
gradam a. To vai za sve dozvoljene tipove elem enata. N aravno, tada elem entu m orate dati
im e vrednost", ali u gornjem sluaju ipak dobijate sem antiki sm islenu specifikaciju
anotacije koja se lako ita:
@SQLStri n g (30)
Drugaija reenja
U ovom sluaju im a i drugih naina da se naprave anotacije. Na primer, m oem o napraviti
samo jednu klasu anotacije @KolotiaTabele u ijem enum elem entu definiemo vrednosti
kao to su STRING, INTEGER, FLOAT itd. O nda ne bism o m orali imati interfejs (@inter-
face) za svaki SQL tip, ali bism o izgubili m ogunost da kvalifikujemo tipove pom ou do-
datnih elemenata kao to su velicina ili preciznost , pa je teta verovatno vea od koristi.
Stvarni SQL tip m oem o opisati String elem entom , npr. VARCHAR(30) ili INTEGER.
Time ne bism o izgubili m ogunost da kvalifikujem o tipove, ali bi preslikavanje }ava tipa
u SQL, tip bilo zakljuano u kodu, a to nije dobro. Ne elimo da zbog prom ene baze
podataka m oram o ponovo da prevodim o klase; bilo bi elegantnije saoptiti procesoru
anotacija da koristim o drugu varijantu" SQL-a i prepustiti njem u da tokom obrade
anotacija sam o tom e vodi brigu.
854 Misliti na Javi
Tree reenje bilo bi korienje dva tipa anotacija, @ Ogranicenja i relevantnog SQL
tipa (recimo, @SQLInteger) za anotiranje eljenog polja. To jeste malo zapetljano, ali
prevodilac dozvoljava proizvoljan broj razliitih anotacija za svako odredite (engl. tar-
get). Kada koristite vie anotacija, istu anotaciju ne sm ete u potrebiti dvaput.
Realizacija procesora
Sledi prim er procesora anotacija koji uitava datoteku klase, trai u njoj anotacije baze
podataka i generie SQL kom andu za pravljenje takve baze podataka:
/ / : a n o ta c ije / b a z a p o d a t a k a / T v o r a c T a b e le . ja v a
/ / R e f l e k t i v n i p ro ce so r a n o t a c i j a .
/ / {Arg um e n ti: a n o ta c ije . b a z a p o d a t a k a . C la n }
package a n o t a c ije . b a z a p o d a t a k a ;
im p ort j a v a . l a n g . a n n o t a t i o n . * ;
im p o rt j a v a . 1a n g . r e f l e c t . * ;
im p o rt j a v a . u t i l . * ;
p u b l i c c la s s TvoracTabele {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) throvvs E xc e p tio n {
i f ( a r g s . 1ength < 1) {
S y s te m .o u t.p r in tln ( " a rg u m e n ti: a n o tirane k la s e " );
System.exi t ( 0 ) ;
}
f o r ( S t r i n g imeKlase : a rg s) {
Class<?> cl = C la s s .fo rN a m e (im e K la s e );
TabelaBP tabelaBP = c l . g e t A n n o t a t i o n ( T a b e l a B P . c l a s s ) ;
i f (tabelaBP == n u l l ) {
S y s te m .o u t.p rin tln (
"U k l a s i " + imeKlase + " nema a n o t a c i j a T abela BP ");
c o n t i nue;
}
S t r i n g imeTabele = t a b e l a B P . i m e ( ) ;
/ / Ako j e ime prazno, u p o tr e b i ime Cla ss:
i f ( i m e T a b e l e . l e n g t h ( ) < 1)
imeTabele = c l .getName() .t o llp p e r C a s e ( ) ;
L i s t < S t r i n g > defKolona = new A r r a y L i s t < S t r i n g > ( ) ;
Poglavlje 20: Anotacije 855
f o r ( F ie l d p o lje : cl .g e tO e c la re d F ie ld s O ) {
S t r i n g imeKolone = n u l l ;
A n n o t a t i o n [ ] anot = p o l j e . g e t D e c l a r e d A n n o t a t i o n s ( ) ;
i f ( a n o t . l e n g t h < 1)
c o n t in u e ; / / N i j e kolona t a b e l e baze podataka
i f ( a n o t [ 0 ] i n s t a n c e o f SQLInteger) {
SQLInteger s l n t = (SQLInteger) a n o t [ 0 ] ;
/ / Ako ime n i j e s p e c i f i c i r a n o , u p o t r e b i ime p o l j a
i f ( s l n t . i m e ( ) . l e n g t h ( ) < 1)
imeKolone = p o l j e . g e t N a m e ( ) , t o U p p e r C a s e ( ) ;
e ls e
imeKolone = s l n t . i m e ( ) ;
d e fKolo na.a dd(im eK olone + " INT" +
d a jO g ra n ic e n ja (s In t.o g ra n ic e n ja () ) ) ;
}
i f ( a n o t [ 0 ] in s t a n c e o f SQLString) {
SQLString s S t r i n g = (SQLString) a n o t [ 0 ] ;
/ / Ako ime n i j e s p e c i f i c i r a n o , u p o tr e b i ime p o l j a .
i f ( s S t r i n g . i me( ) . l e n g t h ( ) < 1)
imeKolone = p o l j e . g e t N a m e ( ) . t o U p p e r C a s e ( ) ;
el se
imeKolone = s S t r i n g . i m e ( ) ;
d e fKolo na.a dd(im eK olone + " VARCHAR(" +
s S trin g .v re d n o s tO + " ) " +
daj Ograni cenj a ( s S t r i ng. o g ra n i cenj a ( ) ) ) ;
}
S t r i n g B u i l d e r komandaZaPravljenje = new S t r i n g B u i l d e r (
"NAPRAVI TABELU 11 + imeTabele + " ( " ) ;
f o r ( S t r i n g defKolone : defKolona)
k om an d a Za P ra v lje n je .a p p en d ("\n " + defKolo ne + " , " ) ;
/ / Uklo ni p r a t e i zarez
S t r i n g na p ra viT a be lu = k o m a n d a Z a P ra v lje n je . s u b s t rin g (
0, k o m a n d a Z a P ra v lje n je . le n g t h f ) - 1) + " ) ; " ;
S y s te m .o u t. p r i n t l n ( " S Q L za p r a v l j e n j e t a b e l e za kla su " +
imeKlase + " g l a s i : \ n " + n a p r a v i T a b e l u ) ;
p r i v a t e s t a t i c S t r i n g d a jO g r a n ic e n ja ( O g r a n ic e n ja og r) {
S t r i n g o g ra n ic e n ja =
i f ( lo g r.d o z v o liN u l1())
o g r a n ic e n ja += " NIJE NULL";
i f ( o g r . p r i m a r n i K L J u c ())
o g r a n ic e n ja += " PRIMARNI KLJUC";
i f ( o g r . je d in s tv e n o O )
o g r a n ic e n ja += " JEDINSTVENO";
r e t u r n o g r a n ic e n ja ;
856 Misliti na Javi
} /* Isp is:
SQL za p r a v l j e n j e t a b e l e za k la su a n o ta c ije . b a z a p o d a t a k a . C la n g la s i:
NAPRAVI TABELU CLAN(
LICNOIME VARCHAR(30)) ;
SQL za p r a v l j e n j e t a b e l e za k la s u a n o ta c ije . b a z a p o d a t a k a . C la n g la s i:
NAPRAVI TABELU CLAN(
LICNOIME VARCHAR(30),
PREZIME VARCHAR(50)) ;
SQL za p r a v l j e n j e t a b e l e za k la su a n o ta c ije . b a z a p o d a t a k a . C la n g la s i:
NAPRAVI TABELU CLAN(
LICNOIME VARCHAR(30),
PREZIME VARCHAR(50),
STAROST I N T ) ;
SQL za p r a v l j e n j e t a b e l e za kla su a n o ta c ije . b a z a p o d a t a k a . C la n g la s i:
NAPRAVI TABELU CLAN(
LICNOIME VARCHAR(30),
PREZIME VARCHAR(50),
STAROST INT,
IDENTIFIKATOR VARCHAR(30) PRIMARNI KLJUC);
* ///:-
M etoda m a in ( ) prolazi kroza sva im ena klasa na kom andnoj liniji. Svaku klasu redom
uitava m etoda forN am e( ) i naredbom getAnnotation(TabelaBP.class) proverava im a li
anotaciju @TabelaBP. Ukoliko ima, ime te tabele biva pronaeno i uskladiteno. Zatim se
sva polja te klase uitavaju i proveravaju m etodom getD eclaredA nnotations( ). O na
vraa niz svih anotacija definisanih za datu m etodu. O peratorom instanceof utvrduje se
da li su te an o ta je tipova @SQLlnteger odnosno @SQLString, i u svakom od tih slua-
jeva pravi se relevantni String odlom ak sa im enom kolone tabele. Poto se interfejsi ano-
tacija ne m ogu nasleivati, korienje m etode getD ecIaredA nnotations( ) jedini je nain
da se postigne priblino polim orfno ponaanje.
Ugneenu anotaciju @Ogranicenja prosleujem o m etodi dajO granicenja( ) koja
gradi String to sadri ta SQL ogranienja.
Vredi spom enuti da je goreopisana tehnika pom alo naivan nain definisanja preslika-
vanja objekata na relacione baze podataka. Ako prom enite im e tabele, m oraete iznova da
prevodite Java kod, poto anotacija tipa @TabelaBP prim a ime tabele kao param etar. To
nije naroito poeljno ponaanje. Ve je m nogo dostupnih struktura (engl. fram ew ork) za
preslikavanje objekata na relacione baze podataka, a u sve vie njih koriste se anotacije.
Veba 1: (2) Realizujte vie SQL tipova u prim eru s bazom podataka.
Projekat: Izm enite prim er s bazom podataka tako da se pom ou JDBC-a povezuje i radi
s pravom bazom podataka.
Projekat: Izm enite prim er s bazom podataka tako da um esto pisanja SQL koda pravi od-
govarajue XML datoteke.
@Target(E1ementType.TYPE)
@Retenti o n (R e t e n t io n P o li c y . SOURCE)
p u b l i c @ in t e rf a c e I z d v o j i I n t e r f e j s {
p u b lic S trin g v re d n o st();
) ///:-
/ / : a n o ta c ij e / M n o z a c .j a v a
/ / Obrada a n o t a c i j a pomou APT-a.
package a n o t a c i j e ;
Klasa M nozac (koja radi sam o s pozitivnim celim brojevim a) im a m etodu p o m n o z i()
koja vie p u ta poziva privatnu m etodu a d d ( ) da bi obavila m noenje. M etoda add( ) nije
javna, te stoga nije ni deo interfejsa. A notaciji je data vrednost IfM nozaca, to je ime in-
terfejsa koji treba napraviti.
Sada nam treba procesor za izdvajanje:
p u b l i c c la s s P r o c e s o r Z a l z d v a j a n j e l n t e r f e j s a
implements A n n o ta tio n P ro c e s s o r {
p r i v a t e f i n a l An n o ta tio n P ro c e ss o rE n vir o n m e n t env;
p r i v a t e A r r a y L is t < M e th o d D e c la r a t io n > m e t o d e l n t e r f e j s a =
new A r r a y L i s t < M e t h o d D e c l a r a t i o n > ( ) ;
p u b lic P ro c e s o rZ a Iz d v a ja n je In te rfe js a (
A n n o ta tio nP ro ce ss o rE n vir on m e n t env) { t h i s . e n v = env; }
Poglavlje 20: Anotacije 859
p u b l i c v o id p ro c e s s ( ) {
f o r ( T y p e D e c l a r a t i o n d e k lT ip a :
e n v . g e t S p e c if ie d T y p e D e c la r a t io n s O ) {
I z d v o j i l n t e r f e j s anot =
d e k lT ip a .g e tA n n o ta tio n (Iz d v o jiIn te rfe js .c la s s );
i f ( a n o t == n u l l )
bre ak;
f o r ( M e t h o d D e c la r a t io n m : d e k lT ip a . g e t M e t h o d s O )
i f ( m . g e t M o d i f i e r s ( ) . c o n t a in s ( M o d ifie r . P U B L I C ) &&
! ( m . g e t M o d i f i e r s O . c o n t a in s ( M o d if ie r .S T A T I C ) ))
m eto d e ln te rfe jsa .a d d (m );
i f ( m e t o d e l n t e r f e j s a . s i z e O > 0) {
try {
P r i n t W r i t e r stampac =
e n v . g e t F i 1e r ( ) . c r e a t e S o u r c e F i l e ( a n o t . v r e d n o s t ( ) ) ;
s ta m p a c .p rin tln C 'p a k e t " +
d e k lT ip a .g e tP a c k a g e O .getQual ifie d N a m e () + " ; " ) ;
s ta m p a c .p rin tln ("ja v n i in t e r f e js " +
a n o t.v re d n o s t() + " { " ) ;
f o r ( M e t h o d D e c la r a t io n m : m e t o d e ln t e r f e js a ) {
s ta m p a c .p rin t(" ja v n i " ) ;
s ta m p a c . p rin t ( m .g e t R e t u rn T y p e () + " " ) ;
s ta m p a c.p ri nt(m .g e tSim p le N a m e() + 11 ( " ) ;
i n t i = 0;
f o r ( P a r a m e t e r D e c la r a t io n parm :
m .ge tP ara m e te rs ( ) ) {
s t a m p a c . p r in t ( p a r m . g e tT y p e ( ) + " " +
parm .getS im ple N am eO );
i f ( + + i < m .ge tP ara m e te rs( ) . s i z e ( ) )
stam pac.p r i n t ( " , " ) ;
}
s ta m p a c .p ri n t l n ( " ) ; " ) ;
}
stampac.p r i n t l n ( " } " ) ;
s ta m p a c .c lo s e O ;
} c a t c h ( IO Exception io e ) {
th ro w new R u n tim e E x c e p t io n ( io e ) ;
} ///:-
Sve se ra d i u m e to d i pro cess( ). P o m o u k lase M ethodDeclaration i n je n e m e to d e
getM odifiers( ) id e n tifik u je m o ja v n e m e to d e (i z a n e m a r u je m o o n e k o je su sta ti n e )
o b r a iv a n e klase. U k o lik o ih p r o n a e m o , s k la d i tim o ih u o b je k tu tip a ArrayList i
u p o tr e b lja v a m o za p ra v lje n je m e to d a n o v o g in te rfe jsa u d a to te c i .java.
O b r a tite p a n ju n a to d a o b je k a t tip a A nnotationProcessorEnvironm ent p ro sle -
u je m o k o n s t r u k t o r u . T o m o b je k tu m o e te slati u p ite za sve tip o v e (d e fin ic ije k lasa) k o je
a la tk a apt o b r a u je i p o m o u n jeg a m o e te d o b iti o b je k a t tip a Messager i o b je k a t tip a
86 0 Misliti na Javi
Filer. Messager slui za slanje poruka korisniku, npr. greaka koje su nastale tokom obra-
de i njihovih m esta u izvornom kodu. Filer je neka vrsta PrintW ritera za pravljenje novih
datoteka. Umesto obinog PrintW ritera najee se koristi objekat tipa Filer zato to
om oguuje alatki apt da prati nove datoteke koje napravite i, ako treba, pronalazi u njim a
anotacije i prevodi ih.
Videete i da m etoda createSourceFile( ) otvara obian izlazni tok s tanim im enom
odgovarajue Java klase ili interfejsa. N em a podrke za pravljenje Javinih jezikih kon-
strukcija, pa Javin izvorni kod m orate da generiete pom alo prim itivnim m etodam a
p r in t( ) i p rin tln ( ). To znai da m orate paziti na to da zatvorite sve zagrade koje ste otvo-
rili i da va kod m ora biti sintaksiki ispravan.
M etodu process( ) poziva alatka apt kojoj treba proizvodna m etoda da bi napravila
odgovarajui procesor:
/ / : a n o t a c ij e / P r o i z v o d j a c P r o c e s o r a Z a l z d v a j a n j e l n t e r f e j s a . j a v a
/ / Obrada a n o t a c i j a pomou APT-a.
package a n o t a c i j e ;
im p o r t c o m . s u n . m i r r o r . a p t . * ;
im p o rt c o m . s u n . m i r r o r . d e c l a r a t i o n . * ;
im p o r t j a v a . u t i l . * ;
p u b l i c c la s s P r o iz v o d j a c P r o c e s o r a Z a l z d v a j a n j e l n t e r f e j s a
implements A n n o ta tio n P ro c e s s o r F a c to ry {
p u b l i c A n n o ta tio n P ro c e s s o r g e tP ro c e s s o rF o r(
Set<AnnotationTypeDec1 a r a t i o n > a t d s ,
A n n o ta tio n P ro c e s s o r E n v ironment env) {
r e t u r n new P r o c e s o r Z a l z d v a j a n j e l n t e r f e j s a ( e n v ) ;
}
p u b l i c C o l l e c t i o n < S t r i n g > s u p p o r te d A n n o ta tio n T y p e s () {
return
C o lle c tio n s .s in g le to n ("a n o ta c ije .Iz d v o jiIn te rfe js ");
}
p u b l i c C o l l e c t i o n < S t r i n g > s u p p o r te d O p tio n s ( ) {
r e t u r n C o l1e c t io n s . e m p t y S e t ( ) ;
}
} III'--
U interfejsu A nnotationProcessorFactory sam o su tri metode. Kao to vidite, procesor
pravi m etoda getProcessorFor( ) koja prim a Set (skup) deklaracija tipova (fava klasa koje
alatka apt obrauje) i objekat tipa A nnotationProcessorEnvironm ent koji sm o ve pro-
putali kroz procesor. Ostale dve metode, supportedA nnotationTypes( ) i supportedO p-
tions( ), postoje da biste mogli proveriti imate li procesore za sve anotacije koje je apt
pronaao i da li podravate sve opcije specificirane na kom andnoj liniji. Naroito je vana
metoda getProcessorFor( ) zato to e vas apt, ako u kolekciji String ne vratite puno ime
kJase (tipa) anotacije, upozoriti da nem a relevantnog procesora i izai, a da nita ne uradi.
Procesor i proizvodna m etoda su u paketu anotacije, pa je za gornju stru k tu ru direk-
torijum a kom andna Iinija ugraena u kom entar Exec na poetku program a Proce-
sorZalzdvajanjelnterfejsa.java. Time se alatki apt kazuje da upotrebi goredefinisanu
Poglav|je 20: Anotacije 861
proizvodnu m etodu i da obradi datoteku Mnozac.java. O pcija -s zadaje da se sve nove da-
toteke m oraju napraviti u direktorijum u anotacije. Ovako izgleda generisana datoteka If-
Mnozaca.java, to ste mogli pogoditi proitavi naredbe p rin tln ( ) u gornjem procesoru:
package a n o t a c i j e ;
p u b l i c i n t e r f a c e IfMnozaca {
p u b l i c i n t pomnozi ( i n t x , i n t y ) ;
}
/ / : a n o t a c i j e / b a z a p o d a t a k a /P r o iz v o d ja c P r o c e s o r a Z a P r a v lj e n je T a b e la . ja v a
/ / Prim er s bazom podataka n a p r a v lje n po p ro je ktn o m obrascu V i s i t o r .
/ / {Exec: apt - f a c t o r y
/ / a n o ta c ije . b a z a p o d a t a k a . P r o iz v o d a P ro c e s o r a Z a P r a v lje n je T a b e la
/ / b a z a p o d a ta k a /C la n .ja v a -s bazapodataka}
package a n o ta c ije . b a z a p o d a t a k a ;
im p o r t com.sun, m ir r o r . a p t . * ;
im p o r t c o m . s u n . m i r r o r . d e c l a r a t i o n . * ;
im p o r t c o m . s u n . m i r r o r . u t i 1 . * ;
im p o rt j a v a . u t i 1 . * ;
im p o r t s t a t i c c o m . s u n . m i r r o r . u t i 1. D e c l a r a t i o n V i s i t o r s . * ;
862 Misliti na Javi
p u b l i c c la s s P ro iz v o d ja c P r o c e s o r a Z a P r a v lje n je T a b e la
implements A n n o ta tio n P ro c e s s o r F a c to ry {
p u b l i c A n n o ta tio n P ro c e s s o r g e tP ro c e s s o rF o r(
Se t< A n n o ta ti onTypeDec1aration> a t d s ,
Ann o ta tio nP ro c e s s o rE n v ir on m e n t env) {
r e t u r n new P r o c e s o r Z a P r a v lje n je T a b e la ( e n v ) ;
}
p u b l i c C o l l e c t i o n < S t r i n g > s u p p o rte d A n n o ta tio n T y p e s () {
re tu rn A rra y s .a s L is t(
" a n o ta c ije .b a z a p o d a ta k a .T a b e la B P " ,
" a n o t a c ije . b a z a p o d a t a k a . O g r a n ic e n j a " ,
" a n o t a c ije . b a z a p o d a t a k a . SQLStri n g " ,
" a n o t a c ije . b a z a p o d a t a k a . S Q L I n t e g e r " ) ;
}
p u b l i c C o l l e c t i o n < S t r i n g > s u p p o r te d O p tio n s () {
r e t u r n C o l1e c t i o n s . emptySet( ) ;
}
p r i v a t e s t a t i c c la s s P ro cesorZ aPravlj e n je T a b e la
implements A n n o ta tio n P ro c e s s o r {
p r i v a t e f i n a l Annota tio nP ro ce s so rE n vir on m e n t env;
p r i v a t e S t r i n g sql =
p u b l i c P r o c e s o rZ a P r a v lje n je T a b e la (
Annota tio nP ro c e ss o rE n v ir on m e n t env) {
t h i s . e n v = env;
}
p u b l i c v o id p ro c e s s () {
f o r ( T y p e D e c la r a t io n d e k lT ip a ;
e n v .g e t S p e c if ie d T y p e D e c la r a t i o n s ( ) ) {
d e k l Ti p a . a c c e p t ( g e t D e c la r a t i onScanner(
new P o s e t i 1a c Z a P r a v l j e n j e T a b e l a ( ) , N0_0P)) ;
sql = s q l . s u b s t r i n g ( 0 , sq1 . 1 e n g th ( ) - 1) + " ) ; " ;
S y s t e m . o u t . p r in t ln ( " S Q L za p r a v l j e n j e g l a s i ; \ n " + s q l ) ;
sql = " " ;
}
}
p r i v a t e c la s s P o s e tila c Z a P r a v lj e n je T a b e la
extends S i m p l e D e c l a r a t i o n V i s i t o r {
p u b l i c v o id v i s i t C l a s s D e c l a r a t i o n (
C1 a s s D e c la r a t io n d) {
TabelaBP tabelaBP = d . g e t A n n o t a t io n ( T a b e la B P . c la s s ) ;
if ( t a b e l a B P != n u l l ) {
sql += "NAPRAVI TABELU " ;
sql += ( t a b e l a B P . i m e ( ) . 1e n g th () < 1)
? d.getS im ple Nam e().toUppe rCase()
: t a b e l a B P . im e ( ) ;
sql += " ( " ;
}
}
Poglavlje 20: Anotacije 863
p u b l i c v o id v i s i t F i e l d D e c l a r a t i o n (
F ie l d D e c l a r a t i o n d) {
S t r i n g imeKolone =
i f ( d . g e t A n n o t a t io n ( S Q L I n t e g e r . c la s s ) != n u l l ) {
SQLInteger s l n t = d . g e t A n n o t a t io n (
S Q L I n t e g e r . c la s s ) ;
/ / Ako ime n i j e s p e c i f i c i r a n o , u p o tr e b i ime p o l j a .
i f ( s l n t . i m e ( ) . l e n g t h ( ) < 1)
imeKolone = d .g etS im p le N a m e ().to U p pe rC a s e ();
el se
imeKolone = s l n t . i m e ( ) ;
sql += " \ n " + imeKolone + " INT" +
d a jO g ra n ic e n ja (s In t.o g ra n ic e n ja ()) +
}
i f ( d . g e t A n n o t a t i o n ( S Q L S t r i n g . c l a s s ) != n u l l ) {
SQLString s S t r in g = d . g e t A n n o t a t io n (
S Q L S tr in g . c la s s ) ;
/ / Ako ime n i j e s p e c i f i c i r a n o , u p o tr e b i ime p o l j a .
i f ( s S t r i n g . i m e ( ) . 1 e n g th () < 1)
imeKolone = d.g etS im p le Na m e (). to U p p e r C a s e () ;
el se
imeKolone = s S t r i n g . i m e ( ) ;
sql += " \ n " + imeKolone + " VARCHAR(" +
s S trin g .v re d n o s tO + " ) " +
d a jO g ra n ic e n ja (s S trin g .o g ra n ic e n ja ()) +
}
}
p r i v a t e S t r i n g d a jO g ra n ic e n ja (O g r a n ic e n ja og r) {
S t r i n g o g ra n ic e n ja =
i f ( l o g r . d o z v o l i Nu l1 ( ) )
o g r a n ic e n ja += " NIJE NULL";
i f ( o g r . p r i m a r n i K L J u c())
o g r a n ic e n ja += " PRIMARNI KLJUC";
i f (o g r.je d in s tv e n o O )
o g ra n ic e n ja += " JEDINSTVENO";
} r e t u r n o g ra n ic e n ja ;
}
}
} III--
Ispis rezultata je isti kao u prethodnom prim eru TabelaBP.
U ovom p rim eru su procesor i posetilac u nutranje klase. O bratite panju na to da me-
toda p ro cess( ) sam o dodaje klasu posetioca i inicijalizuje SQL znakovni niz.
O ba param etra m etode getD eclarationScanner( ) jesu posetioci; prvi biva upo-
trebljen pre posete svakoj deklaraciji, a drugi posle. O vom procesoru je potreban sam o
posetilac od pre posete, pa se NO_OP ne daje kao drugi param etar. To je statino polje in-
terfejsa DeclarationVisitor, to je objekat tipa DeclarationV isitor koji ne radi nita.
PosetilacZaPravljenjeTabela nasleduje ldasu Sim pleDeclarationVisitor i redefinie
m etode visitC lassD eclaration( ) i visitFieldD ecIaration( ). SimpleDeclarationVisitor
86 4 Misliti na Javi
p u b l i c c la s s A t U n i t P r i m e r l {
p u b l i c S t r i n g metodaJedan() {
r e t u r n "Ovo j e metodaJedan";
}
p u b l i c i n t metodaDva() {
S y s t e m . o u t . p r i n t l n ( " O v o j e metodaDva");
r e t u r n 2;
}
@Test boolean metodaJedanTest() {
r e t u r n m e t o d a Je d a n().eq u a ls ("O v o j e metodaJedan");
}
@Test boolean m2() { r e t u r n metodaDva() == 2 ; }
@Test p r i v a t e boolean m3() { r e t u r n t r u e ; }
/ / P r i k a z u j e r e z u l t a t u s lu a j u g re a ka :
@Test boolean neuspesanTest() { r e t u r n f a l s e ; }
@Test boolean jo sje danNeuspeh() { r e t u r n f a l s e ; }
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) throws Exce p tio n {
OSIzvrenje.kom anda(
"ja va n e t.m in d v ie w .a tu n it.A tU n it A tU n itP r im e r l" ) ;
}
} / * Is p is :
a n o ta c ije .A tU n itP rim e rl
. metodaJedanTest
. m2 Ovo j e metodaDva
. m3
. neuspesanTest ( f a i l e d )
. josjedanNeuspeh ( f a i l e d )
(5 t e s t s )
p u b l i c c la s s A t U n i t S p o l j n i T e s t e xtends A t U n i t P r i m e r l {
@Test boolean _metodaJedan() {
r e t u r n m e to d a J e d a n ( ) .e q u a ls ( "0 v o j e m eto d a Je d a n");
}
@Test boolean _metodaDva() { r e t u r n metodaDva() == 2 ; }
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) thro ws E xc e p tio n {
OSIzvrenje.komanda(
" ja v a n e t . m i n d v i e w . a t u n i t . A t U n i t A t U n i t S p o l j n i T e s t " ) ;
}
} / * Is p is :
a n o ta c ije .A tU n itS p o l jn iT e s t
. _metodaJedan
. _metodaDva Ovo j e metodaDva
OK (2 t e s t s )
* ///:-
Iz ovog prim era vidi se i vrednost slobodnog davanja im ena (za razliku od obaveznog
test na poetku imena svih testova u JU nitu). Ovde je <Test m etodi koja neposredno te-
stira drugu m etodu dato ime te m etode, uz p o tcrtu (_) na poetku. (Ne tvrdim da je to
idealno reenje, nego sam o pokazujem jed n u od m ogunosti.)
Za pravljenje neugraenih testova m oete upotrebiti i kompoziciju:
p u b l i c c la s s A t U n it K o m p o z ic ija {
A t U n i t P r i m e r l t e s t O b j e k a t = new A t U n i t P r i m e r l ( ) ;
@Test boolean _metodaJedan() {
return
te stO b je k a t.m e to d a J e d a n O . e q u a l s ( 0vo j e m eto d a Je d a n");
}
@Test boolean _metodaDva() {
r e t u r n t e s tO b je k a t.m e to d a D v a () == 2;
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) thro ws Exce p tio n {
O S I z v r e n je . komanda(
Poglavlje 20: Anotacije 867
" ja v a n e t . m i n d v i e w . a t u n i t . A t U n i t A t U n i t K o m p o z i c i j a " ) ;
)
} / * Is p is :
a n o t a c i j e . A t U n i t K o m p o z ic ija
. metodaJedan
. jn etodaDva Ovo j e metodaDva
OK (2 t e s t s )
* ///.-
Za svaki test pravi se po jedan nov lan testObjekat, poto se po jedan objekat tipa
AtUnitKompozicija pravi za svaki test.
N ema posebnih m etoda za proveru uspenosti testiranja kao u JUnitu, ali drugi oblik
m etode @Test om oguuje da vratite tip void (ili boolean, ako i u ovom sluaju elite da
vraate tru e ili false). Za testiranje uspenosti m oete koristiti Javine naredbe assert koje
treba ukljuiti indikatorom -ea na java kom andnoj liniji, ali ih @Unit ukljuuje autom at-
ski. Kao pokazatelj neuspeha m oete upotrebiti ak i izuzetak. Jedan od ciljeva prilikom
projektovanja alatke @Unit bio je da se koliina doatne sintakse svede na najm anju
m eru, pa su za prijavljivanje greaka potrebni sam o Javine naredlie assert i izuzeci. Da je
test neuspean, pokazuje assert koji vrati negativan rezultat ili izuzetak koji potie iz
ispitne m etode, ali @Unit ni u tom sluaju ne prestaje da radi, nego nastavlja ispitivanje
dok ne obavi sve testove. Evo prim era:
p u b l i c c la s s A t U n it P r im e r 2 {
p u b l i c S t r i n g metodaJedan() {
r e t u r n "Ovo j e metodaJedan";
}
p u b l i c i n t metodaDvaO {
S y s te m .o u t. p r i n t l n ( Ovo j e metodaDva");
r e t u r n 2;
}
OTest vo id a s s e r t P r i m e r ( ) {
a s s e r t metodaJedan( ) . e q u a ls ( " 0 v o j e m eto d a Je d a n");
}
@Test v o id ass ertP rim erN euspehaO {
a s s e r t 1 == 2: "Kojeg l i iz n e n a e n ja ! " ;
}
@Test v o id p r i m e r l z u z e t k a ( ) throws I0 E x c e p tio n {
new F i l e I n p u t S t r e a m ( " n i j e d a t o t e k a . t x t " ) ; / / Baca
}
OTest boolean a s s e r t l R e t u r n () {
868 Mlsliti na Javi
(4 t e s t s )
/ / : a n o ta c ij e / H a s h S e t T e s t .j a v a
package a n o t a c i j e ;
im p o r t j a v a . u t i l . * ;
im p o r t n e t . m i n d v i e w . a t u n i t . * ;
im p o r t n e t . m i n d v i e w . u t i l . * ;
p u b l i c c la s s HashSetTest {
HashSet<String> t e s t O b j e k a t = new H a s h S e t < S t r in g > ( ) ;
OTest v o id i n i c i j a l i z a c i j a ( ) {
assert te stO bjeka t.isE m p ty( ) ;
}
@Test v o id _ c o n t a i n s ( ) {
te s tO b je k a t.a d d ("je d a n ");
asse rt te s tO b je k a t.c o n ta in s ( " j e d a n " ) ;
}
@Test v o id _remove() {
te s tO b je k a t.a d d ("je d a n ");
te s tO b je k a t.re m o v e ("je d a n ");
assert te s tO b je k a t.is E m p ty ();
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exce p tio n {
OSIzvrenje.komanda(
" ja v a n e t .m in d v ie w . a t u n i t . A t U n i t H a s h S e tT e s t" ) ;
Poglavjje 20: Anotaclje 869
}
} / * Is p is :
a n o ta c ije .H a s h S e tT e s t
. in ic ija liz a c ija
. _remove
. _ c o n ta in s
OK (3 t e s t s )
* ///:-
p u b l i c c la s s A tU n itP rim e r3 {
p r i v a t e i n t n;
p u b l i c A t U n i t P r i m e r 3 ( i n t n) { t h i s . n = n; }
p u b l i c i n t getN() { r e t u r n n; }
p u b l i c S t r i n g metodaJedan() {
r e t u r n "Ovo j e metodaJedan";
}
p u b l i c i n t metodaDva() {
S y s t e m . o u t . p r i n t l n("Ovo j e metodaDva");
r e t u r n 2;
}
@TestObjectCreate s t a t i c A tU n it P rim e r3 n a p r a v i () {
r e t u r n new A t U n i t P r i m e r 3 ( 4 7 ) ;
}
@Test boolean i n i c i j a l i z a c i j a ( ) { r e t u r n n == 47; }
@Test boolean metodaJedanTest() {
r e t u r n m etodaJedan(). equals("Ovo j e m etodaJedan");
}
@Test boolean m2() { r e t u r n metodaDva() == 2; }
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws E x ce p tio n {
870 Misliti na Javi
OK (3 t e s t s )
* ///:-
M etoda @TestObjectCreate m ora biti statina i vratiti objekat tipa koji testirate - pro-
gram @Unit e se postarati da to bude ispunjeno.
Katkada e vam zatrebati dodatna polja za podrku jedininom testiranju. A notaciju
@TestProperty moete upotrebiti za oznaavanje polja koja se upotrebljavaju sam o za je-
dinino testiranje (da biste mogli da ih uklonite pre isporuke program a klijentu). U na-
rednom p rim eru itam o vrednosti iz znakovnog niza ralanjenog m etodom
S tring.split( ). Taj ulaz se upotrebljava za proizvodnju test objekata:
/ / : a n o t a c i j e / A t U n i t P r i m e r 4 . ja v a
package a n o t a c i j e ;
im p o r t j a v a . u t i l . * ;
im p o r t n e t . m i n d v i e w . a t u n i t . * ;
im p o r t n e t . m i n d v i e w . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s A tU n itP rim e r4 {
s t a t i c S t r i n g t e o r i j a = " A l l b ro n to sa u ru s e s " +
" a r e t h i n a t one end, much MUCH t h i c k e r i n th e " +
" m id d le , and then t h i n again a t the f a r e n d ." ;
p r i v a t e S trin g rec;
/ / I n i c i j a l i z a c i j a g e n e r a to ra s l u a j n i h b ro je v a k o ja z a v i s i od vremena
p r i v a t e Random s lu c a ja n = new Random();
p u b l i c A t U n i t P r i m e r 4 ( S t r i n g re c ) { t h i s . r e c = r e c ; }
p u b l i c S t r i n g dajR ec() { r e t u r n r e c ; }
p u b l i c S t r i n g is p r e t u r a j R e c ( ) {
L i s t< C h ara c te r> znakovi = new A r r a y L i s t < C h a r a c t e r > ( ) ;
fo r(C h a ra cte r z : rec.toC harA rray( ) )
z n a k o v i.a d d (z );
C o l1e c t i o n s . s h u f f l e ( z n a k o v i , s l u c a j a n ) ;
S t r i n g B u i 1der r e z u l t a t = new S t r i n g B u i l d e r ( ) ;
f o r ( c h a r zn : zna k o vi)
re z u lta t.a p p e n d (z n );
retu rn re z u lt a t . t o S tr in g ( );
}
@TestProperty s t a t i c L i s t < S t r i n g > u la z =
A rra y s .a s L is t(te o rija .s p lit(" " ) ) ;
@TestProperty
s t a t ic Ite ra to r< S trin g > reci = u l az. i t e r a t o r ( ) ;
Poglavlje 20: Anotacije 871
@TestObjectCreate s t a t i c A tU n it P rim e r4 n a p r a v i( ) (
if(re c i,h a s N e x t())
r e t u r n new A t U n i t P r i m e r 4 ( r e c i . n e x t ( ) ) ;
el se
retu rn n u l l ;
}
@Test boolean r e c i ( ) (
p r i n t ( ..... + d a jR ec() + ..... ) ;
retu rn d a jR e c ().e q u a ls ("a re ");
}
@Test boolean i s p r e t u r a j l ( ) (
/ / Prelazimo na odreeno seme (g e n e r a to r a s l u a j n i h
/ / b r o je v a ) da bismo m ogli da proveravamo r e z u l t a t e :
s lu c a ja n = new Random(47);
p r i n t ( ..... + dajR ec() + ..... ) ;
S trin g is p returano = is p r e tu r a jR e c ( ) ;
p ri n t ( i spreturano);
retu rn is p re tu ra n o .e q u a ls ("lA l" ) ;
}
@Test boolean i s p r e t u r a j 2 ( ) {
s lu c a ja n = new Random(74);
p r i n t ( ..... + dajRecO + ..... ) ;
S t r i n g is p r e t u r a n o = i s p r e t u r a j R e c ( ) ;
p r i n t ( i spreturano);
r e tu rn is p re tu ra n o .e q u a ls ("ts a e b o ro rn u s s u ");
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] arg s) throws Exceptio n {
S y s te m .o u t. p r i n t l n ( k r e e " ) ;
OSIzvrenje.komanda(
" ja v a n e t . m i n d v i e w . a t u n i t . A t U n i t A t U n i t P r i m e r 4 " ) ;
}
} / * Is p is :
kree
a n o t a c i j e . A t U n i tP rim er4
. i s p r e t u r a j 1 ' A11 '
1A1
. is p re tu ra j2 ' b r o n t o s a u ru s e s '
ts a e bororn ussu
OK (3 t e s t s )
* ///:-
p u b l i c c la s s A tU n itP rim e r5 {
p riv a te S trin g te k s t;
p u b l i c A t U n it P r im e r 5 ( S t r in g t e k s t ) { t h i s . t e k s t = t e k s t ; }
p u b lic S trin g to S trin g () { re tu rn t e k s t; }
@TestProperty s t a t i c P r i n t W r i t e r o u t p u t ;
@TestProperty s t a t i c i n t b r o j a c ;
PT estO bje ctCreate s t a t i c A t U n it P r im e r 5 n a p r a v i () {
S t r i n g id = I n t e g e r . t o S t r i n g ( b r o j a c + + ) ;
try {
i z l a z = new P r i n t W r i t e r ( " T e s t " + i d + " . t x t " ) ;
} ca tc h (IO E x c e p tio n e) {
th ro w new R u n tim e E x c e p tio n ( e ) ;
}
r e t u r n new A t U n i t P r i m e r 5 ( i d ) ;
}
PTestObjectCleanup s t a t i c v o id
c le a n u p ( A tU n itP rim e r5 t o b j ) {
S y s t e m . o u t . p r in t ln ( " P o k r e e m metodu c l e a n u p " ) ;
iz la z .c lo s e O ;
}
@Test boolean t e s t l ( ) {
iz la z .p rin t(" te s tl" );
retu rn tru e ;
}
OTest boolean t e s t 2 ( ) {
iz la z .p rin t( " te s t2 " ) ;
retu rn tru e ;
}
@Test boolean t e s t 3 ( ) {
iz la z .p rin t("te s t3 ");
retu rn tru e ;
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) throws Exce p tio n {
OSIzvrenje.komanda(
" ja v a n e t . m i n d v i e w . a t u n i t . A t U n i t A t U n i t P r i m e r 5 " ) ;
Poglavlje 20: Anotacije 873
} / * Is p is :
a n o ta c i j e . A t l l n i t P r i m e r 5
. te s tl
Pokreem cleanup
. test2
Pokreem cleanup
. te st3
Pokreem cleanup
OK (3 t e s t s )
* ///-
Iz ispisa rezultata vidite da se m etoda za ienje autom atski pokree nakon svakog te-
stiranja.
/ / : a n o t a c i j e / S t e k L . ja v a
/ / Stek n a p r a v lje n od ulanane l i s t e .
package a n o t a c i j e ;
im p o r t j a v a . u t i l . * ;
p u b l i c c la s s StekL<T> {
p r i v a t e L in k e d L is t< T > l i s t = new L i n k e d L i s t < T > ( ) ;
p u b l i c v o id push(T v) { l i s t . a d d F i r s t ( v ) ; }
p u b l i c T t o p ( ) { r e t u r n 1i s t . g g e t F i r s t ( ) ; }
p u b l i c T pop() { r e t u r n 1i s t . r e m o v e F ir s t ( ) ; }
} ///:-
PTarget(E1ementType.METHOD)
@Re tention(Re tentionPolicy.RUNT IME)
p u b l i c @ in te rfa c e T e s tO b je c tC re a te {} / / / : -
/ / : n e t / m in d v i e w / a t u n i t / T e s t O b j e c t C l e a n u p . j a v a
/ / PU n it oznaka PT estO bjectCleanup.
package n e t . m i n d v i e w . a t u n i t ;
im p o r t j a v a . l a n g . a n n o t a t i o n . * ;
O Ta rg e t(E1ementType.METHOD)
@ R e t e n tio n ( R e te n tio n P o li c y . RUNTIME)
p u b l i c (Pin te rfa ce TestO bje ctCle anup {} / / / : -
/ / : n e t/m i ndvi e w /a tu n i t / T e s t P r o p e r t y . j a v a
/ / @Unit oznaka @TestProperty.
package n e t . m i n d v i e w . a t u n i t ;
im p o r t j a v a . l a n g . a n n o t a t i o n . * ;
Svi testovi imaju RUNTIME kao vrednost m etaanotacije @ Retention, zato to sistem
@Unit testove m ora da pronalazi u prevedenom kodu.
l/.vojiemo anotacije pom ou refleksije da bism o realizovali sistem koji izvrava te-
stiranje. Na osnovu tih informacija program odluuje kako da napravi test objekte i kako da
ih testira. Zbog anotacija, to se postie iznenaujue malim i jednostavnim programom:
/ / : n e t / m i n d v i e w / a t u n i t / A t U n i t . ja v a
/ / S t r u k t u r a za j e d i n i n o t e s t i r a n j e i j u osnovu in e a n o t a c i j e .
/ / {RunByHand}
package n e t . m i n d v i e w . a t u n i t ;
im p o r t j a v a . l a n g . r e f l e c t . * ;
im p o r t j a v a . i o . * ;
im p o r t j a v a . u t i 1. * ;
im p o r t n e t . m i n d v i e w . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
87 6 Misliti na Javi
p u b l i c c la s s A t U n i t implements P r o c e s s F ile s . S t r a t e g y {
s t a t i c Class<?> t e s t C l a s s ;
s t a t i c L i s t < S t r i n g > f a i l e d T e s t s = new A r r a y L i s t < S t r i n g > ( ) ;
s t a t i c long testsRun = 0;
s t a t i c long f a i l u r e s = 0;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exce p tio n {
C la ssL o a d er.g e tSyste m C la ssL o a d e r()
. s e t D e f a u l t A s s e r t i o n S t a t u s ( t r u e ) ; / / D ozvoli naredbe a s s e r t
new P r o ce s sF ile s (n e w A t U n i t ( ) , " c l a s s " ) . s t a r t ( a r g s ) ;
i f ( f a i l u r e s == 0)
p r i n t ( " 0 K ( " + testsRun + " t e s t s ) " ) ;
e ls e {
p r i n t ( " ( " + te stsRun + " t e s t s ) " ) ;
p r i n t ( " \ n > " + f a i l u r e s + " FAILURE" +
( f a i l u r e s > 1 ? "S" : " " ) + " < " ) ;
fo r ( S t r in g f a ile d : fa ile d T e s ts )
p rin t(" " + fa ile d );
}
}
p u b l i c v o id p r o c e s s ( F i l e c F i l e ) {
try {
S t r i n g cName = C la s s N a m e F in d e r.th is C la s s (
B in a ry F ile .re a d (c F ile ));
r e t u r n ; / / Zanemari k la s e iz va n paketa
i f ( ! c N a m e . c o n t a in s ( " . " ) )
t e s t C la s s = Class.forName(cName);
} c a t c h ( E x c e p t io n e) {
th ro w new R u n t im e E x c e p t io n ( e ) ;
}
TestMethods te stM e th o d s = new T e s tM e th o d s ( ) ;
Method c r e a t o r = n u l l ;
Method cleanup = n u l l ;
fo r(M e th o d m : t e s t C la s s . g e t e c la r e d M e t h o d s O ) {
t e s t M e t h o d s . a d d lf T e s t M e t h o d ( m ) ;
i f ( c r e a t o r == n u l l )
c r e a t o r = ch e ckForCre atorM ethod(m );
i f ( c l e a n u p == n u l l )
cleanup = checkForCleanupMethod(m);
}
i f ( t e s t M e t h o d s . s i z e ( ) > 0) {
i f ( c r e a t o r == n u l 1)
try {
if( !M o d ifie r .is P u b lic ( te s tC la s s
,g e tD e c la re d C o n s tru c to r(),g e tM o d ifie rs ())) {
p r i n t ( " E r r o r : " + t e s t C la s s +
" d e f a u l t c o n s t r u c t o r must be p u b l i c " ) ;
S y s te m .e x it(l);
}
} catch(NoSuchMethodException e) {
Poglavjje 20: Anotacije 877
/ / N a p ra v lje n podrazumevani k o n s t r u k t o r ; 0K
1
p rin t(te s tC la s s .g e tN a m e ());
}
f o r( M e th o d m : te stM e th o d s) {
p rin tn b (" . " + m.getName() + " " ) ;
try {
O b je ct t e s t O b j e k a t = c r e a t e T e s t O b j e c t ( c r e a t o r ) ;
boolean success = f a l s e ;
try {
if(m .g e tR e turn T y p e ().e q u a ls (bo o le a n .c la s s ))
success = ( B o o le a n ) m . in v o k e ( t e s t O b je k a t ) ;
el se {
m .i n v o k e ( t e s t O b j e k a t ) ;
success = t r u e ; / / Ako sve naredbe a s s e r t uspeju
}
} ca tc h (In v o c a tio n T a rg e tE x c e p t" io n e) {
/ / S t v a r n i iz u z e t a k j e u n u ta r e:
p rin t(e .g e tC a u s e O );
}
p rint(success ? "" : " ( f a i l e d ) " ) ;
testsRu n++;
if(is u c c e s s ) {
fa ilu re s + + ;
f a i le d T e s t s . a d d (t e s t C l ass.getNameO +
" : " + m.getName()) ;
}
i f ( c l e a n u p != n u l l )
c l e a n up .i n v o k e ( t e s t O b je k a t , t e s t O b j e k a t ) ;
} c a t c h (E x c e p t io n e) {
th ro w new R u n tiirte E x ce ptio n (e );
}
}
}
s t a t i c c la s s TestMethods extends A rray L is t< M e th o d > {
v o id addIfTestMethod(Method m) {
i f ( m . g e t A n n o t a t i o n ( T e s t . c l ass) == n u l l )
retu rn ;
i f ( ! ( m . g e t R e t u r n T y p e ( ) .e q u a ls ( b o o le a n . c la s s ) | |
m .g e t R e t u r n T y p e ( ) . e q u a ls ( v o i d . c l a s s ) ))
th ro w new RuntimeException("@Test method" +
" must r e t u r n boolean o r v o i d " ) ;
m .s e tA c c e s s ib le (tru e ); / / lik o lik o j e p riv a tn a i t d .
add(m );
}
}
p r i v a t e s t a t i c Method checkForCreatorMethod(Method m) {
if ( m . g e t A n n o t a t i o n ( T e s t O b j e c t C r e a t e . c l a s s ) == n u l l )
retu rn n u l1 ;
i f ( !m .g e t R e t u rn T y p e ( ) . e q u a l s ( t e s t C l a s s ) )
878 Misliti na Javi
Ako ne zadate argum ent s kom andne linije, program e pretraiti stablo tekueg di-
rektorijum a. M oete zadati i vie argum enata, bilo class datoteka (s nastavkom .class ili
bez njega) bilo direktorijum a. Poto @Unit autom atski pronalazi klase i m etode koji se
m ogu testirati, nije potreban m ehanizam ,,svita.8
Jedan od problem a koje AtUnit.java m ora da rei kada pronae class datoteku jeste taj
to se p u n o im e klase (koje obuhvata i ime njenog paketa) ne m oe saznati iz im ena same
class datoteke. Zato se class datoteka m ora analizirati, to nije lako, ali ni nem ogue.9
Dalde, nakon pronalaska .class datoteke ona se prvo otvara, njen binarni sadraj uitava
i predaje m etodi ClassNam eFinder.thisClass( ). Potom prelazim o u dom en inenjerin-
ga bajtkoda, poto zapravo analiziram o sadraj class datoteke:
/ / : n e t/m i n d v i e w / a t u n i t / C l assNameFin d e r . ja v a
package n e t . m i n d v i e w . a t u n i t ;
im port j a v a . i o . * ;
im p o r t j a v a . u t i l . * ;
im p o r t n e t . m i n d v i e w . u t i l . * ;
im p o r t s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s ClassNameFinder {
p u b l i c s t a t i c S t r i n g t h i s C la s s ( byt e [ ] c la s s B y te s ) {
M ap<Integer,Integer> o ffs e tT a b le =
new H a s h M a p < I n t e g e r , I n t e g e r > ( ) ;
M a p < I n t e g e r , S t r in g > classNameTable =
new H a s h M a p < I n t e g e r , S t r in g > ( ) ;
try {
Da ta ln p utS tre a m data = new Da ta InputStream(
new B y t e A r r a y I n p u t S t r e a m ( c la s s B y t e s ) ) ;
i n t magic = d a t a . r e a d l n t ( ) ; / / Oxcafebabe
i n t m in o rV e rsio n = d a t a . r e a d S h o r t ( ) ;
i n t m a jo rV e rsio n = d a t a . re a d S h o r t ( ) ;
i n t c o n s t a n t_ p o o l_ c o u n t = d a t a . r e a d S h o r t ( ) ;
i n t [ ] c o n s tan t_ p o o l = new i n t [ c o n s t a n t _ p o o l _ c o u n t ] ;
f o r ( i n t i = 1; i < c o n s ta n t_ p o o l_ c o u n t; i+ + ) {
i n t tag = d a t a . r e a d f ) ;
in t ta b le S iz e ;
s w itc h (ta g ) {
case 1: / / UTF
i n t le n g t h = d a t a . r e a d S h o r t ( ) ;
c h a r [ ] bytes = new c h a r [ l e n g t h ] ;
f o r ( i n t k = 0; k < b y t e s . l e n g t h ; k++)
b yte s[k] = (c h a r)d a ta .re a d ();
S t r i n g imeKlase = new S t r i n g ( b y t e s ) ;
classNameTable . p u t ( i , im e K la s e );
b re ak;
case 5: / / LONG
case 6: / / DOUBLE
d a t a . r e a d L o n g O ; / / o d b a c i t i 8 b a jt o v a
i+ + ; / / Potreban j e poseban skok
b re ak;
case 7: / / CLASS
in t o ffs e t = d a ta .re a d S h o rt();
o ffs e tT a b le .p u t(i, o ffs e t) ;
break;
case 8: / / STRING
d a ta .re a d S h o rt(); / / o d b a c iti 2 b a jta
bre ak;
case 3: / / INTEGER
case 4: / / FLOAT
case 9: / / FIELD_REF
case 10: / / METHOD_REF
case 11: / / INTERFACE_METHOD_REF
case 12: / / NAME_AND_TYPE
d a ta .re a d ln t( ) ; / / o d b a c iti 4 b a jta ;
break;
d e fa u lt:
throw new R untim eE xceptio n("B ad tag " + t a g ) ;
}
i
s h o r t a c c e s s _ fl ag s = d a t a . r e a d S h o r t ( ) ;
i n t th is _ c la s s = d a ta .r e a d S h o rt( ) ;
i n t s uper_ cla ss = d a t a . r e a d S h o r t ( ) ;
r e t u r n cla ssNam eT able.get(
o f f s e t T a b l e . g e t ( t h i s _ c l a s s ) ) . r e p l a c e ( 1/ 1, 1. 1) ;
} c a t c h (E x c e p t io n e) {
th ro w new R u n t im e E x c e p t io n ( e ) ;
}
}
/ / P r ik a z :
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) throws Exceptio n {
i f ( a r g s . l e n g t h > 0) {
f o r ( S t r i n g arg : args)
p r i n t ( t h i s C l a s s ( B i n a r y F i 1e .re ad(new Fi 1e ( a r g ) ) ) ) ;
} el se
/ / Prola zak kroz c e lo s t a b l o :
f o r ( F i l e kla ss : D i r e c t o r y . w a l k ( " . " , " . * \ \ . c l a s s " ) )
p rin t(th is C la s s (B in a ry F ile .re a d (k la s s )));
}
} lll--~
lako ovde ne m oem o ulaziti u sve pojedinosti, svaka class datoteka im a odredeni for-
m at, a ja sam pariim a podataka izvadenih iz toka B yteA rray In p u tS tream pokuao da
dam smislena imena. Veliinu svakog pareta moete saznati na osnovu duine uitanog
ulaznog toka. Prim era radi, prva 32 bita svake class datoteke uvek zauzim a magini broj
Poglavlje 20: Anotacije 881
Oxcafebabe,10 a sledea dva shorta su inform acija o verziji. Skladite (engl. pool)
konstanti sadri konstante za program i zato je prom enljive veliine; sledei short kazuje
koliki je, da bi m u mogao biti dodeljen niz odgovarajue veliine. Svaka stavka skladita
konstanti moe biti vrednost fiksne ili prom enljive veliine, pa m oram o da ispitam o
oznaku kojom stavka poinje da bism o shvatili ta s njom da radim o - to je naredba
switch. Ovde nism o pokuavaii da tano analiziram o sve podatke u class datoteci, nego
sam o da proem o kroz sve vane parie i da ih uskladitim o, pa se nem ojte uditi to se
dobar deo podataka odbacuje. Inform acije o klasam a skladite se u tabeli className-
Table i tabeli offsetTable. Nakon uitavanja skladita konstanti m oe se pronai inform a-
cija this_dass, to je indeks tabele offsetTable koja proizvodi indeks za classNameTable
koja proizvodi ime klase.
V ratim o se program u AtUnit.java. M etoda pro cess( ) sada im a ime klase i m oe u njoj
p o tra iti., to znai da je deo nekog paketa. Klase izvan paketa se zanem aruju. Ukoliko je
klasa u paketu, standardni uitava klasa uitava klasu m etodom Class.forN am e( ). Sada
se u klasi m ogu potraiti @Unit anotacije.
Traim o samo tri stvari: @Test m etode koje su uskladitene u listi TestMethods i me-
tode oznaene sa @TestObjectCreate ili @TestObjectCIeanup. Njih pronalazim o tako
to pozivam o pridruene m etode koje trae anotacije.
Ako se pronae neka @Test m etoda, ime odgovarajue klase se tam pa da bi posm a-
tra znao ta se dogaa i zatim se izvrava svaki test. To znai da se tam pa ime metode,
zatim poziva createTestO bject( ) koja e pozvati m etodu @TestObjectCreate ako takva
postoji ili e u protivnom pozvati podrazum evani konstruktor. Nakon pravljcnja test
objekta poziva se m etoda koja ga testira. Ako test vrati vrednost tipa boolean, taj rezultat
se pam ti. U suprotnom , pretpostavljam o da je test uspean ukoliko se nije pojavio
izuzetak (to bi se desilo u sluaju neuspene naredbe assert ili bilo koje druge vrste izu-
zetka). Ukoliko izuzetak bude generisan, tam paju se pripadajue inform acije da bi
korisnik video uzrok. U svim sluajevima neuspeha (engl. failure) poveava se sadraj
brojaa neuspeha, a ime neuspene klase i m etode dodaju se listi failedTests da bi bile pri-
javljene na kraju testiranja.
Veba 11: (5) Alatki @Unit dodajte anotaciju @TestNote; ona oznaava pratee napom e-
ne (engl. notes) koje se ispisuju tokom testiranja.
/ / : n e t / m in d v ie w / a t u n i t / A t U n it R e n io v e r . ja v a
/ / P r ik a z u je @Unit a n o t a c i j e u prevednim datotekama k la s a . Ako j e
/ / p r v i argument " - r " , @Unit a n o t a c i j e e b i t i u k lo n je n e .
/ / { A rg s: . . }
/ / {Neophodno za r a d : j a v a s s i s t . b y t e c o d e . C l a s s F i l e ;
/ / Morate i n s t a l i r a t i b i b l i o t e k u J a v a s s i s t sa
/ / h ttp ://s o u rc e fo rg e .n e t/p ro je c ts /jb o s s / }
package n e t . m i n d v i e w . a t u n i t ;
im p o r t j a v a s s i s t . * ;
im p o rt j a v a s s i s t . e x p r . * ;
im p o r t j a v a s s i s t . b y t e c o d e . * ;
im p o r t j a v a s s i s t . b y t e c o d e . a n n o t a t i o n . * ;
im p o r t j a v a . i o . * ;
im p o rt j a v a . u t i l . * ;
im p o r t n e t . m i n d v i e w . u t i l . * ;
im p o rt s t a t i c n e t . m i n d v i e w . u t i l . P r i n t . * ;
p u b l i c c la s s AtUnitRemover
implements P r o c e s s F ile s . S t r a t e g y {
p r i v a t e s t a t i c boolean u k lo n i = f a l s e ;
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) throws Exce p tio n {
i f ( a r g s . l e n g t h > 0 && a r g s , e q u a l s ( - r " ) ) {
u k lo n i = t r u e ;
S t r i n g [ ] b r o j a r g = new S t r i n g [ a r g s . l e n g t h - 1 ] ;
S y s te m .a rr a y c o p y ( a rg s , 1, b r o j a r g , 0, b r o j a r g . 1e n g t h ) ;
args = b r o j a r g ;
}
new P ro c e s s F i1e s (
new A tU n itR e m o v e r( ) , " c l a s s " ) . s t a r t ( a r g s ) ;
}
p u b l i c v o id p r o c e s s ( F i l e cDatka) {
boolean m o d if ik o v a n a = f a l s e ;
try {
S t r i n g clme = C la s sN a m e F in d e r.th is C la s s(
B i n a r y F i 1e . r e a d ( c D a t k a ) ) ;
if(!c Im e .c o n ta in s ("."))
r e t u r n ; / / Klase iz v a n paketa se zanemaruju
ClassPool cPool = C l a s s P o o l . g e t D e f a u l t ( ) ;
CtClass c t C la s s = c P o o l . g e t ( c l m e ) ;
fo r(C tM e th o d metoda : c t C l a s s . g e tD e c l a r e d M e t h o d s f ) ) {
M eth o d ln fo mi = m e to d a .g e tM e th o d ln fo O ;
A n n o ta tio n s A ttrib u te a t t r = (A n n o ta tio n s A ttrib u te )
m i.g e tA ttrib u te (A n n o ta tio n s A ttrib u te . vi s ib le T a g );
i f ( a t t r == n u l l ) c o n t in u e ;
f o r ( A n n o t a t i o n ann : a t t r . g e t A n n o t a t i o n s O ) {
if (ann.getTypeNam e()
Poglavjje 20: Anotacije 883
Saetak
Anotacije su dobrodoao dodatak Javi. O ne su stru k tu riran nain dodavanja m etapoda-
taka kodu, zajemeno bezbedan u pogledu tipova, a pri tom kod ne ini neitljivim i za-
petljanim . O ne mogu pom oi da se smanji dosadno pisanje deskriptora prim ene i drugih
Isto vai i za program iranje grafikih korisnikih okruenja, kao to ete videti u sledeem
poglavlju. Iako biblioteke Swing i SWT im aju m ehanizm e za bezbednost niti, teko je shva-
titi kako da ih ispravno upotrebljavate ako ne razum ete paralelno izvravanje.
Java je vienitni jezik i problem i s paralelnim izvravanjem postoje, znali vi to ili ne.
Zato postoji m nogo Java program a koji rade ili sluajnim sticajem okolnosti ili tek vei
deo vrem ena, i povrem eno m isteriozno zakazuju zbog neotkrivenih greaka u para-
lelnom izvravanju. Katkada su ta zakazivanja dobroudna, ali um eju da prouzrokuju
gubljenje vrednih podataka, i ako barem niste uli za problem e s paralelnim izvrava-
njem, misliete da je problem u svemu pre nego u vaem softveru. Ta vrsta problem a
m oe izroniti ili se pojaati kada se program prem esti na vieprocesorski raunar. Nakon
to prouite ovo poglavlje, trebalo bi da znate kako prividno ispravni program i mogu
zbog paralelnog izvravanja da ispolje neispravno ponaanje.
Kada ponete da se bavite paralelnim program iranjem , kao da ste otili u stranu zemlju
da uite njen jezik ili barem p o tp u n o nov skup jezikih pojm ova. Nauiti paralelno pro-
gram iranje jednako je zahtevno kao nauiti objektno orijentisano program iranje. Ako se
potrudite, shvatiete osnovni m ehanizam , ali za pravo ovladavanje tim predm etom po
pravilu je potrebno dobro zagrejati stolicu. Iz ovog poglavlja stei ete osnovno znanje o
paralelnom izvravanju, pa ete razum eti pojmove i moi ete da piete um ereno sloene
vienitne program e. Budite svesni da je veoma lako stei neosnovano veliko poverenje u
svoje sposobnosti za paralelno program iranje. Moraete da proitate knjige posveene
iskljuivo toj temi ukoliko se odluite za pisanje iole sloenijih vienitnih programa.
Bre izvravanje
Spoetka problem zvui jednostavno: ako elite da se program izvrava bre, podelite ga na
niti koje izvravaju zasebni procesori. Paralelno izvravanje je osnovna alatka vieproce-
sorskog program iranja. Poto M urov zakon sve ree deluje (barem za obina integrisana
kola), sredstvo za poveanje brzine postaju procesori s vie jezgara, a ne bra integrisana
kola. Da biste naterali program e da rade bre, m oraete nauiti da iskoristite te dodatne
procesore, i to je jedna od stvari koje e vam paralelno izvravanje omoguiti.
Ako imate raunar s vie procesora, njim a se moe dodeliti vie zadataka (na isto-
vrem eno izvravanje), to um e znatno da pobolja protok. Tako esto rade snani vie-
procesorski Web serveri; oni procesorim a rasporeuju veliki broj korisnikih zahteva u
program u koji dodeljuje jednu nit po zahtevu.
Poglavlje 21: Paraielno izvravanje 887
Evo jednostavnog prim era procesa u operativnom sistemu. D ok piem knjigu, redov-
no pravim vie redundantnih rezervnih kopija tekueg stanja knjige. Jednu kopiju napra-
vim u lokalnom direktorijum u, dru gu na fle ureaju, treu na Zip disku i etvrtu na
udaljenoj FTP lokaciji. Za autom atizaciju tog po stu p k a napisao sam m ali program (na
Pythonu, ali koncepti su isti) koji kom prim uje knjigu u datoteku ije im e sadri broj ver-
zije i zatim kopira. Spoetka sam sve kopije pravio sekvencijalno (ekao da se prethodno
kopiranje zavri pa da otponem sledee). Potom sam shvatio da operacije kopiranja ne
traju jednako, jer se U/I brzine m edijum a razlikuju. Poto sam im ao vieprogram ski
operativni sistem, svaku operaciju kopiranja m ogao sam da zaponem kao zaseban pro-
ces i pustim ih da se izvravaju paralelno - tako se ubrzavalo izvravanje celog program a.
D ok je jedan proces blokiran, drugi m ogu da rade.
To je idealan prim er paralelnog izvravanja. Svaki zadatak se izvrava kao proces u
sopstvenom adresnom prostoru, p a zadaci ne m ogu da utiu jedni na druge. Jo je vanije
to to zadaci nem aju potrebe da kom uniciraju, poto su p o tp u n o nezavisni. O perativni
sistem se stara o svim pojedinostim a koje obezbeuju ispravno kopiranje datoteka. Stoga
nem a rizika i dobijam o bri program , zapravo besplatno.
Neki zagovaraju procese kao jedini razum an p ristu p paralelnom izvravanju,1 ali je
naalost broj procesa po pravilu ogranien, a njihovi reijski trokovi veliki. Zato se pri-
m enom procesa ne mogu reiti svi zadaci iz spektra paralelnog izvravanja.
Neki program ski jezici m eusobno izoluju zadatke koji se izvravaju paralelno.
O bino ih nazivamo fu n kcijski jezici, jer u njim a poziv funkcije ne prouzrokuje sporedne
uticaje (te ne moe ni da utie na druge funkcije) i stoga se m oe izvravati kao zaseban
zadatak. Jedan od takvih jezika je Erlang, a on obuhvata m ehanizam sefa za kom unikaciju
jednog zadatka s drugim. Ukoliko shvatite da u delu vaeg program a m ora intenzivno da
se koristi paralelno izvravanje, a pri pisanju tog dela nailazite na velike problem e, raz-
mislite o ideji da taj deo program a napiete na nam enskom jeziku za paralelno izvra-
vanje kao to je Erlang.
U Javi je pristup tradicionalniji - podrka za vienitni rad dodata je na gotov
sekvencijalni jezik.2 Umesto da se ,,love spoljni procesi u vieprogram skom operativnom
sistemu, niti prave zadatke u n u ta r istog procesa koji predstavlja program koji se izvrava.
Jedna od prednosti koje se pri tom e postiu jeste nezavisnost od operativnog sistema, to
je bio vaan cilj prilikom projektovanja Jave. Na prim er, pre verzije OS X operativnog
sistema M acintosh (prilino vana publika za prve verzije Jave) nisu podravale viepro-
gramski rad. Da vienitni rad nije dodat u Javu, Java program i za paralelno izvravanje ne
bi mogli da se izvravaju na M acintoshu i njem u slinim platform am a, im e bi se naruio
zahtev napii jednom/izvravaj svuda.3
Definisanje zadataka
Nit izvrava jedan zadatak, pa m oram o imati naina da taj zadatak opiemo. Tome slui
interfejs R unnable. Zadatak ete efinisati kada realizujete R unnable i napiete rnetodu
r u n ( ) koja obavlja ono to zadatak treba da uradi.
Prim era radi, naredni zadatak L ansiranje prikazuje odbrojavanje pre lansiranja:
/ / : p a ra le ln o /L a n s ira n je .ja v a
/ / Prim er i n t e r f e j s a Runnable.
p u b l i c c la s s L a n s ir a n je implements Runnable {
p ro t e c t e d i n t o d b ro ja v a n je = 10; / / Podrazumevana
p r i v a t e s t a t i c i n t b ro jZ a d a tk a = 0;
p r i v a t e f i n a l i n t id = bro jZ a d a tk a + + ;
p u b l i c L a n s i r a n j e ( ) {)
p u b l i c L a n s i r a n j e ( i n t o d b ro ja v a n je ) {
t h i s . o d b ro ja v a n je = o d b r o ja v a n je ;
}
p u b lic S trin g s ta tu s () {
r e t u r n "#" + i d + " ( " +
( o d b r o ja v a n je > 0 ? o d b ro ja v a n je : " L a n s i r a n j e ! ") + " ) , ";
}
p u b l i c v o i r u n ( ) {
w h i l e ( o d b r o j a v a n j e - - > 0) {
S y s te m .o u t.p rin t(s ta tu s ());
T h re a d .y ie ld ();
}
}
} ///:-
Instance zadatka se ra/.likuju po pripadajuem identifikatoru id. Uz njega je rezervisa-
na re final zato to ne oekujem o da e se p rom eniti nakon to bude inicijalizovan.
M etoda r u n ( ) obino im a neku vrstu petlje koja se izvrava sve dok zadatak ne posta-
ne nepotreban, pa m orate da utvrdite uslov za izlazak iz nje. Jedna m ogunost bi bila da
jednostavno izaete (vratite se) iz m etode r u n ( ). M etodu r u n ( ) esto piu u obliku bes-
konane petlje, to znai da e se ona izvravati u nedogled ako je neto ne prekine. (U na-
stavku poglavlja saznaete kako da bezbedno okonate zadatak.)
Poziv statike m etode T hread.yield( ) u n u tar m etode r u n ( ) predstavlja sugestiju
m eh a n izm u za raspodelu procesorskog vrem ena nitim a , engl. thread schedular (koji preba-
cuje procesor s jedne niti na drugu) koja kazuje: Obavio sam vane delove svog ciklusa i
sada je vrem e za prebacivanje na drugi zadatak. M etoda je neobavezna (opciona), a ovde
sam je upotrebio zato to u navedenim prim erim a daje zanimljivije rezultate: ona povea-
va verovatnou da e doi do prebacivanja s jednog zadatka na drugi.
U narednom prim eru, zadatkovu m etodu r u n ( ) ne izvrava zasebna nit; nju jedno-
stavno poziva m etoda m a in ( ). Zapravo, to jeste zasebna nit: ona koja se uvek dodeljuje
metodi m a in ( ):
//: p a ra le ln o /G la v n a N it.ja v a
p u b l i c c la s s G la vn a N it {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
L a n s ir a n je l a n s i r a j = new L a n s ir a n j e ( ) ;
1ansi r a j . r u n ( ) ;
}
} / * Is p is :
# 0 (9 ), # 0 (8 ), # 0(7), # 0(6), #0(5), # 0 (4 ), # 0 (3 ), # 0 (2 ), # 0 ( 0 ,
#0(Lansi r a n j e ! ) ,
* ///:-
Klasa Thread
Runnable objekat se pretvara u zadatak koji se izvrava najee tako to objekat
prosledite konstruktoru klase Thread. U sledeem prim eru em o pom ou klase Thread
pokrenuti izvravanje objekta tipa Lansiranje:
892 Misliti na Javi
//: p a ra le ln o /O s n o v e N iti.ja v a
/ / N a j j e d n o s t a v n i j a u p o tr e b a k la s e Thread.
p u b l i c c la s s O snoveN iti {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s ) {
Thread t = new Thread(new L a n s i r a n j e O ) ;
t.s ta rtO ;
S y s te m . o u t . p r in t ln ( " e k a m o na L a n s i r a n j e " ) ;
}
} / * I s p i s : (90% podudaranja)
ekamo na L a n s ir a n je
# 0 (9 ), # 0 (8 ), # 0 (7 ), # 0 (6 ), # 0 (5 ), # 0 (4 ), # 0 (3 ), # 0 (2 ), # 0(1),
# 0 (L a n s ira n je !),
* ///:-
K onstruktoru klase Thread treba sam o objekat tipa Runnable. N it se inicijali/.uje po-
zivom m etode s ta rt( ) objekta tipa Thread, a zatim se pozivom m etode r u n ( ) objekta tipa
Runnable pokree zadatak u novoj niti. Mada izgleda kao da s ta r t( ) poziva neku m etodu
koja se izvrava dugo, iz ispisa rezultata moete videti - poruka ekamo na Lansiranje
ispisuje se pre dovrenja odbrojavanja - da se m etoda s ta r t( ) vraa brzo. U stvari, pozvana
je m etoda L ansiranje.run( ) koja se jo nije zavrila, ali poto se Lansiranje.run( ) izvrava
u drugoj niti, u metodi m a in ( ) i dalje m oem o da izvravamo ostale operacije. (Ta spo-
sobnost nije ograniena na nit m etode m a in ( ) - svaka nit m oe da pokrene druge niti.)
DakJe, program izvrava dve m etode istovrem eno - m a in ( ) i Lansiranje.run( ). Kod m e -
tode r u n ( ) izvrava se istovrem eno sa ostalim nitim a program a.
Lako je dodati jo niti za izvravanje drugih zadataka. U narednom prim eru vidite sve
zadatke u uzajam no usklaenom izvravanju:5
/ / : p a r a l e l n o / J o s O s n o v a N i t i . ja v a
/ / Dodavanje n i t i .
p u b l i c c la s s JosO sn ovaNiti {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
f o r ( i n t i = 0 ; i < 5; i+ + )
new Thread(new L a n s i r a n j e ( ) ) . s t a r t ( ) ;
S y s t e m . o u t . p r ir t ln ( " e k a m o na L a n s i r a n j e " ) ;
}
} / * I s p i s : ( p r im e r)
ekamo na L a n s ir a n je
# 0 (9 ), # 1 (9 ), # 2 (9 ), # 3 (9 ), # 4 (9 ), # 0 (8 ), # 1 (8 ), # 2(8), # 3 (8 ), #4(8), #0(7),
# 1 ( 7 ) , # 2 ( 7 ) , # 3 ( 7 ) , # 4 ( 7 ) , # 0 ( 6 ) , # 1 ( 6 ) , # 2 ( 6 ) , # 3 ( 6 ) , # 4 ( 6 ) , # 0 ( 5 ) , # 1 (5 ) ,
# 2 (5 ), # 3 (5 ), # 4(5), # 0 (4 ), # 1 (4 ), # 2 (4 ), # 3 (4 ), # 4 (4 ), # 0 (3 ), # 1 (3 ), #2(3),
# 3 (3 ), # 4 (3 ), # 0(2), # 1 (2 ), # 2 (2 ), # 3 (2 ), # 4 (2 ), # 0(1), # 1 (1 ), #2(1), # 3 (1 ),
# 4 ( 1 ) , # 0 ( L a n s ir a n j e ! ) , # 1 ( L a n s i r a n j e ! ) , # 2 ( L a n s i r a n j e ! ) , # 3 ( L a n s i r a n j e ! ) ,
# 4(L ansi r a n j e ! ) ,
* ///:-
prim cru, klasa C achedT hreadP ool pravi po jed n u nit za svaki zadatak. O bratite panju
na to da se objekat tipa ExecutorService pravi statikom m etodom klase Executors; ona
odreuje koja e vrsta izvrioca biti napravljena:
/ / : p a ra le ln o /C a c h e d T h re a d P o o l. ja v a
im p o r t j a v a . u t i l . c o n c u r r e n t . * ;
p u b l i c c la s s CachedThreadPool {
p u b l i c s t a t l c vo id m a i n ( S t r i n g [ ] a rg s ) {
E x e cu to rS e rv ic e exec = Executors.newCach edThreadPool( ) ;
f o r ( i n t i = 0 ; i < 5 ; i+ +)
exe c.execute(new L a n s i r a n j e ( ) ) ;
exec.shutdown();
}
} / * I s p i s : ( p r im e r)
# 0 (9 ), # 0 (8 ), # 1 (9 ), # 2 (9 ), # 3 (9 ), # 4 (9 ), # 0 (7 ), # 1 (8 ), # 2 (8 ), # 3 (8 ), # 4(8),
# 0 (6 ), # 1 (7 ), # 2 (7 ), # 3 (7 ), # 4 (7 ), # 0 (5 ), # 1 (6 ), # 2 (6 ), # 3 (6 ), # 4 (6 ), # 0(4),
# 1 (5 ), # 2 (5 ), # 3 (5 ), # 4 (5 ), # 0 (3 ), # 1 (4 ), # 2 (4 ), # 3 (4 ), # 4(4), # 0 (2 ), # 1 (3 ),
# 2(3), # 3 (3 ), # 4 (3 ), # 0 (1 ), # 1 (2 ), # 2 (2 ), # 3 (2 ), # 4 (2 ), # 0 (L a n s ir a n je !) ,
# 1(1), #2(1), # 3 (1 ), # 4 (1 ), # l ( L a n s i r a n j e ! ) , # 2 (L a n s ira n je !) ,
# 3 (L a n s ira n je !), # 4 (L a n s ira n je !) ,
* ///:-
Veoma esto, sam o jednim izvriocem m oete da napravite sve zadatke u sistemu i da
svima njim a upravljate.
Poziv m etode s h u td o w n () spreava dodeljivanje novih zadataka tom izvriocu. Te-
kua nit - u ovom sluaju, ona koja izvrava m a in ( ) - nastavie da izvrava sve zadatke
prijavljene pre poziva m etode s h u td o w n ( ). Program e prekinuti izvravanje im se
zavre svi zadaci u tom izvriocu.
C achedT hreadP ool iz prethodnog prim era lako m oete zam eniti nekom drugom vr-
stom izvrioca. Za izvravanje prijavljenih zadataka, F ixedT hreadPool koristi ogranien
skup niti:
/ / : p a r a le ln o / F i x e d T h r e a d P o o l. j a v a
im p o rt j a v a . u t i l . c o n c u r r e n t . * ;
p u b l i c c la s s FixedThreadPool {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] a rg s) {
/ / Argument k o n s t r u k t o r a j e b r o j n i t i :
E x e c u to rS e rv ic e exec = E x e c u to rs.n e w F ix e d T h rea d P oo l( 5 ) ;
f o r ( i n t i = 0; i < 5; i++)
e xec.execute(new L a n s i r a n j e O ) ;
exec.shutdow n();
}
} / * Is p is : ( p r im e r)
Poglavlje 21: Paralelno izvravanje 895
}
} / * Is p is :
# 0 (9 ), # 0(8), #0(7), # 0 (6 ), # 0 (5 ), # 0 (4 ), # 0 (3 ), # 0 (2 ), # 0 (1 ),
# 0 (L a n s ir a n je !) , # 1(9), # 1 (8 ), # 1 (7 ), # 1 (6 ), # 1 (5 ), # 1 (4 ), # 1 (3 ), # 1(2),
#1(1), # l( L a n s ir a n je !) , # 2 (9 ), # 2 (8 ), # 2 (7 ), # 2 (6 ), # 2 (5 ), # 2 (4 ), # 2(3),
# 2 (2 ), # 2(1), # 2 ( L a n s ir a n je !) , # 3 (9 ), # 3 (8 ), # 3 (7 ), # 3 (6 ), # 3 (5 ), # 3(4),
# 3 (3 ), # 3(2), #3(1), # 3 ( L a n s ir a n je ! ) , # 4 (9 ), # 4 (8 ), # 4 (7 ), # 4 (6 ), #4(5),
# 4(4), # 4(3), # 4(2), # 4 (1 ), # 4 (L a n s ir a n je !) ,
* ///:-
Kao drugi primer, pretpostavim o da vie niti izvrava zadatke koji koriste sistem
datoteka. Za te zadatke m oete u potrebiti izvrilac tipa SingleThreadExecutor koji jem i
da se u svakom trenutku u svakoj niti izvrava sam o po jedan zadatak. U tom sluaju ne
m orate da se bavite sinhronizovanjem deljenog resursa (a ni sistem datoteka neete
zabrljati u m eduvrem enu). Ponekad je bolje reenje sinhronizovanje resursa (o em u ete
vie saznati u nastavku poglavlja), ali SingleThreadExecutor om oguuje da preskoite
pravilnu koordinaciju kada elite sam o da napravite neki prototip. Serijalizacijom
zadataka moete da uklonite potrebu za serijalizacijom objekata.
Veba3: (1) Ponovite vebu 1 s raznim vrstam a izvrilaca predstavljenim u ovom odeljku.
Veba 4: ( 1) Ponovite vebu 2 s raznim vrstam a izvrilaca predstavljenim u ovom odeljku.
/ / : p a r a l e l no/Prim erZaCal1a b l e . j a v a
im p o rt j a v a . u t i l . c o n c u r r e n t . * ;
im p o rt j a v a . u t i l . * ;
p u b l i c c la s s PrimerZaCal1a b le {
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) {
E x e cu to rS e rv ic e exec = Executors.newCachedThreadPool( ) ;
A rra y L is t< F u tu re < S trin g r e z u lt a t i =
Poglavlje 2 1: Paralelno izvravanje 897
M etoda s u b m it( ) proizvodi objekat tipa Future, param etrizovan za odreeni tip re-
zultata koji vraa taj objekat tipa Callable. O bjekat tipa Future moete ispitivati meto-
dom isD o n e( ) kako biste videli da li je zavrio rad. Kada zadatak zavri s radom i ima
rezultat, pozovite m etodu g e t( ) da biste ga saznali. Ukoliko g e t( ) pozovete bez prethod-
ne provere zavrenosti m etodom isD o ne( ), g e t( ) e se blokirati sve dok rezultat ne bude
sprem an. g e t( ) m oete pozvati i uz vrem ensko odlaganje (engl. tim eout), ili pozovite
isD o n e( ) kako biste videli da li je zadatak zavrio s radom pre nego to pozovete g e t( ) da
pribavi njegov rezultat.
Preklopljena m etoda Executors.caIlable( ) prim a objekat koji realizuje interfejs
Runnable i proizvodi objekat tipa Callable. ExecutorService ima ,,pozivajue m etode
koje izvravaju kolekcije Callable objekata.
Veba 5: (2) Izmenite vebu 2 tako da zadatak realizuje interfejs Callable i sabira sve Fi-
bonaccijeve brojeve. Napravite nekoliko zadataka i prikaite rezultate.
Spavanje
M etodom sleep ( ) prekidate (blokirate) izvravanje zadatka na odredeno vreme. Ako u
klasi Lansiranje zam enite poziv m etode y ie ld ( ) pozivom m etode sleep( ), dobiete ovo:
898 Misliti na Javi
/ / : p a r a le ln o / Z a d a t a k K o jiS p a v a . ja v a
/ / Prekidam iz v r a v a n je zadatka
/ / na odreeno vreme metodom s l e e p ( ) .
im p o rt j a v a . u t i l . c o n c u r r e n t . * ;
Prioritet
P rioritet niti pokazuje koliko je ona vana m ehanizm u za raspodelu procesorskog vrem e-
na. Iako je redosled kojim CPU izvrava skup niti neodreen, m ehanizam za raspodelu
procesorskog vrem ena daje prednost niti najvieg p rioriteta koja eka na izvravanje. To
ne znai da se niti nieg prioriteta uopte ne izvravaju. (Dakle, prioriteti ne m ogu da
prouzrokuju zastoj u izvravanju). M ehanizam za raspodelu procesorskog vrem ena ree
pokree niti nieg prioriteta i to je sva razlika.
Gotovo uvek bi sve niti trebalo da se izvravaju s podrazum evanim prioritetom . Runo
m enjanje prioriteta najee nije opravdano.
Sledi prim er s razliitim nivoim a prioriteta. Prioritet postojee niti itam o m etodom
g e tP rio rity ( ), a zadajemo (kad god poelim o) m etodom setP rio rity ( ).
/ / : p a r a l e l n o / P r o s t i P r i o r i t e t i . ja v a
/ / Prim e r k o r i e n ja p r i o r i t e t a n i t i .
im p o r t j a v a . u t i l . c o n c u r r e n t . * ;
p u b l i c c la s s P r o s t i P r i o r i t e t i implements Runnable {
p r i v a t e i n t o d b ro ja v a n je = 5;
p r i v a t e v o l a t i l e double d; / / Bez o p t i m i z a c i j e
p riv a te in t p r i o r it e t ;
p u b lic P r o s t i P r i o r i t e t i ( i nt p r i o r i t e t ) {
th is .p rio rite t = p rio rite t;
}
p u b lic S trin g to S tr in g ( ) {
r e t u r n T h r e a d .c u r r e n t T h re a d () + " : " + o d b r o ja v a n je ;
}
p u b l i c v o id r u n ( ) {
T h re a d .c u rre n tT h re a d ().s e tP rio rity (p rio rite t);
w h ile (tru e ) {
/ / Skupa o p e r a c ija koja se moe p r e k i n u t i :
f o r ( i n t i = 1; i < 100000; i+ + ) {
d += (Math.PI + Math.E) / ( d o u b l e ) i ;
i f ( i % 1000 == 0)
Thread, y i e l d ( ) ;
}
S y s te m .o u t.p rin tln (th i s ) ;
i f ( - - o d b r o j a v a n j e == 0) r e t u r n ;
}
}
p u b l i c s t a t i c v o id m a i n ( S t r i n g [ ] args) {
900 Misliti na Javi
* ///:-
(onih 10 na ovih 7) neodreeno. Sunov Solaris im a 231nivoa. Jedini pristup koji je prenosiv
na sve platform e jeste drati se MAX_PRIORITY, NORM_PRIORITY i MIN_PRIORITY
prilikom podeavanja nivoa prioriteta.
Preputanje
Ukoliko znate da ste uradili ono to je trebalo tokom jednog prolaska kroz petlju u m etodi
r u n ( ), m ehanizm u za raspoelu procesorskog vrem ena nitim a m oete saoptiti da je te-
kua n it uradila dovoljno i predloiti m u da procesor dodeli nekom drugom zadatku. Taj
predlog (to i jeste sam o predlog, poto nem a jem stva da e ga realizacija posluati) im a
oblik m etode y ie ld ( ). Kada pozovete y ie ld ( ), predlaete prelazak na izvravanje drugih
niti istog prioriteta.
Lansiranje.java m etodom y ield ( ) dobro raspodeljuje obradu na razne zadatke progra-
m a Lansiranje. U m etodi Lansiranje. r u n ( ) pozive Thread.yield( ) pretvorite u kom en-
tare, pa ete videti razliku. M eutim , za ozbiljnu kontrolu ili podeavanje aplikacije po
pravilu se ne moete osloniti na y ield ( ). ta vie, esto se y ield( ) pogreno upotrebljava.
Servisne niti
Servisne niti (engl. daem on threads) obezbeuju neke usluge nam enjene program u u ce-
lini i izvravaju se u pozadini tokom rada program a, ali ne spadaju u njegove sutinske
delove. Zato se program zavrava im zavre s radom sve obine niti. Vai i obratno: ako
jo ima obinih niti koje se izvravaju, program nastavlja rad - na prim er, ako postoji nit
koja izvrava m a in ( ).
//: paralelno/JednostavneServisneNiti.java
// Serv is ne niti ne spreavaju da se program okona.
import ja v a . u t i 1 .concurrent
import static n e t .mindview.uti1 .P r i n t .*;
*///:-
Pre pokretanja m etodom s ta r t( ), nit m orate m etodom setD aem on( ) najpre pretvo-
riti u servisnu (naterati je da se izvrava u pozadini).
Program nem a ta da radi kada m a in ( ) zavri svoj posao, jer se tada ne izvrava nita
drugo sem servisnih niti. Stavio sam m a in ( ) nakratko na spavanje da biste videli posle-
dice pokretanja svih servisnih niti. Bez toga biste videli samo neke rezultate pravljenja niti
koje se izvravaju u pozadini. (Isprobajte pozive m etode sleep ( ) raznih duina da biste vi-
deli to ponaanje.)
Program JednostavneServisneNiti.java pravi eksplicitne Thread olijekte kako bi
mogao da ih pretvori u servisne postavljanjem odgovarajueg indikatora. A tribute niti
(da li je servisna, njen prioritet, ime) napravljenih pom ou izvrioca moete prilagoditi
pisanjem nam enske klase ThreadFactory:
//: paralelno/DaemonThreadFactory.java
// Pravljenje servisnih niti pomou ThreadFactory.
import java.uti1 .concurrent.*;
import net.mindview.util.*;
Poglavlj'e 2 1: Paralelno izvravanje 903
A rgum ente za poziv konstruktora osnovne klase pronaao sam u izvornom kodu klase
Executors.java.
Pozivanjem m etode isD aem on( ) saznaete da li je data nit servisna (da li se izvrava u
pozadini). Ako se neka nit izvrava u pozadini, to autom atski vai i za sve niti koje ona na-
pravi, kao to se vidi iz sledeeg prim era:
//: paralelno/ServisneNiti.java
// Servisna nit raa druge servisne niti.
904 Misliti na Javi
import java.util.concurrent.*;
import static net.mindview.util.Print.*;
ServisnaNit ukljuuje svoj indikator servisne niti i zatim pravi gom ilu drugih niti
kako bi pokazala da su i one servisne, iako nisn eksplicitno pretvorene u servisne. Zatim
ServisnaNit ide u beskonanu petlju koja poziva m etodu y ield ( ) da bi predala kontrolu
drugim procesima.
Im ajte u vidu injenicu da servisne niti ne izvravaju odredbe finally prilikom
okonanja svojih m etoda r u n ( ):
//: pa ra le lno/ServisneNitiNeIzvrsavajuOdrebeFinally.java
// Servisne niti ne izvravaju odredbe finally
import java.util.concurrent.*;
import static ne t. mi nd vi ew .u ti1 . P r i n t .*;
Kada pokrenete ovaj program , videete da se odredba finally ne izvrava, ali ako poziv
m etode s e tD a e m o n () pretvorite u kom entar, videete da se odredba finally izvrava.
Takvo ponaanje je ispravno, iako ga m oda ne oekujete na osnovu prethodnih
obeanja u vezi sa odredbom finally. Servisne niti bivaju naglo prekinute kada prestane
izvravanje poslednje neservisne niti. Dakle, im m a in ( ) izade, JVM odm ah prekida rad
svih servisnih niti, bez ikakvih form alnosti koje ste m oda oekivali. Poto se servisne niti
ne m ogu lepo prekinuti, one su retko kada podesne. Po pravilu su neservisni izvrioci
bolji, poto se svi zadaci koje izvrilac kontrolie m ogu prekinuti odjednom . Kao to ete
videti u nastavku poglavlja, u tom sluaju se gaenje odvija pravilno.
Veba 7: (2) Eksperim entiite s razliitim vrem enim a spavanja u program u Servisne-
N iti.java da biste videli ta se deava.
906 Misliti na Javi
Varijante programiranja
U dosadanjim prim erim a su sve klase zadataka realizovale interfejs Runnable. U veoma
jednostavnim sluajevima m ogu je i drugaiji pristup, nasleivanje neposredno od klase
Thread, to se radi ovako:
//: paralelno/JednostavnaNit.java
// Neposredno nasleivanje od klase Thread.
Nitima (objektima klase T h read ) dajemo imena tako to pozivamo odgovarajue T hread
konstruktore. To ime ispisuje to S trin g () nakon to ga dobije od m etode getN am e().
M oda ete sresti i idiom objekta tipa R unnable koji sam sobom upravlja:
//: paralelno/Samoupravno.java
// Objekat tipa Runnable koji sadri sopstvenu nit koja ga izvrava.
Poglavlje 2 1: Paralelno izvravanje 907
//: paralelno/VarijanteNiti.java
// Pravljenje niti pomou unutranjih klasa.
import java.util.concurrent.*;
import static net.mindview.uti1 .Print.*;
Unutrasnja(String ime) {
super(ime);
start();
}
public void run() {
try {
while(true) {
print(this);
if( odbrojavanje == 0) return;
sleep(lO);
}
} catch(InterruptedException e) {
print("prekinuto");
}
}
public String toStringO {
return getName() + ": " + odbrojavanje;
}
}
public UnutrasnjaNitl(String ime) {
unutrasnja = new Unutrasnja(ime);
}
}
}, ime);
t.start();
}
}
U nutrasnjaN itl pravi im enovanu unutranju klasu koja nasleuje Thread i u kon-
struktoru pravi instancu te unutranje klase. To ima smisla ako unutranja klasa ima po-
sebne sposobnosti (nove m etode) potrebne u drugim m etodam a. M edutim , nit obino
pravim o sam o zbog sposobnosti klase Thread, pa nije n eophodno da pravim o imenova-
nu unutranju klasu. U nutrasnjaN it pokazuje drugaiji pristup: u konstruktoru se pravi
ano nim na unutranja potklasa od Thread i svodi navie na Thread referencu t. Ukoliko
Poglavlje 2 1: Paralelno izvravanje 911
ostalim m etodam a te klase zatreba pristup objektu na koji upuuje t, m ogu to uiniti pre-
ko interfejsa T hread i bez poznavanja stvarnog tipa tog objekta.
Trea i etvrta klasa u prim eru ponavljaju prve dve klase, ali koriste interfejse Runna-
ble, a ne klasu Thread.
Klasa M etodaNit pokazuje pravljenje niti u n u tar m etode. M etodu pozivate kada ste
sprem ni da pokrenete tu nit, i m etoda vraa svoj rezultat nakon to nit otpone s radom .
Ukoliko nit obavlja sam o pom one, a ne i osnovne operacije klase, to je verovatno koris-
niji i prikladniji pristup nego to je pokretanje niti u n u tar konstruktora klase.
Veba 10: (4) Izm enite vebu 5 po uzoru na prim er s klasom MetodaNit, tako da m etoda
ru n T ask ( ) p rim a kao argum ent broj Fibonaccijevih brojeva koje treba sabrati, i svaki
p u t kada pozovete run T ask ( ), ona vraa objekat tipa Future koji proizvodi poziv m eto-
de s u b m it().
Terminologija
Kao to se vidi iz prethodnog odeljka, paralelni program i se u Javi m ogu pisati na vie
naina i to program era m oe da zbuni. esto problem nastaje zbog term inologije kojom
je opisan program za paralelno izvravanje, naroito tam o gde su u pitanju niti.
Dosad je trebalo da uvidite kako postoji razlika izm eu zadatka i niti koja taj zadatak
izvrava; ta razlika je naroito jasna u Javinim bibliotekam a, poto nad klasom Thread za-
pravo nem am o nikakvu kontrolu (a jo je jasnija kada se radi o izvriocima koji um esto
nas prave niti i upravljaju njim a). Program er pie zaatak i na neki nain m u dodeljuje nit
koja e ga izvravati.
U Javi, nit (klasa Thread) sam a po sebi ne radi nita. O na izvrava zadatak koji joj da-
mo. Pa ipak, u literaturi o vienitnom program iranju uvek se kae ,,nit radi ovo ili ono.
D obija se utisak da nit je s te zadatak. Kada sam upoznao Javine niti, utisak je bio toliko jak
da sam video jasnu relaciju JE, koja mi je govorila kako zadatak oigledno treba da izve-
dem iz klase Thread. Dodajte tom e loe odabrano ime interfejsa Runnable (koji se moe
izvravati); po m om miljenju, trebalo je da se zove Task (zadatak). Ukoliko interfejs
oigledno nije nita vie od generikog kapsuliranja svojih m etoda, onda je im enovanje
po kalupum oe da uradi lo i to odgovarajue, ali ako treba da izrazi vii pojam - kao to
je Zadatak - o nda m u treba dati ime tog pojma.
Problem potie od meanja nivoa apstrakcije. Na nivou koncepta, elimo da napravi-
m o zadatak koji se izvrava nezavisno od drugih zadataka, pa bi trebalo da je mogue de-
finisati zadatak i rei ,,radi, bez petljanja s detaljima. Ali fiziki, pravljenje niti je skupo, pa
m oram o da ih tedim o i upravljam o njim a. Zato sa stanovita realizacije im a smisla od-
vojiti zadatke od niti. Sem toga, Javine niti su napravljene na osnovu nekakvih p-niti koje
potiu jo iz C-a, a u tom jeziku program er je opkoljen detaljim a i m ora poznavati do u
sitnicu sve to se dogaa. Delimino je takav pristup preao i u realizaciju Jave, pa da bi-
sm o ostali na visokom nivou apstrakcije, m oram o biti disciplinovani pri pisanju progra-
ma. (Potrudiu se da u ovom poglavlju sam pokaem tu disciplinu.)
Da bi razm atranje bilo jasnije, term inom zadatak opisivau ono to se radi, a term i-
nom nit - m ehanizam koji izvrava zadatak. Dakle, ako sistem razm atram o na koncep-
tualnom nivou, m oem o upotrebiti term in zadatak, a da uopte ne spom injem o
m ehanizam izvravanja.
912 Misliti na Javi
//: paralelno/Joining.java
// Objanjenje metode join().
import static net.mindview.util.Print.*;
//: paralelno/BrzoKorisnickoOkruzenje.java
// Brzina reagovanja korisnikog okruenja.
// {RunByHand)
class SporoKorisnickoOkruzenje {
private volatile double d = 1;
public SporoKorisnickoOkruzenje() throws Exception {
while(d > 0)
d = d + (Math.PI + Math.E) / d;
System.in.read{); // Ovo se nikada ne izvrava
}
}
Grupe niti
G rupa niti sadri kolekciju niti. V rednost grupa niti saeo je Joshua Bioch,8 projektant
softvera koji je (izm edu ostalog), dok je radio za Sun, popravio i znatno poboljao biblio-
teku Java kolekcija u JDK 1.2:
G rupe niti je najbolje sm atrati neuspenim eksperim entom i zaboraviti da postoje.
Ukoliko ste (kao ja) potroili vreme i energiju pokuavajui da shvatite vrednost grupa
niti, m oda se pitate zato Sun o toj tem i nikada nije dao zvanino saoptenje. Isto vai i za
brojne druge prom ene sprovedene u Javi tokom godina. Izgleda da bism o mogli prim eniti
Teoriju rastueg angaovanjd' - njen tvorac je Joseph Stiglitz (dobitnik Nobelove nagrade).
Cenu nastavljanja greaka plaaju drugi, dok cenu priznavanja greaka plaam o sami.
Hvatanje izuzetaka
Izuzetak koji je pobegao iz niti ne m oete uhvatiti - takva je njihova priroda. Kada izuze-
tak izae iz m etode r u n ( ) zadatka, prodree do konzole ukoliko ne preduzm ete posebne
m ere za hvatanje takvih zabludelih greaka. Pre Jave SE5, za hvatanje takvih izuzetaka ko-
ristili sm o grupe niti, ali sada problem m oem o reiti izvriocima, te o grupam a niti vie
ne m oram o nita da znam o (sem onoliko koliko je po trebno da bism o razum eli stari kod;
pojedinosti o grupam a niti proitajte u knjizi T h in kin g in Java, 2 nE dition, koju m oete
preuzeti sa adrese w w w .M indV iew .net).
Sledei zadatak uvek baca izuzetak koji izlazi iz njegove m etode r u n ( ), a m a in ( ) po-
kazuje ta se deava kada ga pokrenete:
//: paralelno/Nitlzuzetka.java
// {ThrowsException}
import java.uti1 .concurrent.*;
java.1ang.RuntimeException
at Nitlzuzetka.run(Nitlzuzetka.java:7)
at ThreadPoolExecutor$Worker.runTask(Unknown Source)
at ThreadPoolExecutor$Worker.run(Unknown Source)
at java.1ang.Thread.run(Unknown Source)
//: paralelno/NaivnaObradalzuzetka.java
// {ThrowsException}
import java.uti1 .concurrent.*;
1 na nckoliko drugih m esta u celoj lavi. Zato da se o g ran iim o sam o na Javu? Bio sam k o n su ltan t u
vie projekata gde se pokazalo da je ta tv rdnja tana.
916 Misliti na Javi
//: paralelno/HvatanjeNeuhvacenihlzuzetaka.java
import java.uti1 .concurrent.
t .setllncaughtExceptionHandler(
new MojBlokZaObraduNeuhvacenihlzuzetakaO);
System.out.println(
"eh = 11 + t.getUncaughtExceptionHandler());
return t;
}
}
Ispisao sam i dodatne oznake kako biste mogli proveriti da se nitim a koje proizvodi
Factory daje novi UncaughtExceptionHandler. Moete videti da neuhvaene izuzetke
sada hvata m etoda neuhvacenlzuzetak( ).
G ornji prim er om oguuje da blok za obradu (engl. handler) prilagoavate svakom po-
jedinom sluaju. Ukoliko nam eravate da isti blok za obradu izuzetaka koristite svuda, jo
je jednostavnije da napravite p o d ra zu m eva n i blok za obradu neuhvaenih izuzetaka koji
postavlja odredeno statiko polje u klasi Thread:
//: paralelno/PodraBlokZaObraduNeuhvacenihlzuzetaka.java
import java.util.concurrent.*;
Ovaj program se poziva sam o u sluaju da ne postoji blok za obradu neuhvaenih izu-
zetaka prilagoden svakoj niti. Sistem proverava postoji li verzija za konkretnu nit i ako je
ne pronae, proverava da li ta grupa niti im a sopstvenu specijalizovanu m etodu
neuhvacenlzuzetak( ); ako nema, poziva se defau!tUncaughtExceptionHandler.
918 Misliti na Javi
Deljenje resursa
Program s jednom n id m oete da zamislite kao usam ljenu jedinku koja se kree kroz pro-
stor vaeg problem a i reava jedan po jedan zadatak. Poto postoji samo jedna jedinka,
uopte ne m orate da vodite rauna o situaciji kada dve jedinke pokuavaju da iskoriste isti
resurs istovremeno, p o p u t dvoje koji pokuavaju da se parkiraju na istom mestu, ili da
prou kroz vrata istovrem eno ili ak da sam o govore istovremeno.
Ako za reavanje problem a upotrebite vie niti, ne javlja se problem usam ljenih jedin-
ki, ali postoji m ogunost da dve ili vie niti pokuaju da upotrebe isti ogranien resurs u
istom trenutku, tj. da se uzajam no om etu. Sukobljavanje zbog nekog resursa m ora se
spreiti ili e dve niti istovrem eno pokuati da pristupe istom bankovnom nalogu,
odtam paju neto na istom tam pau, okrenu isti ventil itd.
G eneratorCelobroj ima m etodu can cel( ) za prom enu stanja boolean indikatora can-
celled i m etodu isC ancelled( ) koja utvruje da li je pravljenje objekta otkazano. Poto je
indikator cancelled tipa boolean, on je a to m ski (nedeljiv), to znai a takvo polje ne
m oete proitati u nekom m eustanju usred jednostavnih operacija kao to su dodelji-
vanje i vraanje vrednosti, jer se one ne m ogu prekidati. Indikatoru cancelled dodat je i
m odifikator volatile, da bi se obezbedila vidljivost. O atom skim indikatorim a i vidljivosti
saznaete vie u nastavku poglavlja.
Sledea klasa ProveraParnosti moe da testira svaki GeneratorCelobroj:
//: paralelno/ProveraParnosti.java
import java.util.concurrent.*;
Poglavlje 2 1: Paralelno izvravanje 919
Zadaci ProvereParnosti stalno itaju i ispituju brojeve koje je dao njim a pridrueni
GeneratorCelobroj. Ukoliko generator.isC ancelled( ) im a vrednost true, m etoda r u n ( )
vraa svoj rezultat i izlazi, to izvriocu u m etodi ProveraParnosti.test( ) kazuje da je
zadatak obavljen. Svaki zadatak ProvereParnosti m oe da pozove m etodu cancel( ) za
svoj pridrueni G eneratorCelobroj, im e prouzrokuje da sve druge ProvereParnosti tog
objekta tipa GeneratorCelobroj n orm alno okonaju svoj rad. U nastavku poglavlja vi-
deete da Java im a i optije m ehanizm e za okonavanje rada niti.
Prvi GeneratorCelobroj koji em o razm otriti im a m eto d u n e x t( ) koja proizvodi se-
riju parnih brojeva:
//: paralelno/GeneratorParnih.java
// Kada se niti sudare.
Moe se desiti da jedan zadatak pozove n e x t ( ) nakon to je drugi zadatak obavio prvo
poveanje broja tekuciP arniB roj za 1, ali ne i drugo (na o nom m estu u program u gde
stoji kom entar Ovo je opasno!). Tim e je broj dospeo u nepravilno stanje. Da bih vam
dokazao da se to m oe dogoditi, P ro v e ra P a rn o sti.te st() pravi grupu objekata tipa Pro-
v era P a rn o sti koji stalno itaju izlaz G en e ra to raP arn ih i ispituju parnost svakog od tih
brojeva. Kada se pronae neki koji nije paran, prijavljuje se greka i program se gasi.
Taj program pre ili kasnije m ora da otkae, zato to zadaci P ro v ereP arn o sti m ogu da
pristupe inform acijam a u G e n e ra to ru P a rn ih dok je on u nepravilnom stanju. M eutim ,
problem ne m ora biti otkriven dok G en e ra to rP a rn ih ne izvri m nogo ciklusa, iji se broj
m enja u zavisnosti od operativnog sistema i pojedinosti realizacije. Ako elite da vidite ot-
kazivanje to pre, izm eu prvog i drugog poveanja za 1 stavite poziv m etode y ie ld ( ). I to
je deo problem a s vienitnim program im a - um eju da daju privid ispravnosti ak i kada
greka postoji, ukoliko je verovatnoa otkazivanja veoma mala.
Vano je uoiti da se operacija poveanja za 1 interno sastoji od vie koraka, i da vie-
nitni m ehanizam moe zaustaviti (prekinuti) zadatak usred tih koraka - drugim reima,
u Javi poveanje za 1 nije atom ska operacija. Dakle, ak se ni poveanje za 1 ne moe oba-
viti bezbedno ako zadatak nije zatien.
Poglavlje 21: Paralelno izvravanje 921
Ve ste nauili da podaci klasa m oraju biti privatni (im ati m odifikator private) u kodu
koji se isporuuje kupcima; toj m em oriji treba da pristupate sam o preko m etoda. Sukobe
ete spreiti tako to ete deklarisati da su te m etode sinhronizovane, to se radi ovako:
Svi objekti autom atski dobijaju sopstvenu bravu (koristi se i ime m onitor). Kada pozo-
vete bilo koju sinhronizovanu m etodu, objekat se zakljuava i nijedna druga sinhronizo-
vana m etoda tog objekta ne m oe biti pozvana dok se prva ne zavri i ne otkljua tu bravu.
Za prethodne m etode vai sledee: ako jedan zadatak pozove f ( ) za neki objekat, drugi
zadaci ne m ogu pozivati ni f ( ) ni g ( ) za taj objekat dokle god f ( ) ne zavri rad i ne otkljua
bravu. Dakle, postoji samo jedna brava koju dele sve sinhronizovane m etode odreenog
objekta, i ona spreava da vie zadataka istovremeno upisuje u m em oriju objekta.
Vodite rauna o tom e da je za paralelno izvravanje izuzetno vano da polja b u d u pri-
vatna; ako nisu, rezervisana re synchronized ne m oe spreiti druge zadatke da polju
pristupaju neposredno i tako izazivaju sukobe.
Isti zadatak moe vie puta zakljuati objekat. To se deava kada jedna m etoda za isti
objekat pozove drugu m etodu, a druga za isti objekat pozove treu itd. JVM prati broj
zakljuavanja objekta. Broj zakljuavanja otkljuanog objekta je nula. Kada zadatak prvi
put zakljua taj objekat, broj zakljuavanja se povea za jedan. Svaki p ut kada taj zadatak
ponovo zakljua taj objekat, broj zakljuavanja se povea za jedan. Naravno, samo
zadatak koji je prvi zakljuao taj objekat m oe da ga zakljua vie puta. Broj zakljuavanja
se sm anjuje za jedan kad god taj zadatak izae iz neke od sinhronizovanih m etoda; kada
broj zakljuavanja padne na nulu, objekat je slobodan i m ogu ga koristiti drugi zadaci.
I svaka klasa autom atski dobija svoju bravu (koja je deo njenog objekta klase Class),
tako da sinhronizovane statike m etode (oznaene kao synchronized i static) mogu jed-
na drugu spreiti da istovrem eno pristupe statikim podacim a u okviru pojedine klase.
Kada sinhronizovati? Prim enite B rajanovopravilo sinhronizacijc:'0
Sinhronizaciju m orate upotrebiti ukoliko piete u prom enljivu koju bi zatim mogla da
proita neka druga nit ili itate prom enljivu koju je prethodno m ogla upisati neka druga
nit. Nadalje, i itanje i pisanje m ora biti sinhronizovano pom ou iste brave (m onitora).
Ako u klasi im ate vie m etoda koje rade s bitnim podacima, m orate sinhronizovati sve
relevantne metode. Ukoliko sinhronizujete sam o jednu od tih m etoda, ostale m ogu zane-
m ariti bravu na objektu i biti nesm etano pozvane. Ovo je vano: sve m etode koje pri-
stupaju kritinom resursu m oraju biti sinhronizovane ili program nee raditi kako treba.
Sinhronizovanje GeneratoraParnih
Ako klasi G eneratorParnih.java dodam o rezervisanu re synchronized, spreiemo
neeljeno pristupanje toj niti:
10 Po Brianu Goetzu, koautoru ]ava Concurrency in Practice ; ostali autori su Tini Peierls, Joshua Bloch,
Joseph Bowbeer, David Holmes i Doug Lea (Addison-WesIey, 2006).
Poglavlje 2 1: Paralelno izvravanje 923
//: paralelno/SinhronizovanGeneratorParnih.java
// Pojednostavljivanje uzajamno iskljuivih brava
// pomou rezervisane rei synchronized.
// {RunByHand}
public class
SinhronizovanGeneratorParnih extends GeneratorCelobroj {
private int tekuciParniBroj = 0;
public synchronized int next() {
++tekuciParniBroj;
Thread.yield(); // Bre izaziva zakazivanje
++tekuci ParniBroj;
return tekuciParniBroj;
}
public static void main(String[] args) {
ProveraParnosti .test(new SinhronizovanGeneratorParnihO);
}
} ///= -
Poziv m etode T hread.yield( ) um etnut je izmeu dva poveanja za 1 da bi se poveala
verovatnoa prebacivanja konteksta dok je tekuciParniBroj neparan. Poto uzajam no
iskljuiva brava spreava da vie zadataka u isto vreme bude u kritinom delu program a,
do otkazivanja nee doi, ali poziv m etode y ie ld ( ) pom ae da se otkazivanje ranije desi
ukoliko ve moe da nastane.
M etodu n e x t( ) zakljuava prvi zadatalc koji ue u nju, i svi drugi zadaci koji pokuaju
da je zakljuaju bivaju blokirani sve dok je prvi zadatak ne otkljua. Tada m ehanizam za
raspodelu procesorskog vrem ena odabire jedan od ostalih zadataka koji ekaju da se bra-
va otkljua. Na taj nain, u svakom trenutku samo po jedan zadatak moe proi kroz kod
koji uva uzajam no iskljuiva brava (mutex).
Veba 11: (3) N apravite klasu koja sari dva polja podataka i m etodu koja radi s tim
poljim a u postupku koji traje vie koraka, tako da tokom izvravanja te m etode polja
budu u nepravilnom stanju (u odnosu na definiciju koju ete sami dati). D odajte m etode
koje itaju ta polja i napravite vie niti za pozivanje raznih m etoda i pokaite da su poda-
ci vidljivi i kada su nepravilni. Reite problem pom ou rezervisane rei synchronized.
//: paralelno/MutexGeneratorParnih.java
// Spreavanje sukoba niti pomou uzajamno iskljuivih brava (mutexa).
// {RunByHand)
import java.util.concurrent.locks.*;
924 Misliti na Javi
//: paralelno/PokusajZakljucavanja.java
// Brave u biblioteci concurrent dozvoljavaju
// da odustanete od pokuaja zakljuavanja.
import java.uti1 .concurrent.*;
import java.util.concurrent.locks.*;
try (
System.out.println("tryLock(): " + zakljucano);
) finally {
if (zakl jucano)
brava.unlock();
1
}
public void odredjenoVremeO {
boolean zakljucano = false;
try {
zakljucano = brava.tryLock(2, TimeUnit.SECONDS);
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
try {
System.out.println("tryLock(2, TimeUnit.SECONDS): " +
zakljucano);
} finally {
if(zakljucano)
brav a .u n l o c k O ;
}
}
public static void main(String[] args) {
final PokusajZakljucavanja pz = new PokusajZakljucavanja();
pz.neodredjenoVremeO ; // True -- brava je otkljuana
pz.odredjenoVreme(); // True brava je otkljuana
// Sada napravi zaseban zadatak koji e pokuati da zakljua:
new Thread() {
{ setDaemon(true); }
public void run() {
p z .brava.1ock();
System.out.pri ntln("zakljuano");
}
}.start();
Thread.yield(); // Daj priliku drugom zadatku
pz.neodredjenoVremef); // False -- prethodni zadatak je ve zakljuao
pz.odredjenoVremeO; // False prethodni zadatak je ve zakljuao
}
} /* Ispis:
tryLock(): true
tryLock(2, TimeUnit.SECONDS): true
zakljuano
tryLock(): false
tryLock(2, TimeUnit.SECONDS): false
* ///:-
1'Po p re th o d n o p o m enutom B rajanu Gecu (Brian G oetz), stru n jak u za paralelno p ro g ram iran je koji
m i je po m o g ao da napiem ovo poglavlje na osnovu njegovih sam o elim in o drskih kom entara.
2 Iz ovog testa n epo sredno sledi: ,Ako neko tvrdi da je paraleln o p ro g ram iran je lako i jednostavno,
po starajte se da ta osoba ne donosi vane odluke o projektu na kojem radite. Ukoliko to nikako ne
m oete da izbegnete, im ate problem .
Poglavlje 21: Paralelno izvravanje 927
Katkada izgleda da bi atom ska operacija trebalo da bude bezbedna, ali ona to nije. Veina
italaca ove knjige sigurno nee m oi da poloi spom enuti Gecov test, te uopte nisu kva-
lifikovani n i da pokuaju da sinhronizaciju zam ene atom skim operacijama. Pokuaj
uklanjanja sinhronizacije obino je znak prerane optim izacije i prouzrokuje grdne pro-
bleme, a dobitak je mali ili nikakav.
Na vieprocesorskim sistemima (koji se sada prave u obliku procesora s vie jezgara
- to je vie procesora u jednom integrisanom kolu), m nogo vei problem od neprekidno-
sti operacija je vidljivost. (Taj problem ne postoji u jednoprocesorskim sistemima.) Izme-
ne koje napravi jedan zadatak, ak i kada su atom ske, odnosno neprekidne, ne m oraju biti
vidljive drugim zadacima (jer sii privrem eno smeterte u lokalni ke procesora, na pri-
m er), pa razni zadaci dobijaju razliite uvide u stanje aplikacije. S druge strane,
m ehanizam sinhronizacije obezbeuje da izm ene koje na vieprocesorskom sistemu na-
pravi jedan zadatak b u du vidljive celoj aplikaciji. Bez sinhronizacije se ne m oe znati kada
e izm ene postati vidljive.
Vidljivost u celoj aplikaciji obezbeduje i rezervisana re volatile. Ako deklariete da je
neko polje volatile, to znai da e svi zadaci koji ga itaju videti izmenu im se upisivanje
u njega zavri. To vai ak i za lokalnu ke m em oriju, zato to se polja oznaena s volatile
odm ah prepisuju u glavnu m em oriju, a sva itanja se obavljaju iz glavne m em orije.
Nadam se da shvatate kako su neprekidnost i trenutna vidljivost razliiti pojmovi.
Atomska operacija polja koje nem a m odifikator volatile ne m ora da bude o dm ah pre-
pisana u glavnu m em oriju, pa ni drugi zadaci koji itaju to polje ne m oraju odm ah da
vide novu vrednost. Svako polje kojem pristupa vie zadataka treba da im a m odifikator
volatile; u protivnom , polju treba pristupati sam o preko sinhronizacije. I sinhronizacija
prouzrokuje prepisivanje u glavnu m em oriju, pa polje koje je potpuno zatieno
sinhronizovanim m etodam a ili blokovim a ne m ora da ima m odifikator volatile.
Rezultati svih upisivanja koja zadatak obavi odm ah su vidljivi tom zadatku, pa polju
ne m orate da dodajete m odifikator volatile ukoliko ga ita sam o njegov zadatak.
volatile ne funkcionie kada vrednost polja zavisi od njegove prethodne vrednosti
(takvo je poveanje vrednosti brojaa za 1), niti funkcionie za vrednosti koje su ogra-
niene vrednostim a drugih polja, kao to su lovver (donja) i upper (gornja) granica ob-
jekta tipa Range koje m oraju da zadovolje ogranienje lovver <= upper.
U potreba m odifikatora volatile umesto rezervisane rei synchronized bezbedna je naj-
ee jedino u sluaju da klasa ima samo jedno prom enljivo polje. Ponavljam, najbolje je
izabrati rezervisanu re synchronized - to je najbezbedniji pristup, a sve ostalo je rizino.
Koje operacije su atomske? Dodeljivanje i vraanje vrednosti polja obino su atomske
operacije. M eutim , u C++-U bi atom ske mogle biti ak i ove operacije:
U Javi gornje operacije sigurno nisu atomske, kao to vidite iz JVM instrukcija koje
proizvode sledee metode:
//: paralelno/Neprekidnost.java
// {Pokretanje: javap -c NeprekidnostJ
void fl();
Code:
0: aload_0
1: dup
2: getfield #2; //Polje i:I
5: iconst_l
6: iadd
7: putfield #2; //Polje i:I
10: return
void f2();
Code:
0: aload_0
1: dup
2: getfield #2; //Polje i : I
5: iconst_3
6: iadd
7: putfield #2; //Polje i:I
10: return
* ///:-
Svaka instrukcija proizvodi jedan get i jedan p ut izmeu kojih ima drugih instrukcija.
Dakle, izm eu itanja (get) i upisivanja (put) neki drugi zadatak moe da izmeni vred-
nost polja; stoga te operacije nisu atomske.
Ako slepo prim enjujete neprekidnost, mogli biste pom isliti da je takva i m etoda
d a j V r e d n o s t ( ) u sledeem program u:
//: paralelno/TestNeprekidnosti.java
import java.uti1.concurrent.*;
//: paralelno/GeneratorSerijskihBrojeva.java
Idcja iz knjige Efikasno programiranje na ]avi Joshue Blocha (M ikro knjiga, 2004), s. 168.
930 Misliti na Javi
Polje serijskiBroj im a m odifikator volatile zato to svaka nit moe da ima lokalni stek
i da u njem u odrava kopije nekih promenljivih. Ako ispred definicije promenljive stavite
m odifikator volatile, tim e kazujete prevodiocu da ne sprovodi optimizacije kojima bi se
uklonila itanja i upisivanja koja polje odravaju u sinhronizaciji s lokalnim podacim a u
nitim a. Zato se itanja i upisivanja obavljaju neposredno u glavnoj m emoriji, a ne u keu.
M odifikator volatile ograniava i prevodioevo prerasporeivanje pristupa tokom optim i-
zacije. M eutim , volatile ne utie na injenicu da poveanje za 1 nije atomska operacija.
U sutini, definiite da je polje volatile ukoliko m u vie zadataka moe istovremeno
pristupiti, a barem jedno od tih pristupanja je upisivanje. Prim era radi, polje koje se
upotrebljava kao indikator za zaustavljanje zadatka m ora biti deklarisano kao volatile; u
protivnom bi indikator m ogao biti keiran u nekom registru procesora, i ta vrednost se ne
bi izm enila kada vi iz nekog drugog zadatka izm enite vrednost indikatora, pa prvi
zadatak ne bi znao kada treba da se zaustavi.
Za ispitivanje GeneratoraSerijskihBrojeva treba nam skup kojem nee ponestati me-
m orije ni u sluaju da pronalaenje problem a potraje. Ovde prikazani KruzniSkup po -
novo upotrebljava m em oriju u kojoj su bili uskladiteni celi brojevi, uz pretpostavku da
e verovatnoa sukoba sa zam enjenim brojevim a biti m inim alna kada se s kraja skupa
vratim o na njegov poetak. M etode a d d ( ) i co n tain s( ) sinhronizovane su da bi se sprei-
Io sudaranje niti:
//: paralelno/ProveraSerijskihBrojeva.java
// Operacije prestaju da budu bezbedne
// kada izvravanje postane vienitno.
// {Args: 4}
import java.uti1 .concurrent.*;
atom sku operaciju koja pristupa objektu dok je o n u nekom nestabilnom m eustanju.
D onositi bilo kakve zakljuke o tom e kakljivo je i opasno. N ajrazboritije je prosto pri-
dravati se Brajanovog pravila za sinhronizaciju.
Veba 12: (3) Popravite TestNeprekidnosti.java pom ou rezervisane rei synchronized.
U m ete li da pokaete kako je program sada ispravan?
Veba 13: (1) Popravite program ProveraSerijskihBrojeva.java p o m o u rezervisane rei
synchronized. U mete li da pokaete kako je program sada ispravan?
Atomske klase
Java SE5 je donela i posebne atom ske klase prom enljivih kao to su Atomiclnteger, Ato-
micLong, AtomicReference itd., koje obezbeuju atom sko uslovno auriranje oblika:
O ne su nam enjene za fino podeavanje p ri kom e se koriste atom ske operacije (nepie-
Idnosti) dostupne na nekim od savrem enih procesora, pa o njim a po pravilu ne bi tre-
balo da razbijate glavu. Ponekad m ogu da poslue i za obino program iranje, ali opet
tam o gde se radi o podeavanju perform ansi. Na prim er, izm eniem o TestN eprekidno-
sti.java tako da upotrebljava klasu A tom iclnteger:
//: paralelno/AtomicIntegerTest.java
import java.util.concurrent.*;
import java.uti1 .concurrent.atomic.*;
import java.util.*;
System.out.println(vre);
System.exit(0);
}
)
}
} ///= -
U potrebom klase Atom iclnteger izbegli sm o korienje rezervisane rei synchroni-
zed. Poto ovaj program ne otkazuje, dodat je Tim er koji autom atski prekida rad nakon
5 sekundi.
Evo kako izgleda M utexG eneratorParnih.java izm enjen tako da upotrebljava klasu
Atomiclnteger:
//: paralelno/AtomskiGeneratorParnih.java
// Atomske klase se povremeno koriste i u obinim programima.
// {RunByHand}
import java.util.concurrent.atomic.*;
Kritini odeljci
Ponekad treba izolovati sam o deo koda u n u ta r m etode r u n ( ), a ne celu m etodu. Deo koji
treba izolovati naziva se kritian (engl. critical), a rezervisana re synchronized se u kri-
tinom delu program a koristi drugaije. U sledeem prim eru re synchronized zakljua-
va bravu odreenog objekta da bi sinhronizovala obuhvaeni blok koda:
synchronized(brava) {
// Ovom kodu moe da pristupi samo jedna nit u jednom trenutku
93 4 Misliti na Javi
O buhvaeni blok koda naziva se sinhrortizovani blok, pre ulaska u sinhronizovani blok,
raorate da zakljuate objekat brava. Ako je neka druga nit ve zakljuala taj objekat, u taj
blok nije mogue ui sve dok ne bude otkljuan.
U sledeem prim eru uporeena su oba p ristupa sinhronizaji. Pokazano je da se vre-
m e tokom kojega je objekat dostupan d rugim zadacim a znatno produava kada se koristi
sinhronizovani blok um esto sinhronizovanja cele m etode. Pored toga, pokazano je kako
se nezatiena klasa m oe upotrebiti u vienitnoj situaciji ukoliko je kontrolie i titi dru-
ga klasa:
//: paralelno/KriticanDeo.java
// Sinhronizovanje blokova umesto celih metoda. Pokazuje i zatitu klase
// nebezbedne u vienitnom izvravanju pomou druge koja je bezbedna.
package concurrency;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util
} /* Ispis: (primer)
mpl: Par: x: 15, y: 15 brojacProvera = 272565
mp2: Par: x: 16, y: 16 brojacProvera = 3956974
* ///:-
Kao to rekoh, Par nije bezbedan u vienitnom izvravanju zato to njegova invarijan-
ta (priznajem , sasvim proizvoljno) zahteva da obe prom enljive zadre istu vrednost. Sem
toga, ve ste u p retho dn om delu poglavlja videli da operacije poveanja za jedan nisu bez-
bedne u vienitnom izvravanju, a poto nijedna od m etoda nije sinhronizovana, ne
m oete oekivati da e objekat tipa Par ostati nepokvaren u vienitnom program u.
Recimo da vam je neko dao klasu Par koja nije bezbedna u vienitnom izvravanju, a vi
m orate da je upotrebite u vienitnom okruenju. To ete postii pravljenjem kiase Mena-
dzerPara koja sadri objekat tipa Par i kontrolie pristupanje njemu. Vodite rauna o tom e
da su jedine javne m etode d ajP ar( ), koja je sinhronizovana, i apstraktna m etoda povecaj-
Z ajed an ( ). M etoda povecajZaJedan( ) bie sinhronizovana na m estu svoje realizacije.
S truktura klase MenadzerPara, u kojoj funkcije realizovane u osnovnoj klasi
upotrebljavaju jednu ili vie apstraktnih m etoda definisanih u izvedenim klasama, naziva se
projektni obrazac Template M ethod.'5 Projektni obrasci om oguuju kapsuliranje prom ena
u kodu; deo koji se ovde menja je metoda povecajZaJedan( ). U klasi MenadzerParal
sinhronizovana je cela metoda povecajZaJedan( ), dok je u klasi MenadzerPara2 pom ou
sinhronizovanog bloka sinhronizovan samo deo metode povecajZaJedan( ). O bratite
panju na to da rezervisana re synchronized ne spada u potpis m etode i stoga se m oe do-
dati prilikom preklapanja.
M etoda sacuvaj( ) dodaje olijekat tipa Par sinhronizovanoj listi tipa ArrayList, pa je ta
operacija bezbedna u vienitnom izvravanju. Stoga nju ne m oram da titim , pa sam je
sm estio izvan sinhronizovanog bloka u klasi MenadzerPara2.
RukovalacPara je napravljen da bi pozivanjem m etode povecajZaJedan( ) iz zadatka te-
stirao dve razliite realizacije apstraktne klase MenadzerPara, dok se ProveraPara obavlja
iz drugog zadatka. Svaki put kada je ProveraPara uspena, ona brojacProvera povea za 1
i tako prati uestalost prilika da obavi testiranje. U metodi m a in ( ), prave se dva objekta tipa
RukovalacPara koji neko vreme rade pa se potom prikazuju rezultati svakog od njih.
Iako e se izlazni rezultati verovatno m nogo razlikovati od jednog do drugog izvra-
vanja, videete da m etoda M enadzerPara).povecajZaJedan( ) nc dozvoljava klasi Prove-
raPara pristup ni priblino onoliko esto kao m etoda M enadzerPara2.povecajZaJedan( )
koja ima sinhronizovan blok i zato due radi bez zakljuavanja. O bino je ba to razlog za
upotrebu sinhronizovanog bloka umesto sinhronizacije cele metode: om oguiti drugim
zadacim a ei i dui pristup (koliko je to bezbedno).
Za zatitu kritinih delova program a moete upotrebiti i eksplicitne objekte tipa Lock:
//: paralelno/EksplicitanKriticanDeo.java
// Zatita kritinih delova programa eksplicitnim objektima tipa Lock.
package concurrency;
import java.uti1.concurrent.locks.*;
// Kritian deo:
class EksplicitanMenadzerPara2 extends MenadzerPara {
private Lock brava = new ReentrantLock();
public void povecajZaJedan () {
Par privr;
brava.lockO;
try {
p.povecajXzaJedan();
p.povecajYzaJedan();
privr = dajPar();
} finally {
brava.unlockO ;
}
sacuvaj(pri vr);
}
//: paralelno/ObjekatSinhronizacije.java
// Sinhronizacija s drugim objektom.
import static net.mindview.util.Print.*;
class DvojnaSinhronizacija (
private Object objekatSinhronizacije = new Object();
public synchronized void f() {
for(int i = 0; i < 5; i++) {
print("f()");
Thread.yield();
)
}
public void g() {
synchroni zed(objekatSinhronizacije) {
for(int i = 0 ; i < 5 ; i++) {
pri n t ("g()");
Thread.yield();
}
}
}
f()
9 ()
f()
g()
f()
g()
f()
* ///:-
DvojnaSinhronizacija.f( ) sinhronizuje na objekat this (sinhronizacijom cele m eto-
de), a g ( ) im a sinhronizovan blok koji sinhronizuje na objekatSinhronizacije. Dakle, te
dve sinhronizacije su nezavisne. To je dokazano u m etodi m a in ( ) pravljenjem niti
(objekta tipa Thread) koja poziva f ( ). Glavna nit - m etode m a in ( ) - upotrebljena je za
poziv g ( ). Iz rezultata vidite da se obe m etode izvravaju istovrem eno, dakle sinhroniza-
cija jedne ne blokira onu drugu.
Veba 15: (1) Napravite klasu s tri m etode koje sadre kritine delove, a sve su
sinhronizovane sa istim objektom . N apravite vie zadataka kako biste pokazali da se u
svakom trenutku moe izvravati sam o jedan od njih. Potom m odifikujte m etode tako
da se sinhronizuju s razliitim objektim a i pokaite da se sve tri m etode m ogu izvravati
istovremeno.
Veba 16: (1) Izmenite vebu 15 tako da se upotrebljavaju eksplicitni Lock objekti.
* ///:-
Objekti tipa ThreadLocal obino se skladite kao statika polja. Kada napravite objekat
tipa ThreadLocal, sadraju tog objekta moete pristupiti sam o m etodam a g e t( ) i s e t( ).
Metoda g e t( ) vraa kopiju objekta pridruenu toj niti, dok s e t( ) umee svoj argum ent u
objekat uskladiten za tu nit i vraa stari objekat koji je bio u tom skladitu. To pokazuju
m etode povecajZaJean( ) i g e t( ) program a ThreadLocalSpremnikPromenljivih.
O bratite panju na to da m etode povecajZaJedan( ) i g e t( ) nisu sinhronizovane, zato to
ThreadLocal jemi da nee doi do uslova za trku.
Kada pokrenete ovaj program , videete dokaz da se svakoj niti dodeljuje njeno sop-
stveno skladite, poto svaka od njih odrava sopstveni broja iako postoji sam o jedan ob-
jekat ThreadLocalSpremnikPromenljivih.
942 Misliti na Javi
Gaenje zadataka
U nekim a od prethodnih prim era, m etode cancel( ) i isCanceIled( ) sm etene su u klasu
vidljivu svim zadacima. Zadaci ispituju vrednost m etode isC ancelled( ) da bi znali kada
da se ugase. To je razborit pristup problem u. M eutim , u nekim situacijam a zadatak
m ora biti ugaen naglije. U ovom odeljku saznaete sve o takvom gaenju i problem im a
zbog njega.
Prvo, razm otrim o prim er koji ne sam o da pokazuje problem gaenja, nego je i doda-
tan prim er deljenja resursa.
Ukrasna bata
U ovoj simulaciji, batenska komisija bi htela da zna koliko Ijudi svakog dana ue u batu
kroz neku od njenih kapija. Svaka kapija im a blokirajuu vrteku ili neku dru g u vrstu
brojaa, i nakon poveanja brojaa blokirajue vrteke za 1, poveava se i zajedniki bro-
ja koji predstavlja ukupan broj posetilaca bate.
//: paralelno/UkrasnaBasta.java
import java.util.concurrent.*;
import java.util
import static net.mindview.uti1 .Print.*;
class Broj {
private int broj = 0;
private Random slucajan = new Random(47);
// Ako uklonite rezervisanu re synchronized,
// prebrojavanje e zakazati:
public synchronized int povecajZaJedan() {
int privr = broji;
if(slucajan.nextBoolean()) // Pola vremena prepusti drugima
Thread.yield();
return (broj = ++privr);
}
public synchronized int value() { return broj; }
}
Ulaz 1: 1 Ukupno: 2
Ulaz 4: 1 Ukupno: 5
Ulaz 3: 1 Ukupno: 4
Ulaz 2: 2 Ukupno: 6
Ulaz 4: 2 Ukupno: 7
Ulaz 0: 2 Ukupno: 8
i stoga zavre svoje izvravanje, objekti tipa Ulaz i dalje su validni zato to je u konstruk-
to ru svaki objekat Ulaz uskladiten u statikoj listi ulazi tipa List<Ulaz>. Zato
saberiU laze( ) i dalje radi s validnim objektim a Ulaz.
D ok ovaj program bude radio, prikazivae ukupan broj posetilaca i broj posetilaca na
svakom ulazu koji p ro u kroz blokirajuu vrteku. Ako uklonite deklaraciju synchroni-
zed ispred m etode Broj.povecajZaJedan( ), videete da ukupan broj posetilaca nije jed-
nak oekivanom . Broj posetilaca koji se prebroji na svim blokirajuim vrtekam a nee
biti jednak iznosu prom enljive broj. Sve ispravno radi dok postoji uzajam no iskljuiva
brava (m utex) koja sinhronizuje pristupanje objektu Broj. Imajte u vidu da m etoda
Broj.povecajZaJedan( ) pom ou prom enljive p riv r i m etode y ield ( ) n am erno poveava
m ogunost otkazivanja. U pravim vienitnim problem im a, m ogunost otkazivanja m oe
biti statistiki mala, pa ete lake poverovati u zabludu da va program radi ispravno. Kao
u gornjem prim eru, verovatno e postojati i skriveni problem i kojih niste svesni, pa bu-
dite izuzetno paljivi kada pregledate program e za paralelno izvravanje.
Veba 17: (2) N apravite Gajgerov broja koji m oe im ati proizvoljan broj daljinskih
senzora.
Stanja niti
Nit m oe biti u jed no m od etiri stanja:
1. Nova: Nit je u ovom stanju privrem eno, dok je prave. O na dodeljuje potrebne si-
stemske resurse i obavlja inicijalizaciju. O d tog trenutka postaje podobna za pri-
m anje procesorskog vrem ena. Potom m ehanizam za raspodelu vrem ena menja
stanje niti u sprem na za izvravanje ili blokirana.
2. Sprem na za izvravanje: Znai da se nit m oe pokrenuti kada m ehanizam podele
procesorskog vrem ena bude im ao slobodnih procesorskih ciklusa za nju. M oda se
ta nit izvrava, a m oda i ne, ali nita ne m oe spreiti njeno izvravanje ukoliko joj
m ehanizam za raspodelu vrem ena dodeli procesor. D rugim reima, nit nije ni m rt-
va ni blokirana.
3. Blokirana: Nit bi mogla da se izvrava, ali je neto spreava. D ok je nit blokirana,
m ehanizam za raspodelu vrem ena je preskae i ne dodeljuje joj procesor. Sve dok
ta nit ponovo ne postane sprem na za izvravanje, nee biti pokretana.
4. M rtva: M rtva ili ugaena (engl. term inated) nit vie nije podobna za rasporeivanje
i procesorsko vrem e joj se ne dodeljuje. Njen zadatak je zavren i ona se vie ne
moe pokrenuti. Zadatak norm alno um ire kada se vrati iz svoje m etode r u n ( ), ali
i njegova nit m oe biti prekinuta, kao to ete uskoro videti.
946 Misliti na Javi
Prekidanje izvravanja
Kao to m oete zamisliti, m nogo je tee izai iz m etode R unnable.run( ) pre njenog kraja
nego saekati da ona dospe do mesta gde ispituje vrednost indikatora ,,otkai ili do ne-
kog drugog m esta gde je program er sprem an da napusti tu m etodu. Kada izaete iz blo-
kiranog zadatka, esto treba da poistite resurse. Zato izlazak iz m etode r u n ( ) datog
zadatka pre njenog kraja, najvie lii na bacanje izuzetka, pa se u Javinim nitim a za tu vr-
stu prekidanja koriste izuzeci.16 (Ovo je na samoj ivici nekorektne upotrebe izuzetaka,
poto znai da ih esto upotrebljavate za kontrolu toka program a.) Da biste se prilikom
ovakvog gaenja zadatka vratili na neko od poznatih dobrih stanja, m orate paljivo raz-
m otriti putanje izvravanja koda i napisati odredbu catch tako da pravilno sve poisti.
Klasa Thread sadri m etodu in te rru p t( ) koja slui za gaenje blokiranih zadataka. O na
niti daje status prekinute. Nit kojoj je postavljen status prekinuta baca izuzetak Interrup-
tedException ukoliko je ve blokirana ili pokuava da izvri operaciju koja prouzrokuje
blokiranje. Status prekinuta bie resetovan kada se baci izuzetak ili kada zadatak pozove
m etodu T h read .interru p ted ( ). Kao to ete videti, m etoda T hread.interrupted( ) prua
drugi nain izlaska iz petlje r u n ( ), bez bacanja izuzetka.
16 M e u tim , izuzeci se nikada ne generiu asinhrono. Stoga n en ia o p asn osti da neto prekine instruk-
ciju/poziv m eto d e. Ukoliko p rilikom u p o treb e m utexa (za razliku o d rezervisane rei sy n c h ro n ized )
b u d ete upotrebljavali idiom try-fin ally, te u zajam no iskljuive brave (m utex i) bie autom atski ot-
k ljuane kada se baci izuzetak.
Poglavlje 21: Paralelno izvravanje 947
Da biste pozvali in te rru p t( ), m orate im ati nit, tj. objekat tipa Thread. M oda ste
uoili da nova biblioteka concurrent (za paralelno izvravanje) kao da izbegava neposre-
dan rad s nitim a; ona sve pokuava da ostvari izvriocima. Ako pozovete shutdow n-
N ow ( ) za nekog izvrioca, on e poslati poziv in te rru p t( ) svim nitim a koje je pokrenuo.
To im a smisla, poto najee hoem o odjednom da ugasim o sve zadatke odredenog
izvrioca, kada zavrimo deo projekta ili ceo program . M eutim , im a sluajeva kada bi-
sm o da ugasim o sam o jedan zadatak. Ako radite sa izvriocem, kontekst zadatka koji ste
pokrenuli m oete da uhvatite tako to ete pozvati m etodu su b m it( ) um esto m etode
execute( ). s u b m it( ) vraa generiki objekat Future<?> s nespeficiranim param etrom ,
zato to za taj objekat nikada n'eete zvati g e t( ) - svrha posedovanja ovakvog objekta tipa
Future jeste da za njega m oete pozvati cancel( ) i tako ga upotrebiti za prekidanje
odreenog zadatka. Ukoliko m etodi cancel( ) prosledite true, ona im a dozvolu da pozove
in te rru p t( ) za tu nit da bi je prekinula; dakle, m etoda cancel( ) predstavlja jedan od nai-
na prekidanja niti koju je pokrenuo izvrilac.
U narednom prim eru videete osnove upotrebe m etode in te rru p t( ) u izvriocu:
//: paralelno/Prekidam.java
// Prekidam blokirane niti.
import java.util.concurrent.*;
import java.io.*;
import static net.mindview.util.Print.*;
//: paralelno/ZatvoriResurs.java
// Prekidam blokirani zadatak zatvaranjem pripadnog resursa.
// {RunByHand}
import java.net.*;
import java.util.concurrent.*;
import java.io.*;
import static net.mindview.uti1.Print.*;
1 Neka izdanja JDK podravaju i In te rru p tc d IO E x c e p tio n . M e u tim , taj izuzetak je te k d e lim i n o rea-
lizovan, i to sanio na nekim platform am a. Bacanje tog izuzetka p ro u zro k u je da U /I o bjekat postane
neupotrebljiv. M alo je Verovatno da e bu d u a izdanja podravati taj izuzetak.
950 Misliti na Javi
exec.execute(new BlokiranoUIOperacijom(System.in));
TimeUni t.MILLISECONDS.sleep(lOO);
print("Gasim sve niti");
exec.shutdownNow();
TimeUnit.SECONDS.sleep(l);
printC'Zatvaram " + ul azIzUticnice.getClass() . g e t N a m e O ) ;
ulazIzUticnice.close(); // Oslobaa blokiranu nit
TimeUnit.SECONDS.sleep(l);
print("Zatvaram " + System.in.getClass().getName());
System.in.close(); // Oslobaa blokiranu nit
}
} /* Ispis: (85% podudaranja)
ekamo na read():
ekamo na read():
Gasim sve niti
Zatvaram java.net.SocketlnputStream
Prekinuto iz blokirane U/I operacije
Izlazim iz niti BlokiranoUIOperacijom.run()
Zatvaram java.io.BufferedlnputStream
Izlazim iz niti B1okiranoUIOperacijom.run()
* ///:-
//: paralelno/NIOPrekid.java
// Prekidam blokiran NIO kanal.
import java.net.*;
import java.nio.*;
import java.nio.channels.*;
import java.uti1 .concurrent.*;
import java.io.*;
import static net.mindview.util.Print.*;
} catch(IOException e) {
throw new RuntimeException(e);
}
print(''Izlazim iz niti NIOBlokiran.run() " + this);
}
}
//: paralelno/VisePutaZakljucanaBrava.java
// Nit moe vie puta da zakljua istu bravu.
import static net.mindview.util.Print.*;
pozivu m etode f 2 ( ) itd. To im a smisla zato to bi zadatak trebalo da moe da poziva sin-
hronizovane m etode u n u tar istog objekta; taj zadatak je ve zakljuao objekat (bravu).
Kao to je ve bilo reeno za ulazno/izlazne operacije koje nije mogue prekinuti, kad
god zadatak m oe biti tako blokiran da ga se ne m oe prekinuti, postoji m ogunost da e
to zakljuati ceo program . U biblioteke za paralelno izvravanje Jave SE5 dodata je i m o-
gunost prekidanja zadataka blokiranih na bravam a (objektim a) tipa R eentrantL ock, za
razliku od zadataka blokiranih na sinhronizovanim m etodam a ili kritinim delovima:
//: paralelno/Prekidam2.java
// Prekidam zadatak blokiran pomou objekta tipa ReentrantLock.
import java.uti1 .concurrent.*;
import java.util.concurrent.locks.*;
import static net.mindview.util.Print.*;
class BlokiranMutex {
private Lock brava = new ReentrantLock();
public BlokiranMutex() {
// Odmah emo ga zakljuati, da bismo pokazali prekidanje
// zadatka blokiranog na bravi Re en tr an tL oc k:
br av a.1o c k ( ) ;
}
public void f() {
try {
// Drugim zadacima ovo nikada nee biti dostupno
b r av a.1o c k l n t e r r u p t i b l y (); // Poseban poziv
print("zakljuana brava u f ()");
} catch(InterruptedException e) {
p r i n t ("Prekinuto u pokuaju zakljuavanja brave u f ()");
}
}
}
} /* Ispis:
ekamo na f() u klasi BlokiranMutex
Pozivam n.interrupt()
Prekinuto u pokuaju zakljuavanja brave u f()
Izaao iz blokiranog poziva
* ///-
Klasa BlokiranMutex im a k onstruktor koji zakljua bravu (objekat tipa Lock) samog
objekta i nikada je ne otkljua. Zbog toga ete, ukoliko pokuate da pozovete f ( ) iz nekog
drugog zadatka (razliitog od onoga koji je napravio objekat BlokiranMutex), uvek biti
blokirani poto je ta uzajam no iskljuiva brava stalno zakljuana. U klasi Blokirana2,
m etodu r u n ( ) zaustavie poziv m etode b lo k irana.f( ). Kada pokrenete program , videete
da, za razliku od poziva ulazno/izlaznih operacija, in te rru p t( ) m oe da izae iz poziva
koji je blokirala uzajamno iskljuiva brava (m u tex ).'9
//: paralelno/IdiomPrekidanja.java
// Opti idiom za prekidanje zadatka.
// {Args: 1100}
import java.util.concurrent.*;
import static net.mindview.util.Print.*;
class TrebaPocistiti {
private final int id;
|g lako je to m a!o verovatno, im ajte u vidu da bi se poziv m eto d e t . i n t e r r u p t ( ) zapravo m ogao desiti
p re poziva m eto de b lo k ira n a .f( ).
Poglavlje 21: Paralelno izvravanje 955
Kada je taj problem reen, sledei korak je nauiti kako da zadaci sarauju jedan s dru-
gim, da bi vie zadataka m oglo zajedniki da rei problem . Sada se ne postavlja pitanje
kako da se zadaci m edusobno ne om etaju, nego kako da rade usaglaeno, poto se takvi
p roblem i m oraju reavati postepeno, utvrenim redosledom . Kao u graevinarstvu: naj-
pre se m o ra iskopati rupa za temelje, ali se arm atura m oe poloiti paralelno sa pra-
vljenjem betonskih blokova, i oba ta zadatka m oraju biti dovrena da bi se nalili temelji.
Cevi m oraju biti poloene pre nalivanja betonske ploe, ploa m ora biti nalivena pre nego
to pone podizanje zidova itd. Neki od ovih zadataka m ogu se izvravati paralelno, ali
odreeni koraci ne m ogu se izvesti ukoliko svi zadaci nisu zavreni.
U m eusobnoj saradnji zadataka glavno pitanje je prim opredaja signala. Za tu p rim o-
predaju upotrebljavam o zajedniki temelj: uzajam no iskljuivu bravu (m utex) koji u
ovom sluaju jem i da e na odreeni signal odgovoriti sam o jedan zadatak. Tim e se iz-
begavaju svi eventualni uslovi za trku. Pored mutexa, dodaem o nain da se zadatak zau-
stavi do k se ne prom eni neko spoljno stanje (npr. Cevi su poloene), koje pokazuje da
je vrem e da se taj zadatak pokrene. U ovom odeljku, razm otriem o prim opredaju signala
izm eu zadataka, koju bezbedno realizuju m etode w a it( ) i notifyA ll( ) klase Object. Bi-
blioteka za paralelno izvravanje Jave SE5 ima i klasu Condition, s m etodam a aw ait( ) i
s ig n a l(). Videemo koji problem i m ogu nastati i kako se reavaju.
wait() i notifyAII()
M etoda w a it( ) se obino koristi dok ekate na prom enu uslova ije ispunjenje odreuju
sile kojim a ne upravlja tekua m etoda. Cesto neki drugi zadatak m enja taj uslov. Ne elite
da program stoji besposleno u niti, stalno ispitujui taj uslov; to se naziva zauzetost e-
kanjem (engl. busy vvaiting) i obino prestavlja lo nain korienja procesorskog vrem e-
na. Stoga w a it( ) om oguava da uspavate tu nit dok eka da se svet prom eni. O na se budi
i ispituje prom ene tek kad naie na m etode n o tify( ) ili notifyA ll( ) koje nagovetavaju da
se m oda desilo neto vano. Tako je dobijen jo jedan nain sinhronizacije niti.
Vano je shvatiti da ni sleep( ) niti yield( ) ne otkljuavaju objekat kada ih pozovete.
S druge strane, kada zadatak iz neke m etode pozove m etodu w a it( ), ona otkljuava obje-
kat pre nego to zaustavi izvravanje niti. Poto w a it( ) otkljuava bravu im je pozovete,
to znai da drugi zadaci mogu da pribave tu bravu, pa tokom izvravanja m etode w a it ( )
moete da pozivate druge sinhronizovane m etode tog (sada otkljuanog) objekta. To je
neophodno, poto obino ba te druge metode prouzrokuju p rom enu koju zaustavljena
nit eka da bi se probudila. Dakle, kada pozovete w a it( ), saoptavate: Zasad sam uradio
sve to sam mogao, pa u na ovom m estu da priekam , ali hou da om oguim drugim
sinhronizovanim operacijam a da se izvravaju ako mogu.
Postoje dva oblika m etode wait( ). Prvi prim a argum ent u milisekundam a, ije je
znaenje jednako onom u m etodi sle ep (), dakle zaustavlja rad u zadatom periodu vreme-
na. Za razliku od prim ene m etode sle ep (), kada se koristi w ait(pauza), deava se sledee:
1. O tkljuava se objekat tokom ekanja izvravanja m etode w a it( ).
2. Iz m etode w a it( ) moete da izaete i zbog obavetenja koje alju m etode n o tify () ili
notifyA U (), ili e se izvravanje samo nastaviti po isteku zadatog vrem ena ekanja.
958 Misliti na Javi
synchronized(x) {
x.notifyAll();
}
Razm otriem o jednostavan prim er. VoskOMatik.java ima dva procesa: nanoenje
voska na Kola i poliranje. Poliranja nem a dok se ne zavri nanoenje voska, a zadatak na-
noenja m ora da saeka dok se zadatak poliranja zavri - tek onda se moe naneti sledei
sloj voska. I Voskalma i VoskaNema rade sa istim objektom tipa Kola koji m etodam a
w a it( ) i notifyA ll( ) zaustavlja i ponovo pokree zadatke dok oni ekaju da se prom eni
odreeni uslov:
//: paralelno/voskomatik/VoskOMatik.java
// Osnove meusobne saradnje zadataka.
package paralelno.voskomatik;
import java.util.concurrent.*;
import static net.mindview.uti1 .Print.*;
class Kola {
private boolean voskalma = false;
public synchronized void voskiranoO {
voskalma = true; // Spremno za poliranje
noti fyAl1 ();
Poglavlje 2 1: Paralelno izvravanje 959
Kola im aju samo jednu prom enljivu tipa boolean pod im enom voskalm a koja po-
kazuje stanje procesa nanoenja voska i poliranja.
U m etodi cekajNaVoskiranje( ) proverava se indikator voskalm a, i ako je njegova
vrednost false, pozivajui zadatak se zaustavlja tako to se poziva m etoda w a it( ). Vano
je da se to deava u sinhronizovanoj m etodi, gde je zadatak pribavio bravu. Kada pozovete
w a it( ), nit se zaustavlja, a brava otkljuava. N eophodno je da brava bude otkljuana zato
to drugi zadaci m oraju im ati m ogunost da je pribave (zakljuaju) da bi stanje tog
objekta moglo biti bezbedno prom enjeno (na prim er, da bi vrednost indikatora voska-
Im a prom enili u true, to m oram o da uradim o da bi zaustavljeni zadatak uopte dobio
priliku da nastavi rad). U ovom prim eru, kada drugi zadatak pozove voskirano( ) da bi
pokazao kako je vreme da se neto uradi, brava m ora biti pribavljena (zakljuana) da bi
se vrednost indikatora voskalma prom enila u true. Zatini vosk iran o ( ) poziva metodu
notifyA ll( ) koja budi zadatak zaustavljen pozivom m etode w a it( ). Da bi se zadatak pro-
budio iz stanja ekanja koje prouzrokuje m etoda w a it( ), najpre m ora ponovo da zakljua
bravu koju je otkljuao kada je uao u taj w a it( ). Zadatak se nee probuditi dok ta brava
ne postane dostupna, tj. otkljuana.20
20 Na nckim platfo rm am a postoji i trei nain izlaska iz m etode w a it(): to je takozvano shiajno
budetije. U sutini, sluajno b u en je p ro u zro k u je nit koja p rera n o prestane da blokira (dok eka na
prom enljivu ili sem afor uslova), a da je nisu pro b u d ile m etode notify( ) ili n otifyA ll() (ili njihovi
ekvivalenti za objekte nove klase Condition). N it se jednostavno p ro b u d i, naizgled sam a od sebe.
Sluajno b u en je postoji zato to realizacija PO SlX niti (ili njinia ekvivalentnih) na nekim plat-
fo rm am a nije onoliko jednostavna koliko bi Sun hteo da bude. No, posao pisanja p th read biblioteke
za te p latfo rm e m n o go je laki ako se proglasi da sluajna bu denja ,,ne sm etaju toliko.
Poglavlje 21: Paralelno izvravanje 961
Proputeni signali
Kada je rad dve niti usklaen m etodam a notify( )/w a it() ili notifyAH( )/w a it(), moe se
propustiti signal. Pretpostavim o da je N1 nit koja obavetava nit N2 i da su obe realizo-
vane na sledei (pogrean) nain:
962 Misliti na Javi
N1 :
synchronized(deljeniMoni tor) {
<pripremo u slo v a za N2>
deljeniMonitor.notify();
}
N2:
while(nekillslov) {
// Taka 1
synchronized(deljeniMonitor) {
deljeniMonitor.wait();
}
}
<priprema uslova za N2> treba da sprei N2 da zove w a it(), ako to N2 ve nije uinila.
Pretpostavim o da N2 izrauna nekiUsIov i dobije rezultat true. U Takil, m ehanizam
za raspodelu procesorskog vrem ena moe prebaciti na nit N l. N1 izvrava svoju pripre-
m u i zatim poziva n o tify (). Kada N2 nastavi da se izvrava, za nju je prekasno da shvati
kako se uslov u m euvrem enu prom enio, i ona slepo ulazi u w a it(). Poruka m etode
n o tify () bie proputena i N2 e ekati beskonano dugo na signal koji je ve bio poslat;
dobili sm o uzajam nu blokadu (engl. deadlock).
Reenje je da se sprei uslov za trku prim en om prom enljive nekiUslov. Ovo je ispra-
van nain realizacije N2:
synchronized(deljeniMonitor) {
while(nekiUslov)
deljeniMonitor.wait();
}
U ovoj realizaciji vai sledee: ako nit N1 prva dobije priliku da se izvrava, kada se
kontrola vrati niti N2 ona e shvatiti da se uslov prom enio i nee ui u w a it(). U protiv-
nom , ukoliko nit N2 prva dobije priliku da se izvrava, ui e u w a it() i kasnije e je pro-
buditi N l. Dakle, signal ne moe biti proputen.
class Blokator {
synchronized void cekatnPoziv() {
try {
while(!Thread.interrupted()) {
wait();
System.out.print(Thread.currentThread() + " ");
}
} catch(InterruptedException e) {
// Ovo je prihvatljiv nain izlaska
}
}
synchronized void probudi() { notify(); }
synchronized void probudiSve() { notifyAll(); }
}
} else {
System.out.print("\nnotifyAl 1() ");
Zadatak.blokator.probudiSve();
probudi = true;
}
}
}, 400, 400); // Pokreni na svake 0,4 sekunde
Timellnit.SEC0NDS.sleep(5); // Neka radi neko vreme...
meracVremena.cancel();
System.out.println("\nMera vremena otkazan");
TimeUni t .MILLISECONDS.sleep(500);
System.out.print("Zadatak2.blokator.probudiSve() ");
Zadatak2.blokator.probudiSve();
TimeUnit.MILLISEC0NDS.sleep(500);
System.out.println("\nGasim");
exec.shutdownNow(); // Prekini sve zadatke
}
} /* Ispis: (primer)
notify() Thread[pool-l-thread-l,5,main]
notifyAl1() Thread[pool-l-thread-l,5,main] Thread[pool-l-thread-5,5,main]
Thread[pool-l-thread-4,5,main] Thread[pool-l-thread-3,5,main] Thread[pool
-l-thread-2,5,main]
notify() Thread[pool-l-thread-l,5,main]
notifyAl1() Thread[pool-1-thread-l,5,main] Thread[pool-l-thread-2,5,main]
Thread[pool-l-thread-3,5,main] Thread[pool-l-thread-4,5,main] Thread[pool
-l-thread-5,5,main]
notify() Thread[pool-1-thread-l,5,main]
notifyAl1 () Thread[pool-1-thread-l,5,main] Thread[pool-l-thread-5,5,main]
Thread[pool-l-thread-4,5,main] Thread[pool-l-thread-3,5,main] Thread[pool
-l-thread-2,5,main]
notify() Thread[pool-l-thread-l,5,main]
notifyAl1 () Thread[pool-l-thread-l,5,main] Thread[pool-l-thread-2,5,main]
Thread[pool-l-thread-3,5,main] Thread[pool-l-thread-4,5,main] Thread[pool
-l-thread-5,5,main]
notify() Thread[pool-1-thread-l,5 ,main]
notifyAll() Thread[pool-1-thread-l,5,main] Thread[pool-l-thread-5,5,main]
Thread[pool-l-thread-4,5,main] Thread[pool-l-thread-3,5,main] Thread[pool
-l-thread-2,5,main]
notify() Thread[pool-1-thread-l,5,main]
notifyAl1 () Thread[pool-1-thread-1,5,main] Thread[pool-l-thread-2,5,main]
Thread[pool-l-thread-3,5,main] Thread[pool-l-thread-4,5,main] Thread[pool
-l-thread-5,5,main]
Mera vremena otkazan
Zadatak2.blokator.probudiSve() Thread[pool-l-thread-6,5,main]
Gasim
*///:-
Zadatak i Zadatak2 imaju sopstvene Blokator objekte, pa svaki objekat tipa Zada-
tak.blokator blokira svaki objekat tipa Zadatak, i svaki objekat tipa Zadatak2.blokator
blokira svaki objekat tipa Zadatak2 . U m etodi m a in (), objekat tipa java.util.Timer biva
Poglavlje 21: Paralelno izvravanje 965
Proizvoai i potroai
Zam islite restoran s jednim kuvarom i jednim konobarom . Konobar m ora da saeka dok
kuvar prip rem i jelo. Kuvar obavetava konobara kada je jeio zgotovljeno. Tada konobar
uzim a jelo, posluuje ga pa se vraa i eka. To je prim er saradnje zadataka: kuvar predsta-
vlja proizvoaa, a konobar potroaa. Zadaci m oraju da razm enjuju signale tokom
proizvodnje i potronje jela, i sistem m ora da se uredno ugasi. Ovo je ta pria oblikovana
kao kod:
//: paralelno/Restoran.java
// Saradnja zadataka kao saradnja proizvoaa i potroaa.
import java.util.concurrent.*;
import static net.mindview.util .Print.*;
class Jelo {
private final int brojNarudzbe;
public Jelo(int brojNarudzbe) { this.brojNarudzbe = brojNarudzbe; }
public String toStringf) { return "Jelo " + brojNarudzbe; }
}
whi1e(uslovNijelspunjen)
wai t();
968 Misliti na Javi
Time se jem i da e uslov biti ispunjen pre nego to izaete iz petlje ekanja, i ako ste
obaveteni o neem u to nem a veze sa uslovom - to se m oe desiti kada je poruka
n o tifyA ll() - ili se uslov pro m eni pre nego to p o tp u n o izaete iz petlje ekanja, svakako
ete se vratiti u ekanje.
Vodite rauna o tom e da poziv n o tify A ll() m ora najpre zakljuati bravu konobara.
Poziv m etode w a it() iz m etode K onobar.run() autom atski otkJjuava bravu, pa je to
mogue. Poto brava m ora biti zakljuana da bi n o tify A ll() m ogla biti pozvana, dva
zadatka koji pokuavaju da pozovu n o tify A ll() za isti objekat zajemeno nee zasmetati
jedan drugom .
O be m etode r u n () uredno se gase tako to je cela m etoda r u n () u m etnuta u blok try.
O dredba catch zavrava se neposredno pre zavrne vitiaste zagrade m etode r u n (), pa
ako zadatak prim i InterruptedException, zavrie se o dm ah im uhvati izuzetak.
U klasi Kuvar, obratite panju na to da bism o nakon poziva m etode sh utdow n N ow ()
obinom naredbom return mogli da se jednostavno vratim o iz m etode r u n ( ), i to
najee i treba da uradite. M eutim , ovako je m alo zanimljivije. Prisetite se da
sh utdow n N ow () alje in terru p t() svim zad a m a koje je ExecutorService pokrenuo. Ali
u sluaju klase Kuvar, zadatak se ne gasi neposredno po prijem u poruke in terru p tf),
poto prekid m oe da generie izuzetak InterruptedException jedino kada zadatak
pokua da ue u (neprekidnu) operaciju koja blokira. Zato se najpre prikazuje Evo
narudzbe! i zatim baca izuzetak InterruptedException kada Kuvar pokua da pozove
sle e p (). Ako uklonite poziv m etode sle e p (), zadatak e doi na vrh petlje r u n () i izai
zbog ispitivanja vrednosti m etode Thread.interrupted(), a da ne baci izuzetak.
U p retho dn om prim eru, zadatak na sam o jedno m esto m oe da smesti objekat koji e
drugi zadatak kasnije upotrebiti. M eutim , u tipinoj realizaciji proizvodaa i potroaa,
za skladitenje objekata koji se proizvode i troe prim enjuje se princip FIFO (fir$t-inyfirst-
out prvi izlazi onaj koji je prvi uao). Vie rei o takvim redovim a za ekanje bie u na-
stavku poglavlja.
Veba 24: (1) M etodam a w a it() i n o tify A ll() reite problem jednog proizvoaa i jed-
nog potroaa. Proizvoa ne sme da prepuni prim aoev bafer, to se moe desiti ukoliko
je proizvoa bri od potroaa. Ako je potroa bri od proizvoaa, onda isti podatak
treba da proita samo jednom . Ne sm ete nita pretpostaviti o relativnim brzinam a
proizvoaa i potroaa.
Veba 25: (1) U klasi Kuvar program a Restoran.java, vratite se naredbom return iz me-
tode r u n () nakon poziva m etode sh u td ow n N o w () i posm atrajte razliku u ponaanju.
Veba 26: (8) Program u Restoran.java dodajte klasu Pom ocnik. Kada poslui jelo, Ko-
nobar treba da obavesti P om ocnika da poisti.
Zadatak zaustavljate pozivom m etode a w ait() za objekat tipa Condition. Kada nastanu
spoljne prom ene stanja koje m oda znae da neki zadatak treba da nastavi izvravanje, taj
zadatak obavetavate poru ko m sig n a l(), odnosno sign alA ll() da biste probudili sve
zadatke koji su se zaustavili do ispunjenja uslova tj. tog objekta C ondition (kao i
notifyA Il(), sign alA ll() je bezbednije koristiti).
Evo kako izgleda program VoskOMatik.java preraden tako da sadri C ondition po-
m ou kojeg se odreeni zadatak zaustavlja u n u ta r m etoda cekajNaVoskiranje() ili
cekajN aPoliranje():
//: paralelno/voskomatik2/VoskOMatik2.java
// Upotreba objekata Lock i Condition.
package paralelno.voskomatik2;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import static net.mindview.util.Print.*;
class Kola {
private Lock brava = new ReentrantLock();
private Condition uslov = brava.newCondition();
private boolean voskalma = false;
public void voskirano() {
brava.lockO ;
try {
voskalma = true; // Spremna za poliranje
usl o v .signalAll ();
} finally {
b r ava . u n l o c k O ;
}
}
public void polirano() {
brava.1ock();
try {
voskalma = false; // Spremna za nanoenje sledeeg sloja voska
uslov.signalA11 ();
} fi nal 1y {
brava.unlock();
U ko nstruktoru Kola, jedna brava (objekat tipa Lock) proizvodi uslov, tj. objekat tipa
C ondition pom ou kojeg se upravlja kom unikacijom izm eu zadataka. M eutim , obje-
kat C ondition ne sadri inform acije o stanju procesa, pa su potrebne dodatne inform a-
cije kojim a pokazujete stanje procesa, a to je prom enljiva voskalm a tipa boolean.
Iza svakog poziva m etode lo c k () m ora neposredno slediti odredba try-finally koja
jem i da e se u svim sluajevima ostvariti otkljuavanje. Kao u ugraenim verzijama,
zaatak m ora zakljuati bravu da bi mogao da pozove a w a it(), sig n a l() ili sig n a lA ll().
Im ajte u vidu da je ovo reenje sloenije nego prethodno, a ta sloenost u ovom sluaju
nije donela nita dobro. Objekti tipa Lock i Condition potrebni su sam o za tee problem e
vienitnog izvravanja.
Veba 27: (2) Izmenite Restoran.java tako da korisli eksplicitne objekte tipa Lock i
Condition.
//: paralelno/TestBlokirajucihRedovaZaCekanje.java
// {RunByHand}
import java.util.concurrent.*;
import java.io.*;
import static net.mindview.util.Print.*;
static void
test(String prk, BlockingQueue<Lansiranje> redZaCekanje) {
print(prk);
IzvrsavaLansiranje izvrsilac = new IzvrsavaLansiranje(redZaCekanje);
Thread n = new Thread(izvrsilac);
n.start();
for(int i = 0 ; i < 5 ; i++)
izvrsilac.add(new Lansiranje(5));
getkey("Pritisnite 'Enter' (" + prk + ")");
n.i nterrupt();
print("Zavren " + prk + " test");
}
public static void main(String[] args) {
test("LinkedBlockingQueue", // Neograniena veliina
new LinkedBlockingQueue<Lansiranje>());
test("ArrayBlockingQueue", // Nepromenljiva veliina
new ArrayBlocking0ueue<Lansiranje>(3));
test("SynchronousQueue", // Veliine 1
new SynchronousQueue<Lansiranje>());
}
} ///:-
M etoda m a in () smeta zadatke u BlockingQueue, iz kojeg ih vadi m etoda Izvr-
savaLansiranje. O bratite panju na to da IzvrsavaLansiranje moe da zaboravi na
sinhronizaciju zato to to reava BlockingQueue.
Veba 28: (3) Izmenite TestBlokirajucihRedovaZaCekanje.java dodavanjem novog
zadatka koji stavlja Lansiranje u BlockingQueue, um esto da se to radi u m etodi m a in ().
//: paralelno/TostOMatik.java
// Toster koji upotrebljava redove za ekanje.
import java.util.concurrent.*;
import java.uti1 .*;
import static net.mindview.uti1 .Print.*;
class Tost {
public enum Status { SUV, SMASLACEM, SPEKMEZOM }
private Status status = Status.SUV;
private final int id;
public Tost(int idn) { id = idn; }
public void namaziMaslacem() { status = Status.SMASLACEM; }
public void namaziPekmezom() { status = Status.SPEKMEZOM; }
public Status dajStatus() { return status; }
974 Misliti na Javi
print("MazeMaslacem iskljuen");
}
}
// Potroi tost:
class Gost implements Runnable {
private RedZaCekanjeTosta redGotovih;
private int brojac = 0;
public Gost(RedZaCekanjeTosta gotovi) {
redGotovih = gotovi;
}
public void run() {
try {
while(!Thread.interrupted()) {
// Blokira se dok ne dobije sledee pare tosta:
Tost n = redGotovih.take();
// Proveri da li tost uredno dolazi,
// i da li sva parad bivaju namazana pekmezom:
if(n.dajld() != brojac++ ||
n.dajStatus() != Tost.Status.SPEKMEZOM) {
p r i n t ( " Greka: " + n);
System.exit(l);
} else
print("Njam! " + n);
}
} catch(InterruptedException e) {
976 Misliti na Javi
print("Gost prekinut");
}
print("Gost iskljuen");
}
}
Tost je odlian prim er vrednosti nabrojanih tipova. Vodite rauna o tom e da nema
eksplicitne sinhronizacije (ne upotrebljavaju se objekti tipa Lock niti rezervisana re syn-
chronized), poto sinhronizaciju im plicitno (interno) obavljaju redovi za ekanje i
projekat sistema - svako pare Tosta u svakom trenutku predm et je obrade sam o jednog
zadatka. Poto redovi za ekanje blokiraju izvravanje, procesi se zaustavljaju i nastavljaju
autom atski. N adam se da vidite kako pojednostavljenje koje su doneli blokirajui redovi
za ekanje um e da bude veom a veliko. Izbegnute su veze izm eu klasa koje bi postojale uz
eksplicitne naredbe w a it() i n o tifyA ll(), jer svaka klasa kom unicira samo sa svojim blo-
kirajuim redom za ekanje.
Veba 29; (8) Izmenite TostOMatik.java tako da na dve zasebne linije pravi sendvie od
tosta nam azanog maslacem i m arm eladom (jedna za tost nam azan maslacem, druga za
m arm eladu, zatim spojite linije).
//: paralelno/UICevovod.java
// Ulazno/izlazna komunikacija zadataka kroz cevi
import java.util.concurrent.*;
Poglavlje 21: Paralelno izvravanje 977
import java.io.*;
import java.util.*;
import static net.mindview.util.Print.*;
Uzajamna blokada
Sada znate da objekat moe im ati sinhronizovane m etode ili druge oblike zakljuavanja
koji spreavaju zadatke da pristupaju tom objektu dok se ne otkijua uzajam no iskljuiva
brava (mutex). Saznali ste i da zadaci m ogu postati blokirani. Dakle, m ogue je da se je-
dan zadatak zaglavi ekajui na drugi, koji eka na trei it., dok lanac ne oe do zadatka
koji eka na onaj prvi zadatak - neprekidan lanac zadataka koji ekaju jedan na drugog i
nijedan od njih ne moe da se pom eri. To se naziva uzajamna blokada (engl. deadlock).1'
Ako pokrenete program i on odm ah ue u uzajam nu blokadu, greku ete odm ah
moi da pronaete. Pravi problem je kada program naizgled radi dobro, ali sadri skrive-
nu m ogunost uzajam ne blokade. U tom sluaju, uopte ne m orate dobiti nikakvu na-
znaku da m ogunost uzajam ne blokade postoji, pa e greka biti latentna u program u
dok se neoekivano ne desi kupcu (na nain koji e gotovo sigurno biti teko ponoviti).
Zato je paljivo projektovanje program a kako bi se spreila uzajam na blokada, kljuan
deo razvoja paralelnih sistema.
Klasian prim er uzajam ne blokade jeste problem veercfilozofa, koji je smislio Edsger
Dijkstra. U njegovoj verziji, filozofa im a pet, ali u prim eru koji u ja ovde opisati, broj fi-
Iozofa je proizvoljan. Ti filozofi deo vrem ena provode u razm iljanju, a deo u jelu. Dok
razmiljaju, ne koriste deljene resurse, ali za jelo imaju na raspolaganju ogranienu
//: paralelno/Stapic.java
// tapii za veeru filozofa.
//: paralelno/Fi1ozof.java
// Filozof veera
import java.util.concurrent.*;
import java.uti1 .*;
import static net.mindview.uti 1 .Print.*;
//: paralelno/UzajamnoBlokiraniFilozofiKojiVeceraju.java
// Pokazuje kako u programu moe biti prikrivena uzajamna blokada.
// {Args: 0 5 odmor}
import java.util .concurrent.*;
Poglavfje 2 1: Paralelno izvravanje 981
Prim etili ste sledee: ukoliko Filozofi provode malo vrem ena razmiljajui, kada po-
kuaju da jedu svi e jedan drugom konkurisati za Stapice i uzajam na blokada e nastu-
piti m nogo bre.
Prvi argum ent na kom andnoj liniji zadaje teinski faktor ponder koji utie na koliinu
vrem ena koje svaki Filozof provodi u razmiljanju. Ako Filozofa im a m nogo ili oni vaz-
dan razmiljaju, m oda uopte neete videti uzajam nu blokadu, iako je ona i dalje m o-
gua. N ula kao argum ent na kom andnoj liniji ini da program prilino brzo ue u
uzajam nu blokadu.
O bratite panju na to da objektim a tipa Stapic nisu potrebni interni identifikatori;
njih identifikuje njihov poloaj u nizu stapici. K onstruktor svakog objekta tipa Filozof
dobija referencu na levi i desni Stapic. Svaki Filozof (sem poslednjeg) u inicijalizaciji biva
smeten izm edu sledeeg para Stapica. Poslednji Filozof dobija nulti Stapic kao svoj de-
sni i tako se obiao krug oko stola - naime, poslednji Filozof sedi odm ah do prvog i obo-
jica dele nulti Stapic. Ukoliko sada svi Filozofi istovrem eno pokuaju da jedu, svaki od
njih e m orati da eka dok susedni Filozof ne spusti svoj Stapic. Program e zato ui u
uzajam nu blokadu.
Ukoliko Filozofi vie vrem ena provode u razmiljanju nego u jelu, onda je i verovat-
noa da e im zatrebati deljeni resursi (Stapici) m nogo m anja, i vi ete biti uvereni da pro-
gram ne m oe ui u uzajam nu blokadu (ako za ponder zadate vrednost razliitu od nule
ili veliki broj Filozofa), iako to nije istina. Ovaj prim er je zanimljiv upravo zato to pokazu-
je da program moe naizgled da radi ispravno, a da u stvari krije uzajam nu blokadu.
982 Misliti na Javi
//: paralelno/PopravljeniFi1ozofiKojiVeceraju.java
// Filozofi koji veeraju bez uzajamne blokade.
// {Args: 5 5 odmor}
import java.util.concurrent
U zajam nu blokadu sm o uklonili tako to poslednji Filozof sada uzima i puta levi Sta-
pic pre desnog, i program e raditi dobro.
Java nem a podrku za spreavanje uzajam ne blokade; m orate je sami izbei tako to
ete paljivije projektovati program . To nisu utene rei za onoga ko pokuava da otkrije
i otkloni greku iz program a koji upada u uzajam nu blokadu.
Veba 31: (8) Izmenite program UzajamnoBiokiraniFilozofiKojiVeceraju.java na sle-
dei nain: kada filozof upotrebi tapie, neka ih ne sputa na sto nego u zdelu. Kada fi-
lozof hoe da jede, uzim a prva dva dostupna tapia iz te zdele. Da li je tim e izbegnuta
m ogunost uzajam ne blokade? Da li ete prostim sm anjenjem broja dostupnih tapia
ponovo uvesti m ogunost uzajam ne blokade?
to odbrojavanje se obino radi kada zadatak obavi svoj posao. CountDownLatch se ko-
risti jednokratno; vrednost se ne m oe resetovati. Kada vam zatreba verzija koja resetuje
vrednost, upotrebite CyclicBarrier.
Zadaci koji pozovu co u n tD o w n () ne blokiraju se zbog tog poziva. Blokiran je sam o
poziv m etode aw ait() dok se vrednost ne izjednai s nulom .
Ova klasa se obino koristi tako to se problem podeli na n nezavisno reivih zadataka
i napravi objekat tipa CountDownLatch kojem se dodeli poetna vrednost n. Svaki
zavren zadatak poziva co u n tD o w n () za taj objekat. Zadaci koji ekaju da se problem rei
pozivaju a w ait() za taj objekat, da bi saekali dok problem bude reen. Tu tehniku prika-
zuje sledei prim er:
// eka na CountDownLatch:
class ZadatakKojiCeka implements Runnable {
private static int brojac = 0;
private final int id = brojac++;
private final CountDownLatch brava;
ZadatakKojiCeka(CountDownLatch brava) {
this.brava = brava;
Poglavjje 21: Paralelno izvravanje 985
}
public void run() {
try {
brava.await();
print(this + " proao barijeru brave");
} catch(InterruptedException izz) {
print(this + " prekinut");
}
}
public String toStringO {
return String.format("ZadatakKojiCeka %l$-3d ", id);
}
}
DeoZadatka spava tokom nasum ino odabranog vrem enskog razdoblja i tako sim u-
lira izvravanje dela zadatka, a ZadatakKojiCeka predstavlja deo sistema koji m ora da
saeka dok se prvi deo problem a ne rei. Svi zadaci rade sa istim objektom tipa Count-
DownLatch definisanim u m etodi m a in ().
Veba 32: (7) Upotrebite CountDownLatch za korelaciju rezultata raznih Ulaza u pri-
m eru UkrasnaBasta.java. Iz nove verzije prim era uklonite nepotreban kod.
CyclicBarrier
Klasu CyclicBarrier koristite u situacijam a kada hoete da napravite gru p u zadataka koji
se izvravaju paralelno, a zatim da saekate dok se svi oni ne zavre pre nego to preete
na sledei korak (neto kao j o in ( ), recim o). Prilikom prolaska kroz barijeru svi paralelni
zadaci su zavreni, pa napred m oete da krenete sa rezultatim a svih njih. To je veom a sli-
no klasi CountDownLatch, sem to je objekat tipa CountDownLatch za jed n o k ratn u
upotrebu, dok se objekat tipa CyclicBarrier moe koristiti vie puta.
Simulacije m e fasciniraju od prvih susreta s raunarom , a paralelno izvravanje je
kljuni faktor koji om oguuje simulacije. Prvi program koji sam napisao22 bila je sim ula-
cija: igra s konjskim trakam a napisana u BASIC-u, nazvana (zbog ograniene duine
im ena datoteka) HOSRAC.BAS. Sledi objektno orijentisana, vienitna verzija tog progra-
ma, u kojoj je upotrebljena klasa CyclicBarrier:
//: paralelno/TrkaKonja.java
// Upotreba klase CyclicBarrier.
import java.util.concurrent.*;
import java.util.*;
import static net.mindview.util.Print.*;
O bjektu tipa CyclicBarrier m oe biti pri od ata akcija barijere", a to je klasa koja rea-
lizuje interfejs Runnable i izvrava se autom atski kada se (na poetku zadat) broj izjed-
nai s nulom - to je druga razlika izm eu klasa CyclicBarrier i CountdownLatch. Ovde
je akcija barijere anonim na klasa koja se daje k o nstru k to ru objekta tipa CyclicBarrier.
Probao sam da postignem da svaki konj odtam pa kada je stigao na cilj, ali se u tom
sluaju redosled prikazivanja m enja u zavisnosti od m ehanizm a za raspodelu procesor-
skog vrem ena nitim a (zadacim a). Klasa CydicBarrier om oguuje svakom konju da radi
sve to treba kako bi doao do cilja, a zatim m ora da eka na barijeri dok ne dou svi ostali
konji. Kada svi konji stignu, objekat tipa CyclicBarrier autom atski poziva svoju akciju
barijere, tj. zadatak koji realizuje interfejs Runnable i prikazuje konje redom kojim su
stigli, kao i ogradu trkalita.
Kada svi zadaci pro u barijeru, ona je autom atski sprem na za sledeu rundu.
Ako elite da postignete efekat veom a jednostavne animacije, sm anjite prozor konzole
tako da se vide sam o konji.
De!ayQueue
Ovo je neogranien BlockingQ ueue (blokirajui red za ekanje) objekata koji realizuju
interfejs Delayed, tj. svaki je odloen na neko vreme (engl. delayed). O bjekat moe biti
uzet iz reda za ekanje tek kada njegovo vrem e odlaganja istekne. Red je tako ureen da
je eonom objektu preostalo vrem e odlaganja koje se najvie skratilo od poetka izvra-
vanja. Ako se nijedno vrem e odlaganja nije skratilo, onda nem a eonog elem enta i meto-
da p o ll( ) vraa null (zato u taj red za ekanje ne m oete stavljati null elemente).
U sledeem prim eru D elayed objekti su i sami zadaci, a P otrosacO dlozenihZ adataka
iz rada za ekanje uzim a najhitniji zadatak (onaj kojem se vreme odlaganja najvie skra-
tilo od poetka izvravanja) i izvrava ga. Dakle, D elayQ ueue je varijacija prioritetnog
reda za ekanje.
//: paralelno/DelayQueuePrimer.java
import java.util.concurrent.*;
import java.uti1 .*;
import static java.util.concurrent.TimeUnit.*;
import static net.mindview.util.Print.*;
new ArrayList<OdlozeniZadatak>();
public OdlozeniZadatak(int odlaganjeUMilisekundama) {
delta = odlaganjeUMilisekundama;
okidac = System.nanoTime() +
NANOSECONDS.convert(delta, MILLISECONDS);
sekvenca.add(this);
}
public long getDelay(TimeUnit jedinica) {
return jedinica.convert(
okidac - System.nanoTime(), NANOSECONDS);
}
public int compareTo(Delayed arg) {
OdlozeniZadatak onaj = (OdlozeniZadatak)arg;
if(okidac < onaj.okidac) return -1;
if(okiac > onaj.okidac) return 1;
return 0;
}
public void run() { printnb(this + " "); }
public String toString() {
return St ri ng .f or ma t("[%l$-4d]", delta) +
" Zadatak " + id;
}
public String sazetak() {
return "(" + id + + delta + ")";
}
public static class StrazarNaCilju extends OdlozeniZadatak {
private ExecutorService exec;
public StrazarNaCilju(int odlaganje, ExecutorService e) {
su pe r( od la ga nj e);
exec = e;
}
public void run() {
for(OdlozeniZadatak iz : sekvenca) {
p r i n t n b ( i z .s a z e t a k O + " ");
}
pri nt ();
print(this + " poziva shutdo wn No w( )");
ex e c . s h u td ow nN ow ();
}
NAN0SEC0NDS.convert(delta, MILLISECONDS);
U metodi getD elay(), eljena jedinica se prosleduje kao argum ent jedinica i pom ou
nje vreme proteklo od okidaa konvertujem o u jedinice koje zahteva pozivalac, a da ak i
ne znam o koje su. (Ovo je jednostavan prim er projektnog obrasca Strategy, u kojem se
deo algoritm a prosleuje kao argum ent.)
Poglavlje 21: Paralelno izvravanje 991
PriorityBlockingQueue
U sutini, ovo je p rio ritetn i red za ekanje ije se operacije vaenja iz reda blokiraju. U na-
rednom prim eru, objekti u prioritetn o m redu za ekanje su zadaci koji se iz reda za e-
kanje pojavljuju po redosledu njihovih prioriteta. ZadatakSPrioritetom dobija broj
prioriteta iz kojeg sledi taj redosled:
//: paralelno/PriorityBlockingQueuePrimer.java
import java.uti1.concurrent.*;
import java.uti 1 .*;
import static net. mi nd vi ew .u ti1.P r i n t .*;
class Za da ta kS Pr io ri te to m implements
Runnable, Co mp ar ab le <ZadatakSPrioritetom> (
private Random slucajan = new Random(47);
private static int brojac = 0;
private final int id = brojac++;
private final int prioritet;
protected static List<ZadatakSPrioritetom> sekvenca =
new A r r a y L i s t < Za da ta kS Pri or it et om >( );
public ZadatakSPrioritetom(int prioritet) {
thi s .priori tet = prioritet;
sekvenca.addfthi s ) ;
}
public int co mp ar eT o(ZadatakSPrioritetom arg) {
return prioritet < arg.prioritet ? 1 :
(prioritet > a r g .prioritet ? -1 : 0);
}
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(sl uc a j a n . n e x t l n t (250));
) catch(InterruptedException e) {
// Prihvatljiv nain izlaska
}
pri nt(thi s ) ;
992 Misliti na Javi
//: paralelno/RasporedjivacStaklenika.java
// Prerada programa unutrasnjeklase/KontrolerStaklenika.java
// u kojoj je upotrebljen ScheduledThreadPoolExecutor.
// (Args: 5000}
import java.util.concurrent.*;
import java.uti1.*;
podaci,add(new RadnaTacka((Calendar)pos1ednjiPut.clone(),
poslednjaTemp, poslednjaVlaznost));
}
}
}
public static void main(String[] args) {
RasporedjivacStaklenika st = new RasporedjivacStaklenika();
st.raspored(st.new Gasi(), 5000);
// Ranije klase "Restart" nisu potrebne:
st.ponavljaj(st.new Zvono(), 0, 1000);
st.ponavljaj(st.new TermostatNoc(), 0, 2000);
st.ponavljaj(st.new UkljuciSvetlo(), 0, 200);
st.ponavljaj(st.new IskljuciSvetlo(), 0, 400);
st.ponavljaj(st.new UkljuciVodu(), 0, 600);
st.ponavljaj(st.new IskljuciVodu(), 0, 800);
st.ponavljaj(st.new TermostatDan(), 0, 1400);
st.ponavljaj(st.new PrikupiPodatke(), 500, 500);
}
} /* (Pokrenite da biste videli rezultat) *///:-
Ova verzija reorganizuje kod i dodaje jednu novinu: prikupljanje m erenja tem pera-
ture i vlanosti u stakieniku. RadnaTacka sari i prikazuje jedan skup merenja, dok je
PrikupiPodatke planiran zadatak koji generie sim ulirane podatke i dodaje ih listi
List<RadnaTacka> u Stakleniku nakon svakog svog izvravanja.
O bratite panju na to da se m odifikatori volatile i synchronized upotrebljavaju na
odgovarajuim m estim a kako bi se spreilo da zadaci sm etaju jedan drugom . Prilikoin
pravljenja liste koja sadri RadneTake, sve m etode bivaju sinhronizovane uslunom me-
todom synchronizeL ist() iz biblioteke java.util.Collections.
Veba 33: (7) Izm enite RasporedjivacStaklenika.java tako da koristi DeIayQueue um e-
sto ScheduledExecutora.
Semafor
O bina brava (eksplicitna iz concurrent.locks ili ugraena synchronized) u svakom tre-
nutku dozvoljava sam o jed no m zadatku da pristupi svakom resursu. Setnafor broja om o-
guuje da n zadataka istovrem eno pristupa jednom resursu. Moete sm atrati da semafor
izdaje dozvole za korienje odredenog resursa, m ada se zapravo ne upotrebljavaju nikak-
vi objekti dozvola.
Kao prim er, razm otriem o pojam grupe objekata koja upravlja ogranienim brojem
objekata tako to dozvoljava da b ud u pojedinano izdati na u p otrebu i p otom vraeni
kada korisnik zavri svoj posao s njima. Te funkcije em o kapsulirati u generikoj klasi:
//: paralelno/Grupa.java
// Semafor u grupi objekata koji ograniava broj zadataka
// koji istovremeno mogu koristiti resurs.
import java.uti1 .concurrent.*;
import java.uti1.*;
998 Misliti na Javi
Niz izdat tipa boolean prati objekte koji su izdati na korienje, a njim e upravljaju me-
tode uzm iStavku() i pustiStavku(). N jih pak uva sem afor (objekat tipa Semaphore)
dostupan, tako da u m etodi izdajObjekatNaKoriscenje(), dostupan blokira poziv uko-
liko vie nem a dostup nih dozvola za korienje objekata iz grupe (to znai da u grupi
vie nem a objekata). M etoda prim iObjekatNazadUGrupu() vraa dozvolu sem aforu
ukoliko je objekat koji se vraa validan.
Kao p rim er upotrebiem o Debeli, tip objekta koji je skupo praviti zato to njegovom
konstruktoru treba m nogo vrem ena da obavi svoj posao:
O kupiem o ove objekte u grupu da bism o ograniili uticaj tog konstruktora. Klasu
Grupa em o testirati pravljenjem zadatka koji objekte tipa Debeli uzima na korienje,
dri ih neko vrem e i zatim vraa nazad:
//: paralelno/PrimerSemafora.java
// Testiranje klase Grupa
import java.uti1.concurrent.*;
import java.util.*;
import static net.mindview.util.Print.*;
Exchanger
Exchanger (razmenjiva) jeste barijera koja om oguava da se m eusobno zam ene objekti
dvaju zadataka. Kada zadaci uu u barijeru, im aju svaki po jedan objekat, a kada izau,
im aju objekat koji je prethodno im ao onaj drugi zadatak. Ovakvi razmenjivai se obino
koriste kada jedan zaatak pravi objekte ija je proizvodnja skupa, a drugi zadatak ih
troi; na taj nain, moe se napraviti vie objekata koji se istovrem eno troe.
Da bism o upotrebili klasu Exchanger, napraviem o zadatke proizvoaa i potroaa
koji preko generikih tipova i Generatora rade sa svim vrstam a objekata, i zatim em o ih
prim eniti na klasu Debeli. Klase RazmenjivacProizvodjac i RazmenjivacPotrosac kori-
ste objekat tipa List<T> za razm enu; svaka od njih sadri Exchanger za ovu listu
List<T>. Kada pozovete m etodu Exchanger.exchangc( ), ona blokira zadatak dok part-
nerski zadatak ne pozove svoju m etodu exch an ge(). Kada obe m etode exchan ge() zavre
svoj posao, lista tipa List<T> bie zamenjena:
//: paralelno/ExchangerPrimer.java
import java.uti1 .concurrent.*;
import java.uti1.*;
import net.mindview.util.*;
U m etodi m a in (), pravi se jedan Exchanger koji koriste oba zadatka, i dve liste tipa
CopyOnWriteArrayList za razm enu. Ova varijanta objekta tipa List tolerie pozivanje
m etode rem ove() tokom prolaska kroz listu (ne baca ConcurrentModificationExcepti-
on). RazmenjivacProizvodjac popunjava jednu listu, zatim zamenjuje p u n u listu praz-
nom koju m u prosleduje RazmenjivacPotrosac. Klasa Exchanger ini da popunjavanje
jedne liste i troenje druge m ogu da se odvijaju istovremeno.
Veba 34: (1) Izm enite ExchangerPrimer.java tako da umesto klase Debeli upotrebite
neku svoju.
Simulacija
Jedna od najzanimljivijih i najuzbudljivijih prim ena paralelnog izvravanja jeste pra-
vljenje simulacija. Zbog paralelnosti, svaka kom ponenta simulacije moe biti zaseban
zadatak, a sim ulaciju je zato m nogo lake program irati. Mnoge video igrice i CGI anim a-
cije u film ovim a su simulacije, a i ranije prikazani program i TrkaKonja.java i Raspored-
jivacStaklenika.java mogu se sm atrati sim ulacijama.
try {
while(!Thread.interrupted{)) {
Klijent klijent = klijenti.take();
TimeUnit.MILLISECONDS.sleep(
kli jent.dajVremeUsluzivanjaO);
synchronized(this) {
usluzenihKlijenata++;
while(!redKlijenataSeUsluzuje)
wait();
}
}
} catch(InterruptedException e) {
System.out.println(this + "prekinut");
}
System.out.println(this + "zavrava");
}
public synchronized void radiNestoDrugo() {
usluzenihKlijenata = 0;
redKlijenataSeUsluzuje = false;
}
public synchronized void usluzujRedKlijenata() {
assert !redKlijenataSeUsluzuje:"ve usluujem: " + this;
redKlijenataSeUsluzuje = true;
notifyAl1 ();
}
public String toString() { return "Slubenik " + id + " "; }
public String shortStringO { return "T" + id; }
// Upotrebljava prioritetni red za ekanje:
public synchronized int compareTo(Sluzbenik drugi) {
return usluzenihKlijenata < drugi.usluzenihKlijenata ? -1 :
(usluzenihKlijenata == drugi.usluzenihKlijenata ? 0 : 1);
}
}
exec.execute(sluzbeni k);
radiSluzbenika.add(sluzbenik);
}
public void prilagodiBrojSluzbenika() {
// Ovo je zapravo upravljaki sistem. Menjanjem brojeva otkriete
// nestabilne radne take upravljakog mehanizma.
// Ako je red predugaak, dodaj jo jednog slubenika:
if(klijenti.size() / radiSluzbenika.size() > 2 ) {
// Ako su slubenici na pauzi ili rade neto drugo,
// vrati jednog nazad:
if(sluzbenikaKojiRadeNestoDrugo.size() > 0) {
Sluzbenik sluzbenik = sluzbenikaKojiRadeNestoDrugo.remove();
sluzbenik.usluzujRedKl ijenata();
radiSluzbenika.offer(sluzbenik);
return;
}
// U protivnom napravi (zaposli) novog slubenika
Sluzbenik sluzbenik = new Sluzbenik(klijenti);
exec.execute(sluzbenik);
radiSluzbenika.add(sluzbenik);
return;
}
// Ako je red dovoljno kratak, ukloni jednog slubenika:
if(radiSluzbenika.size() > 1 &&
klijenti.size() / radiSluzbenika.size() < 2)
premestiJednogSluzbeni ka();
// Ako reda uopte nema, treba nam samo jedan slubenik:
if (kl ijenti .size() == 0)
whi1e(radiS1uzbenika.size() > 1)
premestiJednogSluzbenika();
}
// Daj slubeniku drugi posao ili ga poalji na pauzu:
private void premestiJednogSluzbenikaf) {
Sluzbenik sluzbenik = radiSluzbenika.pol1();
sluzbeni k .radi NestoDrugo();
sluzbeni kaKojiRadeNestoDrugo.offer(sluzbeni k);
}
public void run() {
try {
while(!Thread.interrupted()) {
TimeUni t.MILLISECONDS.sleep(periodPri1agodjavanja);
prilagodiBrojSluzbenika();
System.out.print(klijenti + " { ");
for(Sluzbenik sluzbenik : radiSluzbenika)
System.out.print(sluzbenik.shortString() + " ");
System.out.pri ntln("}");
}
} catch(InterruptedException e) {
System.out.println(this + "prekinut");
Poglavlje 21: Paralelno izvravanje 1007
System.out.println(this + "zavrava")-
}
public String toStringO { return "RukovodilacSluzbenika }
}
O bjekti tipa Klijent veoma su jednostavni, poto sare sam o jedno final int polje.
Poto se ti objekti nikada ne menjaju, oni su samo za itanje i ne zahtevaju sinhronizaciju
niti m odifikator volatile. Sein toga, svaki zadatak Slubenik u svakom tren u tk u uklanja
1008 Misliti na Javi
sam o po jedan objekat tipa Klijent iz ulaznog reda i usluuje ga dok ne zavri, pa svakom
objektu tipa Klijent u svakom tren u tk u ionako p ristu p a sam o po jedan zadatak.
RedKlijenata, kako m u im e kae, ine klijenti koji ekaju da ih uslui neki objekat tipa
Slubenik. To je sam o objekat tipa ArrayBlockingQueue s m etodom to S trin g () koja is-
pisuje rezultate u eljenom obliku.
O bjektu tipa RedKlijenata p ridru en je jedan GeneratorKlijenata koji u nasum inim
vrem enskim intervalim a dodaje klijente u red.
Slubenik uzim a klijente iz objekta tipa RedKIijenata i obrauje ih jednog po jednog,
pam tei broj klijenata koje je usluio tok om odreene sm ene. Moe m u se poruiti da
radiN estoD rugo() kada nem a dovoljno klijenata i usluzujRedKlijenata( ) kada doe
m nogo klijenata. Slubenika koji e biti vraen na opsluivanje ulaznog reda bira m etoda
com pareTo() koja poredi broj usluenih klijenata da bi p rio ritetn i red za ekanje (Prio-
rityQueue) m ogao autom atski da stavi najm anje optereenog slubenika napred.
RukovodilacSluzbenika upravlja svim aktivnostima. On prati sve slubcnike i nadgleda
ta rade klijenti. Jedna od zanimljivosti ove simulacije jeste pokuaj otkrivanja optim alnog
broja slubenika za dati dotok klijenata. To moete videti u metodi prilagodiBrojSluzbe-
n ik a() koja je upravljaki sistem za dodavanje i uklanjanje slubenika na stabilan nain. Svi
upravljald sistemi m oraju da paze na stabilnost; ako na prom enu reaguju prebrzo, izgubie
stabilnost, a ako reaguju presporo, sistem e prei u jedan od ekstrema (red klijenata
maksimalne duine, a ne rade svi dostupni slubenici ili su zaposleni svi slubenici iako kli-
jenata nem a).
Veba 35: (8) Izm enite program SimuIacijaSalterskogSluzbenika.java tako da predsta-
vlja Web klijente koji alju zahteve o dreenom broju servera. Treba utvrditi optereenje
koje ta grupa servera moe da savlada.
Simulacija restorana
Jednostavan prim er Restoran.java prikazan u prethodnom delu poglavlja obogatiu u
ovoj simulaciji dodavanjem vie kom ponenata kao to su objekti tipa Narudzba i
DeoObroka; pored toga, ponovo u upotrebiti klase jelovnik iz poglavlja Nnbrojani tipovi.
Predstaviu i Java SE5 klasu SynchronousQueue to je blokirajui red za ekanje nultog
internog kapaciteta, pa svaki poziv m etode p u t() m ora da eka na svoj poziv m etode take()
i obrnuto. Kao da nekome treba da predate neki predm et, a nema stola na koji biste ga mo-
gli staviti - uspeete jedino u sluaju da ta osoba prui ka vama ruku da uzme predmet.
U ovom prim eru, SynchronousQueue predstavlja prostor neposredno ispred restoranskog
gosta, kako bi se naglasilo da u svakom trenutku moe biti poslueno sam o jedno jelo.
Ostale klase i funkcije u ovom prim eru slede iz strukture program a R estoran.java ili
predstavljaju prilino neposredno preslikavanje operacija pravog restorana:
exec.execute(kuvar);
}
}
public void run() {
try {
while(!Thread.interrupted()) {
// Doao je novi gost; dodeli rnu Konobara:
Konobar knbr = konobari.get(
slucajan.nextInt(konobari,size()));
Gost k = new Gost(knbr);
exec.execute(k);
TimeUnit.MILLISECONDS.sleep(100);
}
} catch(InterruptedException e) {
print("Restoran prekinut");
}
print("Restoran se zatvara");
}
}
*///:-
Poglavlje 21: Paralelno izvravanje 1013
Jedna od veom a vanih stvari na koje u ovom prim eru treba obratiti panju jeste upra-
vljanje sloenou tako to su za kom unikaciju izm eu zadataka upotrebljeni redovi za
ekanje. Ve sama ta tehnika uveliko pojednostavljuje postupak paralelnog program iranja
tako to invertuje kontrolu: zadaci se ne obraaju jedan drugom neposredno, nego jedni
drugim a alju objekte preko redova za ekanje. Zadatak koji je prim io objekat obrauje ga
i tretira ga kao poruku, um esto da ga podvrgava poruci. Ukoliko se budete pridravali tog
naina rada, imaete m nogo vie anse da pravite robusne paralelne sisteme.
Veba 36: (10) Izm enite RestoranSRedovima.java tako da za svaki sto postoji po jedan
objekat tip a Narudzbenica. Prepravite klasu narudzba u narudzbenica i dodajte klasu
Sto, s vie G ostiju za stolom.
Raspodela posla
Naredni prim er je sim ulacija koja obuhvata vie koncepata iz ovog poglavlja. Zamislite
robotizovanu m ontanu liniju za autom obile. Svaka Kola se proizvode u nekoliko faza,
poev o d pravljenja asije, preko m ontae m otora, pogonskog sistema i tokova.
//: paralelno/ProizvodnjaKola.java
// Sloen primer saradnje zadataka.
import java.uti1 .concurrent
import java.util.*;
import static net.mindview.uti 1.Print.*;
class Kola {
private final int id;
private boolean
motor = false, pogonskiSistem = false, tockovi = false;
public Kola(int idn) { id = idn; }
// Prazan objekat tipa Kola:
public Kola() { id = -1; }
public synchronized int dajId() { return id; }
public synchronized void dodajMotor() { motor = true; }
public synchronized void dodajPogonskiSistem() {
pogonskiSistem = true;
}
public synchronized void dodajTockove() { tockovi = true; }
public synchronized String toStringO {
return "Kola " + id + " [" + " motor: " + motor
+ " pogonskiSistem: " + pogonskiSistem
+ " tockovi: " + tockovi + " ]";
print("Monter iskljuen");
}
class GrupaRobota {
// (Neujno) spreava identine stavke:
private Set<Robot> grupa = new HashSet<Robot>();
public synchronized void add(Robot r) {
grupa.add(r);
noti fyAl1 ();
}
public synchronized void
unajmi(Class<? extends Robot> tipRobota, Monter d)
throws InterruptedException {
for(Robot r : grupa)
if (r.getClassO .equals(tipRobota)) {
Poglavlje 21: Paralelno izvravanje 1017
grupa.remove(r);
r.dodeliMontera(d);
r.angazuj(); // Ukljui ga da obavi posao
return;
}
wait(); // Nema dostupnih
unajmi(tipRobota, d); // Rekurzivno pokuaj ponovo
}
public synchronized void release(Robot r) { add(r); )
}
Kola se prenose s m esta na mesto pom ou objekta tipa RedKola, to je tip reda Lin-
kedBlockingQueue. PravljenjeSasije pravi kostur Kola i sm eta ga u RedKola. Monter
skida Kola i/. RedaKola i unajm ljuje Robote da na njim a rade. Barijera tipa CyclicBarrier
om oguuje Monteru da eka dok svi unajm ljeni Roboti ne b u d u gotovi, a potom stavlja
Kola u izlazni RedKoIa koji ih prenosi za sledeu operaciju. Potroa zavrnog objekta
tipa RedKola jeste Izvestilac koji sam o ispisuje sastav Kola da bi pokazao da su svi zadaci
pravilno izvreni.
Robotima se upravlja u grupi, i kada neto treba da se uradi, odgovarajui Robot biva
unajmljen iz grupe. Nakon dovretka posla, Robot se vraa u grupu.
U m etodi m a in () prave se svi potrebni objekti i inicijalizuju svi zadaci; poslednje se
pokree PravljenjeSasije da bi se pokrenuo proces. (M eutim , ponaanje reda Linked-
BIockingQueue je takvo da sam m ogao njega prvog da pokrenem .) O bratite panju na to
da ovaj pm gram sledi sve sm ernice u vezi sa ivotuim ciklusom objekata i zadataka koje
su spom enute u ovom poglavlju, pa je postupak gaenja bezbedan.
Uoili ste da su sve m etode Kola sinhronizovane. Ispostavlja se da je to u ovom primeru
redundantno, poto su Kola unutar proizvodnje uvek u nekom od redova za ekanje i na
svakim kolima u svakom trenutku moe raditi sam o jedan zadatak. U sutini, redovi za e-
kanje nam eu serijsko pristupanje objektima tipa Kola. Aii upravo to i jeste zamka - mogli
1018 Misliti na Javi
biste rei: Hajde da optimizujemo perform anse tako to klasu Kola neem o sinhronizovati,
poto izgleda da to ovde nije neophodno". Ali kasnije, kada ovaj sistem bude povezan s ne-
kim drugim koji zahteva da Kola bud u sinhronizovana, sve e se raspasti.
Brian Goetz komentarie:
M nogo je lake reiKola m ogu biti upotrebljena iz vie niti, pa hajde da ih napravim o
oigledno bezbednim za vienitno izvravanje". Evo kako ja to posm atram : na strm im
m estim a u parkovim a postoje zatitne ograde i natpisi Z abranjeno naslanjanje na
zatitnu ogradu. Naravno, prava svrha ovog pravila nije da sprei naslanjanje na ogradu,
nego da sprei padanje niza strm inu. Ali je m nogo lake pridravati se pravila Zabranje-
no naslanjanje na ogradu nego pravila Zabranjeno padanje niza strminu".
Veba 37: (2) Izmenite program ProizvodnjaKola.java dodavanjem jo jedne faze u
postupak pravljenja kola, u kojoj se dodaju izduvni sistem, karoserija i branici. Kao i u
drugoj fazi, pretpostavite da te procese roboti m ogu da obavljaju istovremeno.
Veba 38: (3) Koristei pristup iz program a ProizvodnjaKola.java, m odelujte priu o
gradnji kue koja je data u ovom poglavlju.
Optimizacija performansi
Z natan broj klasa u biblioteci Jave SE5 java.util.concurrent postoji radi poboljanja
perform ansi. Tokom prelistavanja biblioteke concurrent, teko ete razluiti klase na-
m enjene za redovnu upotrebu (kao to su redovi BlockingQueue) od klasa koje su sam o
za poboljavanje perform ansi. U ovom odeljku razm otriem o neka od tih pitanja i klasa
za optim izaciju performansi.
Brian G oetz m i je fflnogo pom ogao da to shvatim . Vie info rm acija o m eren ju p erfo rm an si proitajte
u njegovom lanku na aresi w w w -t28.ibm .com /devdoperw orks/librarY /j-jtpl2214.
1020 Misliti na Javi
da shvati kako se brojac poveava fiksan broj p u ta pa da unapred izrauna rezultat. Ima
razliitih prevodilaca i sistema za izvravanje, pa je teko rei ta e se tano dogoditi, ali
m oram o spreiti m ogunost da prevodilac predvidi ishod.
D a bi testiranje bilo validno, program m ora biti sloeniji. Prvo m oram o napraviti vie
zadataka, i to ne sam o onih koji m enjaju interne vrednosti, ve i onih koji te vrednosti i-
taju (inae b i optim izator m ogao prepoznati da se te vrednosti nikada ne koriste). Pored
toga, izraunavanje m ora biti toliko sloeno i nepredvidljivo da prevodilac nem a anse da
obavi agresivnu optim izaju. To em o postii prethodnim uitavanjem velikog niza
pseudosluajnih celih brojeva (p reth od no uitavanje sm anjuje uticaj poziva m etode
R andom .nextInt() na glavne petlje) i sabiranjem tih brojeva:
//: para'le'lno/PoredjenjeSinhronizacija.java
// Poreenje performansi pri upotrebi eksplicitnih objekata tipa Lock
// i Atomic i performansi pri korienju rezervisane rei synchronized.
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.concurrent.locks.*;
import java.util.*;
import static net.mindvievv.uti 1 .Print .*;
} /* Ispis: (primer)
Zagrevanje
OsnZ aP or : 34237033
Ciklusa : 50000
OsnZ aP or : 20966632
synchronized : 24326555
Lock : 53669950
Atomi c : 30552487
synchroni zed/OsnZaPc r 1.16
Lock/OsnZaPor 2.56
Atomi c/OsnZaPor 1.46
synchroni zed/Lock 0.45
synchronized/Atomic 0.79
Lock/Atomi c 1.76
Ciklusa : 100000
OsnZaPor : 41512818
synchronized : 43843003
1024 Misliti na Javi
Lock 87430386
Atomi c 51892350
synchroni zed/OsnZaPor : 1.06
Lock/OsnZaPor : 2.11
Atomic/OsnZaPor : 1.25
synchronized/Lock : 0.50
synchronized/Atom 'c : 0.84
Lock/Atomic : 1.68
Ciklusa 200000
OsnZaPor 80176670
synchronized 5455046661
Lock 177686829
Atomic 101789194
synchroni zed/OsnZaPor 68.04
Lock/OsnZaPor 2.22
Atomic/OsnZaPor 1.27
synchronized/Lock 30.70
synchroni zed/Atomi c 53.59
Lock/Atomi c 1.75
Ci klusa 400000
OsnZaPor 160383513
synchronized 780052493
Lock 362187652
Atomi c 202030984
synchronized/OsnZaPor 4.86
Lock/OsnZaPor 2.26
Atomi c/OsnZaPor 1.26
synchroni zed/Lock 2.15
synchroni zed/Atomi c 3.86
Lock/Atomic 1.79
Ci klusa 800000
OsnZaPor 322064955
synchroni zed 336155014
Lock 704615531
Atomi c 393231542
synchronized/OsnZaPor : 1.04
Lock/OsnZaPor 2.19
Atomi c/OsnZaPor 1.22
synchronized/Lock 0.47
synchronized/Atomic : 0.85
L o c k /Atomic 1.79
Ci klusa 1600000
OsnZaPor 650004120
synchroni zed 52235762925
Lock 1419602771
Atomi c 796950171
Poglavlje 2 1: Paralelno izvravanje 1025
sy nchronized/OsnZaPor : 80.36
Lock/OsnZaPor : 2.18
A tomic/OsnZaPor : 1.23
synchronized/Lock : 36.80
synchronized/Atomic : 65.54
Lock/Atomic : 1.78
Ciklusa : 3200000
OsnZaPor : 1285664519
synchronized : 96336767661
Lock : 2846988654
Atomic : 1590545726
synchronized/OsnZaPor : 74.93
Lock/OsnZaPor : 2.21
Atomic/OsnZaPor : 1.24
synchronized/Lock : 33.84
synchronized/Atomic : 60.57
Lock/Atomic : 1.79
*///:-
U metodi m a in (), testiranje se ponavlja i moete odluiti da zatraite vie od pet (po-
drazumevanih) ponavljanja. U svakom ponavljanju, broj ciklusa testiranja se udvo-
struuje, pa moete videti kako se razne uzajamno iskljuive brave (m utexi) ponaaju
kada se izvravaju sve due i due. Kao to vidite iz izlaza, rezultati su prilino iznenau-
ju i. U prve etiri iteracije izgleda da je rezervisana re synchronized efikasnija od klasa
Lock i Atomic. Ali iznenada neka granica biva prekoraena pa deluje da synchronized
postaje veoma neefikasna, dok Lock i Atom ic kao da priblino odravaju svoju srazmeru
prema testu OsnZaPor (osnova za poreenje) i stoga postaju mnogo efikasniji od syn-
chronized.
Im ajte u vidu da ovaj program daje tek naznaku razlike izmeu raznih realizacija uza-
jam no iskljuivih brava i da gornji izlaz pokazuje te razlike samo na m om konkretnom
raunaru pod m ojim konkretnim okolnostima. Kao to ete videti kada budete eksperi-
mentisali s ponaanjem, ono se znatno menja u zavisnosti od broja niti i trajanja izvra-
vanja programa. Neke optimizacije vruih taaka pozivaju se tek nekoliko minuta nakon
poetka izvravanja programa, a u sluaju serverskih programa, nakon nekoliko sati.
Uza sve to, prilino je jasno da je klasa Lock najee znatno efikasnija od rezervisane
rei synchronized, a izgleda i da se reijski trokovi upotrebe rezervisane rei synchroni-
zed znatno meniaju, dok oni klase Lock ostaju relativno ujednaeni.
Da li to znai da rezervisanu re synchronize uopte ne treba upotrebljavati? U obzir
morate uzeti dva inioca: prvo, u primeru PoredjenjeSinhronizacija.java tela mutex
metoda su izuzetno mala. Uopte uzev, to je dobro - uzajamno iskljuite samo one delove
programa koje apsolutno morate. Meutim, uzajamno iskljueni delovi u praksi mogu
biti vei nego u gornjem primeru, te e i procentualni deo vremena koji se provodi u telu
metoda verovatno biti znatno vei nego reijski trokovi od ulaska i izlaska iz uzajamno
iskljuive brave, a to bi moglo da poniti eventualno poboljanje koje prouzrokuje
ubrzanje uzajamno iskljuive brave. Naravno, istinu ete saznati tek kada isprobate
razliite pristupe i vidite njihov uticaj, a to bi trebalo da radite tek prilikom optimizacije
performansi.
Drugo, ko proita kod u ovom poglavlju videe da rezervisana re synchronized
proizvodi mnogo itljiviji kod od idioma zakljuaj-try/finally-otkljuaj, za koji su po-
trebne brave tipa Lock, i zato sam u ovom poglavlju uglavnom koristio synchronized. Na
vie mesta u ovoj knjizi rekao sam da se kod mnogo ee ita nego pie u programi-
ranju je vanije da kod razumeju drugi ljudi nego raunar - te je itljivost koda kljuna.
Zato ima smisla poeti s rezervisanom rei synchronized i prei na objekte tipa Lock tek
prilikom optim izacije performansi.
Najzad, lepo je kada moete da upotrebite klase Atomic u paralelnom programu, ali
morate voditi rauna o tome da su, kao to smo videli u programu PoreenjeSinhroni-
zacija.java, Atomic objekti korisni samo u veoma jednostavnim sluajevima, po pravilu
samo kada imate jedan Atom ic objekat koji menjate i kada je taj objekat nezavisan od svih
o s ta lih o b je k a ta . B e z b e d n ij e je k r e n u ti s tr a d i c i o n a l n ij im u z a ja m n o is k lju iv im bra\ 'ain a
i pokuati prelazak na Atoinic objekte kasnije, ukoliko to budete morali da uinite zbog
performansi.
Poglavlje 2 1: Paralelno izvravanje 1027
O performansama
Ukoliko iz kontejnera bez zakljuavanja uglavnom itate, bie to mnogo bre nego da i-
tate iz njegove sinhronizovane verzije, zato to izbegavate reijske trokove od zakljua-
vanja i otkljuavanja. To vai i za mali broj upisivanja u kontejner bez zakljuavanja, ali bi
bilo zanimljivo stei neku predstavu koliko je to ,,malo. U ovom odeljku daemo grubu
slik u o r a z lik a m a u p e r io r m a n s a m a tili k o n te jn e r a p o d r a z li itim u s lo v im a .
1028 Misliti na Javi
//: paralelno/Tester.java
// Osnovna struktura za te stiranje performansi paralelnih kontejnera.
import java.util.concurrent.*;
import net.mindview.util.*;
Prethodnu strukturu (u kojoj ste prepoznali projektni obrazac Template Metho) ko-
ristite tako to iz klase Tester izvedete konkretni tip kontejnera koji elite da testirate i na-
pravite odgovarajue klase Citalac i Upisivac:
} /* Ispis: (primer)
Tip Vreme itanja Vreme upis.
Sinhro. ArrayList 10c Ou 232158294700 0
Sinhro. ArrayList 9c lu 198947618203 24918613399
vremeCit + vremeUpis = 223866231602
Sinhro. ArrayList 5c 5u 117367305062 132176613508
vremeCit + vremeUpis = 249543918570
CopyOnWriteArrayList 10c Ou 758386889 0
CopyOnWriteArrayList 9c lu 741305671 136145237
vremeCit + vremeUpis = 877450908
CopyOnWriteArrayList 5c 5u 212763075 67967464300
vremeCit + vremeUpis = 68180227375
*/// =-
vremeCit += trajanje;
}
}
class Upisivac extends ZadatakTestiranja {
void test() {
for(long i = 0; i < ciklusaTestiranja; i++)
for(int indeks = 0; indeks < velicinaKontejnera; indeks++)
ko nt ej nerZaTestiranje.put(indeks, up is iP odatke[indeks]) ;
}
void upisiRezultate() {
vremeUpis += trajanje;
}
}
void po kr en i C i t a o c e l U p i s i v a c e O {
for(int i = 0; i < nCitalaca; i++)
exec.execute(new C i t a l a c O ) ;
for(int i = 0; i < nUpisivaca; i++)
exec.execute(new U p i s i v a c O ) ;
}
Optimistiko zakljuavanje
Pored toga to objekti tipa Atomic izvravaju atomske operacije kao to je decrement-
AndGet( ), neke Atomic klase omoguuju i tzv. optimistiko zakljuavanje. To znai da
prilikom izraunavanja ne koristite uzajamno iskljuivanje, ali da nakon zavretka izrau-
navanja za auriranje Atomic objekta koristite metodu com pareA ndSet(). Prosleujete
jo j staru i novu vrednost, i ako se stara vrednost ne podudara s vrednou pronaenom u
Atomic objektu, operacija se zavrava neuspehom - to znai da je neki drugi zadatak u
meuvremenu izmenio objekat. Ne zaboravite da inae uvek upotrebljavamo mutex (re-
zervisanu re synchronized ili objekat tipa Lock) i tako spreavamo da vie zadataka isto-
vremeno modifikuje objekat, ali ovde se ponaamo optimistiki tako to podatke
ostavljamo nezakljuane i nadamo se da drugi zaaci nee uleteti i modifikovati ih. Narav-
no, sve to radimo samo zbog performansi - korienjem objekta tipa Atomic umesto re-
zervisane rei synchronized ili objekta tipa Lock, verovatno ete poboljati performanse.
ta se deava ako operacija com pareA ndSet() zakae? Stvari postaju upave, pa ovu
tehniku moete da prim enjujete samo na projekte koje moete krojiti kako god potrebe
nalau. Ako com pareA ndSet() zakae, morate da odluite ta da radite; to je veoma va-
n o , p o t o u s lu a ju d a je o p o r a v a k n e m o g u , u m e s to o v e te h n ik e m o r a t e d a u p o tie b U e
neku od konvencionalnih brava za uzajamno iskljuivanje (m utexa). Moda moete po-
kuati da ponovite operaciju i nee smetati ako ona (tek) drugi put uspe. Ili moda moe-
te da zanemarite neuspeh - u nekim simulacijama, gubitak jedne take ne znai nita za
celinu, jer je broj taaka ogroman. (Naravno, model morate poznavati toliko dobro da
znate je li prethodna hipoteza istinita.)
Poglav[je 2 !: Paralelno izvravanje 1035
Zamislimo fiktivnu simulaciju koja se sastoji od 100 000 ,,gena duine 30; recimo da je
to poetak nekakvog genetikog algoritma. Pretpostavimo da je za svaku ,,evoluciju gene-
tikog algoritma potreban veoma skup proraun, pa ste odluili da upotrebite vieproce-
sorski raunar, rasporedite zadatke meu procesorima i tako poboljate performanse. Sem
toga, umesto objekata tipa Lock koristite Atomic objekte da biste izbegli reijske trokove
uzajamnog iskljuivanja. (Naravno, program ste najpre napisali na najjednostavniji mo-
gui nain, pomou rezervisane rei synchronized. Tek kada je takav program proradio,
otkrili ste da je prespor i poeli da primenjujete tehnike za poboljavanje performansi!)
Zbog prirode ovog modela, zadatak koji otkrije sudar tokom proruuna, moe da ga zane-
mari i da ne aurira svoju vrednost. Evo kako to izgleda:
//: pa ralelno/BrzaSimulacija.java
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import j a v a . u t i l .*;
import static n e t . mi nd vi ew .u ti l.Print.*;
Sve elemente smo stavili u niz, zato to sm atram o da e to poboljati performanse. (Tu
pretpostavku emo testirati u jed noj od vebi.) Svaki objekat tipa Evolver uproseava
svoju vrednost s prethodnom i sa sledeom, i ako auriranje ne uspe, on ispisuje tu vred-
nost i ide dalje. Imajte u vidu da u programu nema uzajamnog iskljuivanja.
Veba 39: (6) Da li su pretpostavke u programu BrzaSimulacija.java razumne? Izmenite
niz tako da sadri proste cele brojeve umesto objekata tipa Atom iclnteger i upotrebite
Lock brave za uzajamno iskljuivanje (mutexe). Uporedite performanse te dve verzije
programa.
ReadWriteLock
ReadVVriteLock optimizuje situaciju kada u strukturu podataka upisujete relativno ret-
ko, ali iz nje vie zadataka esto ita. Klasa ReadVVriteLock om oguuje da do prvog
pokuaja upisivanja istovremeno radi vie italaca. Nakon zakljuavanja brave za pisanje,
itaoci ne mogu da rade sve dok se brava za pisanje ponovo ne otkljua.
Nemogue je unapred rei da li e ReadVVriteLock poboljati performanse vaeg pro-
grama; to zavisi od inilaca kao to su srazmera broja itanja i broja modifikovanja poda-
taka, trajanje operacije itanja i upisivanja (brava je sloenija, pa kratke operacije ne daju
da se vidi poboljanje), koliina takm ienja meu nitima i da li se program izvrava na
vieprocesorskom raunaru. Na kraju krajeva, jedini nain da saznate da li ReadWri-
teLock poboljava va program jeste da ga isprobate.
U narednom primeru prikazana je samo najjednostavnija upotreba klase ReadVVri-
teLock, tj. zasebnih brava za itanje i upisivanje:
//: paralelno/ListaCitalacalUpisivaca.java
import ja v a . u t i 1 .concurrent.*;
import java.util.concurrent.locks.*;
import ja v a . u t i l .*;
import static n e t . mi nd vi ew .u ti l.Print.*;
new R e en tr an tR ea dW ri te Loc k( tr ue );
public ListaCitalacaIUpisivaca(int velicina, T pocetnaVrednost) {
zakljucanaLista = new ArrayList<T>(
Collections.nCopies(velicina, p o c e tn aV re dn os t) );
}
public T set(int indeks, T element) {
Lock bravaZaUpisivanje = b r av a. wr it eL oc k( );
br av aZ aU pi si va nj e. loc k( );
try {
return zakljucanaLista.set(indeks, element);
} finally {
b r a v a Z a U pi si va nj e. unl oc k( );
}
}
public T get(int indeks) {
Lock bravaZaCitanje = b r a v a . r e a d L o c k ( ) ;
br a v aZ aC it an je .l oc k();
try {
// Dokaz da vie italaca moe zakljuati
// (pribaviti) bravu za itanje:
if(brava.getReadLockCount() > 1)
p r i n t ( br av a. ge tR ea dLo ck Co un t());
return zakljucanaLista.get(indeks);
} finally {
br av aZ aC it an je .u nl ock ();
}
}
public static void main(String[] args) throws Exception {
new Te stListeCitalacaIUpisivaca(30, 1);
}
}
class TestListeCitalacalUpisivaca {
ExecutorService exec = E x e c u t o r s . ne wC ac he dTh re ad Po ol();
private final static int VELICINA = 100;
private static Random slucajan = new Random(47);
private Li staCitalacalUpisivaca<Integer> lista =
new ListaCitalacaIUpisivaca<Integer>(VELICINA, 0);
private class Upisivac implements Runnable {
public void run() {
try {
for(int i = 0; i < 20; i++) { // test od 2 sekunde
1 i s ta .s et (i, s l u c a j a n .n ex tl nt () );
TimeUni t. M I L L I S E C O N D S .s l e e p (1 0 0 ) ;
}
} catch(InterruptedException e) {
// Prihvatljiv nain izlaska
}
1038 Misliti na Javi
Aktivni objekti
Kada prouite ovo poglavlje, moda ete stei utisak da je u Javi veoma sloeno i teko ko-
rektno sprovesti vienitni rad. Pored toga, izgleda i pomalo kontraproduktivno - iako
zadaci rade paralelno, morate uloiti mnogo truda da realizujete tehnike za spreavanje
tih zadataka kako ne bi smetali jedan drugom.
Ako ste ikada pisali u asembleru, pisanje vienitnih programa izaziva isti oseaj: vana
je svaka sitnica, sve morate sami da uradite i nema zatite u vidu provere koju sprovodi
prevodilac.
Da problem nije u samom modelu vienitnog rada? Na kraju krajeva, on je preuzet re-
Iativno nepromenjen iz sveta proceduralnog programiranja. Moda postoji drugaiji mo-
del paralelnog rada, prikladniji za objektno orijentisano programiranje.
Jedan od alternativnih pristupa nazvan je aktivni objekti ili aktori.26 Objekti su proglae-
ni ,,aktivnim zato to svaki objekat odrava sopstvenu radnu nit i red za poruke; svi za-
htevi koji se odnose na taj objekat ulaze u njegov red za ekanje i izvravaju se jedan po
jedan. Dakle, kod aktivnih objekata serijalizujemoporuke, a ne tnetode, to znai da vie ne
moramo da se titimo od problema koji nastaju kada se zadatak prekine usred petlje.
Kada aktivnom objektu poaljete poruku, ona se transformie u zadatak koji ulazi u ob-
jektov red za ekanje na kasnije izvravanje. Za realizaciju te eme podesna je klasa Future
Jave SE5. Evo jenostavnog primera u kojem dve metode stavljaju pozive u red za ekanje:
//: paralelno/PrimerAktivnogObjekta.java
// Moe da prosledi samo konstante, nepromenljive, "nevezane
// objekte" ili druge aktivne objekte kao argumente
// asinhronim metodama.
import j a v a .ut i 1 .co nc u r r e n t .
import j a v a . u t i l .*;
import static net.mindvievv.uti 1 .P r i n t .*;
public Future<Integer>
calculatelnt(final int x, final int y) {
return izvr si1ac.submit(new C a l1able<Integer>() {
public Integer c a l l () {
print("pokreem " + x + 11 + " + y ) ;
s a c e k a j (500);
return x + y;
}
});
}
public Future<Float>
calculateFloat(final float x, final float y) {
return izvrsilac.submit(new Callable<Float>() {
public Float call () {
print("pokreem " + x + " + " + y);
s a c e k a j (2000);
return x + y;
}
});
}
public void shutdown() { izvrsi la c. sh ut do wn (); }
public static void main(String[] args) {
Primer Ak tivnogObjekta pl = new Prim er Ak ti vn og Ob je kta ();
// Spreava izuzetak ConcurrentModificationException:
L i s t < F u t u r e < ? rezultati =
new C o p y O n W r i t e A r r a y L i s t < F u t u r e < ? ( ) ;
for(float f = O.Of; f < l.Of; f += 0.2f)
r e z u l t a t i ,add(pl.calculateFloat(f, f ) ) ;
forfint i = 0 ; i <5; i++)
r e zu lt at i. ad d( pl .c alc ul at el nt (i, i ) ) ;
print("Zavreni pozivi svih asinhronih metoda");
while(rezultati.size() > 0) {
fo r( Future<?> f : rezultati)
if ( f .is D on e( )) {
try {
print(f.get());
} catch(Exception e) {
throw new R u n t im eE xc ep ti on (e );
}
re zu lt at i. re mo ve (f );
}
}
pl.shutdown();
}
} /* Ispis: (85% podudaranja)
Zavreni pozivi svih asinhronih metoda
pokr e em 0.0 + 0.0
pokreem 0.2 + 0.2
0.0
pokreem 0.4 + 0.4
0.4
pokreem 0.6 + 0.6
0.8
Poglavlje 2 1: Paralelno izvravanje 1041
p o kr e em 0.8 + 0.8
1.2
p o kr e em 0 + 0
1.6
p o kr e em 1 + 1
0
p o kr e em 2 + 2
2
p o kr e em 3 + 3
4
pokr e em 4 + 4
6
8
*///:-
(najgore to se moe desiti je kratko odlaganje). Poto sistem aktivnih objekata kom uni-
cira samo preko poruka, dva objekta ne mogu biti blokirana dok se nadmeu da pozovu
metodu nekog treeg objekta, a to znai da ne moe nastati uzajamna blokada, to je veliki
korak napred. Poto radna nit aktivnog objekta u svakom trenutku izvrava samo po jed-
nu poruku, nema takm ienja za resurse i ne moram o da sinhronizujemo metode. Sinhro-
nizaja i dalje postoji, ali na nivou poruka, zato to se pozivi metoda ubacuju u red za
ekanje, pa se u svakom trenutku moe izvravati samo jedan od njih.
Naalost, prevodilac ne daje neposrednu podrku za aktivne objekte, a runo pro-
gramiranje po gornjem obrascu previe je zametno. Meutim, oblast aktivnih objekata i
aktora se razvija, kao i oblast agentski orijentisanogprogram iranja koja je jo zanimljivija.
Agenti su zapravo aktivni objekti, ali agentski sistemi se ne m enjaju u zavisnosti od rau-
nara niti mree. Ne bi me iznenadilo da agentski orijentisano programiranje nasledi
objektno orijentisano program iranje, zato to se u njemu kombinuju objekti i relativno
lako reenje za paralelno izvravanje.
Vie inform acija o aktivnim objektim a, aktorima i agentima moete nai na Webu;
neke ideje realizovane u aktivnim objektim a moete nai naroito u C.A.R. Hoareovoj
teoriji komunicirajuih sekvencijalnih procesa (Communicating Seciuential Processes, CSP).
Veba 41: (6) Programu PrimerAktivnogObjekta.java dodajte deo za obradu poruka
koji nema povratnu vrednost, a poziva se iz metode m a in ().
Veba 42: (7) Izmenite VoskOMatik.java tako da realizuje aktivne objekte.
Projekat:27 Pomou anotacija i Javassista napravite anotaciju klase @Active koja odre-
dinu klasu transformie u aktivan objekat.
Saetak
Trebalo je da iz ovog poglavlja nauite osnove paralelnog programiranja pomou Javinih
niti, kako biste shvatili sledee:
1. Moete izvravati vie nezavisnih zadataka.
2 . Morate uzeti u obzir sve mogue probleme prilikom gaenja tih zadataka.
3 . Zadaci se meusobno om etaju prilikom korienja deljenih resursa. Osnovna alat-
ka za spreavanje takvih sudara je uzajamno iskljuiva brava (mutex).
4 . Ako zadatke ne projektujete paljivo, oni se mogu uzajamno blokirati.
Neophodno je nauiti kada se koristi paralelno izvravanje, a lcada da ga izbegavati.
Osnovni razlozi za upotrebu jesu:
Da biste posao podelili na vie zadataka i tako efikasnije koristili raunar. Time se
postie i (za programera nevidljiva) raspodela zadataka na vie procesora.
Radi bolje organizacije koda.
Radi vece pogodnosti za korisnika.
P rojekti su predlozi koji se m ogu koristiti (recim o ) za sem inarske radove. Vodi s reenjim a ne sadri
reenja projckata.
Poglavjje 21: Paralelno izvravanje 1043
V arijanta ovoga se zove princip n ajm anjeg iznenaenja, to znai da korisnika ne bi trebalo iznena-
ivati.
IBM j e za svoj program za ureivanje teksta Eclipse ( www.Eclipse.org) napravio novu G U I biblioteku
O t v o r e n o g iz v o r n o g koda koja je alternativa Svvingu; b o lje je predstavljena u nastavku poglavlja.
1046 Misliti na Javi
javax.swing u toj dokumentaciji kako biste saznali sve detalje o biblioteci Swing i metode
iz nje. Pomo moete potraiti i na Webu, ali najbolje je da krenete od Sunovog udbenika
za Swing na adresi http://java.sun.com/docs/books/tutorial/uiswing.
Postoji veliki broj (prilino debelih) knjiga posveenih iskljuivo bibliote Swing i
njih ete sigurno prouavati ako vam zatreba ire znanje, ili ako poelite da promenite
podrazumevano ponaanje biblioteke Swing.
Kako budete savladavali biblioteku Swing, otkrivaete sledee:
1. Biblioteka Swing je mnogo bolji model za programiranje od onih koje ste verovatno
sretali u drugim jezicim a i razvojnim okruenjima. Osnovna struktura za tu bibli-
oteku jesu zrna Jave (koja e biti objanjena pri kraju ovog poglavlja).
2. Alatke za pravljenje grafikih okruenja (vizuelna okruenja za programiranje)
obavezan su vid kompletnog razvojnog okruenja za Javu. Zrna Jave i Swing om o-
guuju razvojnom okruenju da pie kod umesto vas, dok vi razmetate kompo-
nente na obrasce pomou grafikih alatki. To u velikoj meri ubrzava projektovanje
grafikog okruenja i om oguuje slobodnije eksperimentisanje i isprobavanje di-
zajna, to posledino dovodi do izbora boljeg okruenja.
3. Jednostavnost i dobar projekat grafike biblioteke Swing znai da e ak i ako kori-
stite vizuelnu alatku, umesto da runo piete kod, dobijeni kod biti razumljiv. To
reava veliki problem s korienjem ranijih vizuelnih alatki kojima se esto generi-
sao nerazumljiv kod.
Grafika biblioteka Swing sadri sve komponente koje se oekuju u modernom korisni-
kom okruenju, od dugmadi sa slikaina, preko stabala do tabela. To je velika biblioteka, ali
sloenost odgovara zadatku koji se obavlja: ako je neto jednostavno, ne morate da piete
mnogo koda, ali ukoliko pokuate da uradite neto tee, i kod postaje srazmerno sloeniji.
Dobar deo privlanosti biblioteke Swing potie od neega to bi se moglo nazvati ,,or-
togonalnost korienja". Odnosno, kada jednom steknete opte ideje o ovoj biblioteci,
m oi ete da ih prim enjujete svuda. Dok sam pisao primere iz ovog poglavlja, najee
sam ve na osnovu imena metode mogao da zakljuim ta ona radi, i to zahvaljujui stan-
dardu za imenovanje. To je, sasvim sigurno, obeleje dobre biblioteke. Pored toga, kom-
ponente se obino mogu dodavati drugim komponentama i sve e raditi ispravno.
Navigacija pom ou tastature je automatska: aplikaciju napisanu pomou Svvinga ino-
ete da pokrenete i bez mia, to ne zahteva nikakvo dodatno programiranje. Podrka za
pom eranje sadraja je izvanredna - treba samo da om otate komponentu u objekat klase
JScrollPane dok je dodajete u obrazac. Za dodavanje komponenata poput prirunih sa-
veta (engl. tooltips) obino je dovoljan samo jedan red koda.
Cela biblioteka Swing napisana je na Javi radi prenosivosti.
Swing podrava i prilino radikalnu mogunost nazvanu prilagodljiv izgled i ponaa-
nje (engl. pluggable look & feel), to znai da izgled grafikog okruenja moe dinamiki
d a sc p r o m e n i d a b i se p r il a g o d io o e k i v a n j im a k o ris n ik a n a r a z li itim p l a t t o r m a m a
i operativnim sistemima. Mogue je (mada teko) napraviti ak i sopstveni izgled okru-
enja. Neka takva okruenja moete nai i na Webu. '
M eni se najvie svia izgled i ponaanje Salveta (engl. nnpkin) autora Kena A rnolda, u kojem prozori
izgledaju kao da su skicirani na salveti. Posetite http://mipkinlaJ.sourceforge.iiet.
Poglavlje 22: Grafika korisnika okruenja 1047
Uprkos svim svojim pozitivnim aspektima, Swing nije za svakoga, niti je sve probleme
s korisnikim okruenjima reio onako kako su njihovi projektanti zamislili. Na kraju
poglavlja razmotriemo dve alternative za Swing: IBM -ov SWT, razvijen za editor teksta
Eclipse, ali besplatno dostupan kao samostalna GUI biblioteka otvorenog izvornog koda,
i Flex kom panije Adobe, alatku za razvoj klijentskih okruenja Web aplikacija u Flashu.
Apleti
Kada se Java tek pojavila, dobar deo halabuke oko tog jezika izazvao je a p le t - program
koji se preuzima sa Interneta da bi se izvravao u itau Weba (unutar tzv. bazena s pe-
skom, da ne bi nakodio klijentskom raunaru). Predvialo se da e Java aplet postati sle-
dea faza u evoluciji Interneta i u mnogima od prvih knjiga o Javi pretpostavljalo se da je
italac zainteresovan za taj jezik prvenstveno zato to eli da pie aplete.
Iz raznih razloga, ta revolucija se nije odigrala. Dobar deo problema inilo je to to
veina raunara nema potreban Java softver za izvravanje apleta, a veina korisnika ne
eli da preuzme i instalira paket od 10 M B da bi prikazali neto to su sluajno pokupili
s Weba. Ve i spominjanje neeg slinog dovoljno je da uplai mnoge korisnike. Java apleti
nikada nisu dostigli kritinu masu kao sistem za distribuciju aplikacija klijentima, i
premda se apleti i alje povremeno sreu, po pravilu pripadaju prolosti raunarstva.
To ne znai da apleti nisu zanimljiva i vredna tehnologija. Ukoliko moete obezbediti
da svi korisni imaju instaliran JRE (recim o u jednoj kom paniji), onda bi apleti (ili
JNLP/Java Web Start koje emo opisati u nastavku poglavlja) mogli biti savreni za istri-
buciju klijentskih programa i automatsko auriranje svih raunara i pri tom bi se izbegli
trokovi i trud koji obino prate instalaciju i distribuciju novog softvera.
Uvod u tehnologiju apleta nai ete u mrenim dodacima ove knjige, na adresi
www.MindView.net.
Osnove Svvinga
Veina Svving aplikacija, tj. grafikih korisnikih okruenja, gradi se unutar jednostavnog
objekta tipa JFram e, koji pravi prazan prozor (ili okvir, engl . fram e) u operativnim si-
stemima svih korisnika. Naslov prozora se ovako zadaje pomou konstruktora objekta
tipa JFram e:
//: gui/ZdravoSwing.java
import javax.swing.*;
Metoda setD efaultC loseO peration() kazuje objektu tipa JFram e ta da radi kada ko-
risnik izvede manevar gaenja. Konstanta EXIT_O N_CLO SE saoptava mu da izae iz
programa. Podrazumevano se u tom sluaju ne radi nita, pa ako ne pozovete metodu
setD efaultC loseO peration() ili ne napiete ekvivalentan kod za va prozor, aplikaja se
nee zavriti.
setS ize() zadaje veliinu prozora u pikselima.
O bratite panju na poslednji red:
p r oz or .s et Vi si bl e( tru e);
//: gu i/ZdravoNatpis.java
import javax.swing.*;
import java.util.concurrent.*;
Tekst JLabel natpisa menja se nakon jedne sekunde. Iako je to zabavno i u tako jedno-
stavnom programu bezbedno, ba i nije dobro da glavna nit m a in () pie neposredno u
GUI komponente. Swing ima sopstvenu nit za prim anje UI dogadaja i auriranje ekrana.
Ako sadraj ekrana ponete da menjate pomou drugih niti, moete izazvati sudare i uza-
jam nu blokadu opisane u poglavlju Paralelno izvravanje.
Umesto toga, druge niti - kao prethodno spomenuta nit m a in () - treba Svvingovoj niti
za otpremu dogaaja (engl. event dispatch thread) da alju (engl. submit) zadatke na
izvravanje.4 To se postie predajom zadatka metodi SwingU tilities.invokeLater( ) koja
zadatak smeta u redza ekanje dogadaja (engl. event queue), iz koga ih nit za otpremu do-
gaaja (u nekom trenutku) vadi i izvrava. U prethodnom primeru to bi izgledalo ovako:
Ova praksa jc novina u Javi SE5, pa je gom ila starih program a ne podrava. To ne znai da su njihovi
autori bili neznalice, nego da se preporuena praksa stalno m enja.
1050 Misliti na Javi
Obratite panju na to da poziv metode sleep () rtije unutar konstruktora. Ako ga sta-
vite tarno, prvobitni tekst natpisa (Jedan natpis) uopte nee biti prikazan, poto u tom
sluaju konstruktor nee zavriti dok se ne zavri metoda sleep () i novi natpis ne bude
umetnut. Ali ako je poziv metode slee p () unutar konstruktora ili bilo koje UI operacije,
to znai da tokom spavanja koje prouzrokuje metoda sle e p () zadravate izvravanje niti
za otpremu dogaaja, to je po pravilu loe.
Veba 1: (1) Izmenite ZdravoSwing.java tako da dokaete da se aplikacija ne gasi bez po-
ziva metode setD efauItCIoseO peration().
Veba 2: (2) Izmenite ZdravoNatpis.java tako da pokaete da je doavanje natpisa di-
namiko - stavite u prozor pseudosluajan broj natpisa.
Alatka za prikazivanje
Objediniem o navedene ideje i smanjiti koliinu redundantnog koda sledeom alatkom
za prikazivanje koju em o koristiti u ostalim primerima biblioteke Svving u ostatku
poglavlja:
Ovu alatku ete moda poeleti da koristite na vie mesta, pa je smetena u biblioteku
net.mindview.util. Da bi mogla da je koristi, aplikacija mora biti u objektu tipa JFram e
(kao svi primeri u ovoj knjizi). Statina metoda r u n () zadaje naslov prozora jednak Class
imenu objekta tipa JFrame.
Veba 3: (3) Izmenite SlanjeSwingPrograma.java tako da upotrebljava program Swing-
Konzola.
PravIjenje dugmeta
Pravljenje dugmeta je prilino jednostavno: samo pozovite konstruktor klase JButton i
prosledite mu natpis koji treba da se pojavi na dugmetu. Kasnije ete videti da moete
uraditi i neto naprednije, npr. staviti slike na dugmad.
Referenca na dugme se obino uva unutar klase da bi kasnije moglo ponovo da jo j se
pristupi.
JButton je Swing kom ponenta sa sopstvenim prozoriem koja se automatski iscrtava
tokom auriranja prikaza. To znai da dugme ili neki drugi kontrolni objekat ne crtate
runo, ve ih samo postavljate na obrazac i om oguujete im da se automatski iscrtavaju.
Dugme se na obrazac postavlja obino unutar konstruktora:
//: gui/Dugmel.java
// Stavljanje dugmadi u Swing aplikaciju.
import javax.swing.*;
import java.awt.*;
import static ne t. m i n d v i e w . u t i l .SwingKonzola.*;
Ovde je dodato neto novo: pre nego to se element postavi u okno sadraja, dodeljuje
mu se novrasporeiva tipa FlowLayout. Rasporediva (engl. Layout manager) opisuje
n a in n a koji o k n o im p l ic itn o o d lu u je o t o m e g d e e p o s ta v iti k o n tr o ln i o b je k a t na
obrascu. Aplet obino koristi rasporediva tipa BorderLayout, ali to nam u ovom sluaju
ne odgovara zato to se na taj nain (kao to ete saznati u nastavku poglavlja) svaki kon-
trolni objekat potpuno prekriva novim objektima u istoj oblasti. Meutim, rasporeiva
1052 Misliti na Javi
Hvatanje dogaaja
Ako prevedete i izvrite prethodni program, primetiete da se nee deavati nita kada
pritiskate dugmad. U tu svrhu morate sami da napiete kod. Sutina programiranja upra-
vljanog dogaajima, to ini veliki deo programiranja grafikih korisnikih okruenja, je-
ste povezivanje dogaaja s kodom koji odgovara na njih.
Ovo se u grafikoj biblioteci Swing postie jasnim razdvajanjem okruenja (grafikih
kom ponenata) i realizacije (koda koji elite da izvravate kada se desi dogaaj). Svaka
komponenta moe da prijavljuje dogaaje, i svaki od njih moe da prijavljuje zasebno.
Dakle, ako niste zainteresovani, na primer, za to da li je pokaziva mia preao preko dug-
meta, neete oslukivati taj dogaaj. To je veoma jednostavan i elegantan nain za pisanje
programa voenih dogaajima. Kada shvatite osnovne pojmove, lako ete koristiti Swing
komponente koje nikada niste videli. Zapravo, ovaj model se prim enjuje na sve to se
moe okarakterisati kao zrno Jave (o emu ete saznati vie u nastavku poglavlja).
Za poetak, usredsrediemo se na glavne ogaaje kom ponenata. Za dugme tipa JBut-
ton, glavni dogaaj je njegovo pritiskanje. Da biste objavili svoje zanim anje za dogadaj
pritiskanja dugmeta, pozivate metodu addActionListener( ) klase JButton. Ta metoda
oekuje argument koji realizuje interfejs ActionListener to sadri samo jednu metodu
action P erform ed (). Dakle, da biste povezali kod s dugmetom tipa JButton, treba samo
da realizujete interfejs ActionListener u klasi i da prosledite objekat te klase dugmetu me-
todom addA ctionListener(). Metoda prosledenog objekta pozivae se kad god se priti-
sne dugme (to se obino naziva povratni poziv , engl. callback).
ta bi trebalo da bude rezultat pritiskanja tog dugmeta? eleli bismo da vidimo da se
neto menja na ekranu, pa e biti predstavljena nova Swing komponenta: JTextFieId. To
je jednoredno polje za unos teksta, ili, u ovom sluaju, polje u kome program moe me-
njati tekst. Iako postoji vie naina da se napravi objekat klase JTextFieId, najjednostav-
niji nain je da se samo saopti konstruktoru koliko treba da bude iroko to polje. Kada se
polje za tekst postavi na obrazac, njegov sadraj moete da menjate metodom setT ext()
(klasa JTextFieldsadri i mnoge druge metode, ali njih morate da potraite sami u HTM L
dokumentaciji na adresi http://java.sun.com). Evo kako to izglea:
//: gui/Dugme2.java
// Reagovanje na pritiskanja dugmeta.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindvie w . u t i 1 .S wi ngKonzola.*;
Poglavlje 22: Grafika korisnika okruenja 1053
Jenoredno polje za tekst pravi se i smeta na obrazac na isti nain kao dugme ili neka
druga Swing komponenta. Gornji program se razlikuje po pravljenju pomenute klase
PrijemnikDugmeta koja realizuje interfejs ActionListener. Argument metode action-
Performed( ) tipa je ActionEvent i sadri sve inform acije o dogaaju i mestu gde je na-
stao dogadaj. U ovom sluaju, eleo sam da opiem dugme koje je pritisnuto: metoda
g etS ou rce() vraa objekat gde se esio dogaaj, a ja sam (eksplicitnom konverzijom) ui-
nio da njegov tip bude JButton. Metoda g etT ext() vraa tekst koji se nalazi na dugmetu,
i ja sam ga stavio u polje tipa JTextField kako bih dokazao da se kod zaista poziva kada se
dugme pritisne.
U konstruktoru se metoda addA ctionListener() koristi za registrovanje objekata klase
PrijemnikDugmeta kao prijemnika dogaaja oba dugmeta.
esto je zgodnije da interfejs ActionListener bude realizovan kao anonimna unutra-
nja klasa, naroito zato to se obino koristi samo jedna instanca svake klase ovog tipa.
Program Dugme.java moe se promeniti tako da koristi anonim nu unutranju klasu na
sledei nain:
//: gui/Duame2b.java
// Korienje anonimnih unutranjih klasa.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static ne t. mi nd vi ew .u ti l.SwingKonzola.*;
1054 Mis/iti na Javi
//: gui/TextArea.java
// Korienje kontrole JTextArea.
import j a v a x . s w i n g .*;
import java.awt.*;
lmport java.awt.event.*;
import j a v a . u t i 1 .*;
import net.mindview.util.*;
import static ne t. mi nd vi ew .u ti1 .SwingKonzola.*;
Poglavlje 22: Grafika korisnika okruenja 1055
Veba 7: (5) Napravite aplikaciju pom ou klase SwingKonzoIa i dodajte sve Swing kom-
ponente koje imaju metodu ad dA ctionListener(). (Potraite ih u HTM L dokumentaciji
na adresi http://java.siin.com. Savet: upotebite indeks.) Uhvatite njihove dogaaje i za
svaki prikaite odgovarajuu poruku u polju za tekst.
Veba 8: (6) Gotovo sve kom ponente biblioteke Swing izvedene su iz klase Component
koja ima metodu se tC u rso r(). Potraite je u H TM L dokumentaciji za Javu. Napiite ap-
likaciju i promenite pokaziva mia u neki iz klase Cursor.
Rasporeivanje elemenata
Nain na koji se komponente rasporeuju u Javi verovatno je drugaiji nego u svim osta-
lim sistemima za grafika okruenja koje ste koristili. Prvo, sve se obavlja programski: ne
postoje ,,resursi koji upravljaju postavljanjem komponenata. Drugo, nainom na koji se
komponente postavljaju na obrazac ne upravlja apsolutno pozicioniranje, ve rasporeiva
koji odluuje o poloaju komponenata na osnovu redosleda kojim ih dodajete. Veliina, ob-
lik i poloaj komponenata znatno se razlikuju od jednog rasporeivaa do drugog. Pored
toga, rasporeivai se prilagodavaju dimenzijama apleta ili prozora aplikacije, pa ako se
promeni dimenzija prozora, u saglasnosti s tim mogu da se promene veliina, oblik i po-
loaj komponenata.
Klase JApplet, JFram e, JWindow, JDialog JPanel itd. mogu da sadre i prikazuju
komponente. Klasa Container sadri metodu setLayout( ) koja omoguuje zadavanje
rasporedivaa. U ovom odeljku prouiem o raziiite rasporeivae tako to emo posta-
vljati dugmad (jer je to najjednostavnije). Neemo obraivati nikakve dogaaje, poto ovi
primeri samo pokazuju kako se kom ponente rasporeuju.
Rasporeiva BorderLayout
Prozor podrazumevano koristi rasporeiva tipa BorderLayout. Ako ne zadate drugaije,
on uzima sve objekte koje mu dodajete i smeta ih u centar, i pri tom ih proiruje sve do
ivica.
Ovaj rasporeiva koristi etiri granine oblasti i centralnu oblast. Kada na pano koji
koristi rasporeiva BorderLayout dodate neto, moete da upotrebite preklopljenu me-
todu a d d () iji je prvi argument konstantna vrednost. Ta vrednost moe da bude neto od
sledeeg:
Borderl_ayout.NORTH fvrh)
BorderLayout. SOUTH |dno)
BorderLayout. EAST (desno)
BorderLayout.WEST (ievoj
BorderLayout.CENTER Ipopunjavanje sredine, do ostaiih komponenata ili ivica)
Poglavlje 22: Grafika korisnika okruenja 1057
//: gu i/ Bo rderLayoutl.java
// Prikazuje rasporeiva B o r d e r L a y o u t .
import javax.swing.*;
import java.awt.*;
import static n e t. mi nd vi ew .u ti l.SwingKonzola.*;
Ako se element postavlja u bilo koju oblast osim CENTER, saima se da bi se uklopio
u najm anji mogui prostor du jedne dimenzije, a maksimalno se produava du druge
dimenzije. Oblast CENTER, meutim, proiruje objekat u obe dimenzije da bi zauzeo
sredinu.
Rasporeiva FlowLayout
Ovaj rasporeiva samo ,,reda komponente na obrazac, sleva udesno, sve dok se ne po-
puni jedan red, a zatim prelazi u sledei red i nastavlja redanje.
Evo primera koji bira rasporeiva tipa FlowLayout i zatim postavlja dugmad na
obrazac. Prim etiete da u ovakvom nainu rasporeivanja komponente zadravaju svoju
,,prirodnu veliinu. Dugme je, na primer, taman toliko da se moe prikazati znakovni niz
koji sadri.
//: g u i / F l o w L a y o u t l .java
// Prikazuje rasporeiva FlowLayout.
import javax.swing.*;
import java.awt.*;
import static net. mi nd vi ew .u ti1 .SwingK on zo la .*;
Rasporeiva GridLayout
GridLayout omoguuje izradu tabele kom ponenata, a kako ih dodajete, one se smetaju
sleva udesno i odozgo nanie u tabeli. U konstruktoru se zaaje potreban broj redova i
kolona i one se prikazuju u jednakim proporcijam a.
//: gui/GridLayoutl.java
// Prikazuje rasporeiva GridLayout.
import javax.swing.*;
import java.awt.*;
import static ne t. mi nd vi ew .u ti l.SwingKonzola.*;
Rasporeiva GridBagLayout
GridBagLayout obezbeduje potpunu kontrolu nad odluivanjem o rasporedu i formati-
ranju oblasti u prozoru kada mu se promeni veliina. Meutim, to je istovremeno i naj-
sloeniji rasporeiva koji je veoma teko razumeti. Namenjen je prvenstveno
a u t o m a ts k o m g e n e ris a n ju k o d a p o m o u a la tk e za p r a v lje n je g r a fi k ih a p lik a c ija (d o b r i
vizuelni alati koriste GridBagLayout umesto apsolutnogpozicioniranja). Ako je program
toliko sloen da mislite kako treba koristiti rasporeiva tipa GridBagLayout, trebalo bi
da upotrebite vizuelnu alatku. Ako ba elite da saznate sve detalje o ovome, potraite ih
u nekoj knjizi potpuno posveenoj grafikoj biblioteci Svving.
Poglavlje 22: Grafika korisnika okruenja 1059
Apsolutno pozicioniranje
Apsolutan poloaj grafikih kom ponenata mogue je zadati i na sledei nain:
1. Uklonite rasporeiva metodom Container.setLayout(null).
2 . U zavisnosti od verzije jezika, za sve komponente pozovite metodu setB ou nd s() ili
resh ap e (), prosleujui jo j okvirni pravougaonik ije su koordinate izraene pik-
selima. To moete da uradite u konstruktoru ili u metodi p a in t(), u zavisnosti od
toga ta elite da postignete.
Neke alatke za pravljenje grafikih okruenja esto koriste ovakav pristup, ali to obi-
no nije najbolji nain za generisanje koda.
Rasporeiva BoxLayout
Poto korisnici nisu razumevali klasu GridBagLayout i teko su je primenjivali, u biblio-
teku Swing dodata je i klasa BoxLayout koja prua mnoge prednosti rasporedivaa Grid-
BagLayout, a nije toliko sloena. Ovakvo rasporeivanje esto moete da koristite pri
runom razmetanju elemenata (i ovde, ako program postane previe sloen, upotrebite
vizuelnu alatku). Rasporediva BoxLayout om oguuje i vertikalno i horizontalno kon-
trolisanje poloaja komponenata, a za kontrolisanje prostora izmedu komponenata kori-
ste se ,,podupirai i ,,lepak. Elementarne primere upotrebe rasporedivaa BoxLayout
potraite u mrenim dodacima ove knjige, na adresi www.MindView.net.
Vidi se da svaki tip komponente podrava samo odredene tipove dogaaja. Ispostavlja
se da je prilino teko traiti sve dogaaje koje podrava svaka komponenta. Laki pristup
je da se prilagodi program PrikaziMetode.java iz poglavlja Podaci o tipu tako da prika-
zuje sve prijem nike ogaaja koje podrava bilo koja uneta Swing komponenta.
U p o g la v lju l\nlnci o tipu o b ja n je n a je rcjlcksija a p o t o m je k o r i e n a i za lista n je m e -
toda odredene klase (ceo spisak nietoda ili podskup metoda u ijem se imenu nalazi za-
data rezervisana re). Ovaj postupak je moan zato to automatski prikazuje svemetode
D ogaaj M o u seM o tio n E v en t ne postoji m ada izgleda kao da bi m o rao postojati. Pom eran je m ia uz
dranje pritisnu tog tastera ob jed in jen o je u dogaaj M ou seE v ent, pa drugo pojavljivanje klase M o-
u seE v en t u tabeli n ije greka.
1062 Misliti na Javi
}
}
}
public PrikaziMetodeAddListener() {
ImeL imeListener = new ImeL();
ime.addActionListener(imeLi st en er );
JPanel gornji = new JPanel();
gornji .add(new JLabelC'Ime Swing klase(pritisnite Enter):'1));
go rn ji . a d d ( i m e ) ;
add(BorderLayout.NORTH, gornji);
add(new JScrollPane(rezultati));
// Poetni podaci i test:
ime.setText("JTextArea'');
imeLi stener.actionPerformed(
new Ac ti o n E v e n t ( " , 0 ,""));
}
public static void main(String[] args) {
run(new Pr i kaziMetodeAddLis t en er (), 500,400);
}
} ///:-
Glavni prozor ovog programa sadri polje ime tipa JTextFiel; u njega treba da une-
sete ime Swing klase koju traite. Rezultati se vade pomou regularnog izraza i prikazuju
u polju tipa JTextArea.
Prim etiete da nema dugmai niti drugih komponenata kojima bi se naznailo kako
elite da ponete pretraivanje. Razlog je to to dogaaje polja tipa JTextField nadgleda
prijem nik tipa ActionListener. Kad god neto izmenite i pritisnete taster Enter, spisak se
trenutno aurira. Ako polje nije prazno, njegov sadraj se koristi za pokuaj pronalaenja
klase metodom C lass.forN am e(). Ukoliko je ime nepravilno, metoda C lass.forN am e()
nee nai klasu, pa generie izuzetak koji se hvata, a u objektu klase JTextArea prikazuje
se znakovni niz ,,Ne postoji". Medutim, ako otkucate ispravno ime (vaan je i raspored ve-
likih i malih slova), metoda Class.forN am e() nalazi klasu i getM ethods() vraa niz obje-
kata klase Method.
Ovde se koriste dva regularna izraza. Prvi, addListener, trai re add iza koje slede slova
pa re Listener i spisak argumenata u zagradi. Ceo regularan izraz je u obinim zagradama
(koje nisu pretvorene u izlazne sekvence), to znai da e biti pristupaan kao ,,grupa
regularnog izraza kada bude pronaden. Unutar metode Im eL.A ctionPerform ed(), svaki
objekat Method prosleuje se metodi Uzorak.matcher( ), ime se pravi objekat tipa
Matcher. Kada se za taj objekat tipa Matcher pozove metoda fin d (), ona vraa true ako
pronae podudaran niz znakova i u tom sluaju pozivom metode g ro u p (l) moete oda-
brati prvu podudarnu grupu unutar zagrada. Taj znakovni niz jo uvek sadri kvalifikato-
re, pa se za n iih o v o o b a c iv a n ie u p o tr e b lia v a o b je k a t kvalifikator Uzorak, k a o u
PrikaiMetode.java.
Na kraju konstruktora, u ime se smeta poetna vrednost i izvrava se reakcija na do-
gadaj (ActionEvent) koja ispitivanje snabdeva poetnim podacima.
1064 Misliti na Javi
Ovaj program je zgodan za ispitivanje mogunosti neke Swing kom ponente. Kada
znate koje dogaaje podrava odredena Swing kom ponenta, ne morate da traite nita
posebno da bi ona reagovala na taj dogaaj; samo uinite sledee:
1. Iz imena klase dogaaja uklonite re Event. Dodajte re Listener onom e to preo-
stane. To je interfejs prijemnika koji morate da realizujete u unutranjoj klasi.
2. Realizujete pomenuti interfejs i napiete metode za obradu dogadaja. Na primer,
moda elite da pratite pokrete mia; u tom sluaju treba da napiete kod za meto-
du m ouseM oved() interfejsa M ouseM otionListener. (Naravno, morate da reali-
zujete i druge metode tog interfejsa, ali za to esto postoji preica, to ete uskoro
saznati.)
3. Napravite objekat prijemnike klase iz drugog koraka. Prijavite ga svojoj kompo-
nenti metodom ije ete ime dobiti ako ispred imena prijem nika dodate add, npr.
addMouseMotionListener.
Evo nekih prijemnikih interfejsa:
Ovo nije sveobuhvatan spisak, elimino i zbog toga to vam model dogadaja dozvo-
ljava da pravite sopstvene tipove dogadaja i prijemnike za njih. Zato ete esto viati bi-
blioteke u kojim a postoje novi dogaaji, a znanje koje ste stekli itajui ovo poglavlje
om oguie vam da smislite kako ete koristiti te dogaaje.
Ovo ne radi, a vi ete izludeti pokuavajui da otkrijete razlog. Sve se lepo prevodi i iz-
vrava, osim to nakon pritiska na taster mia vaa metoda nee biti pozivana. Vidite li ta
je problem? Ime metode: navedeno je M ouseClicked() umesto m ouseC licked(). Malo
zanemarivanje veliine slova prouzrokuje dodavanje potpuno nove metode. Meutim, to
nije metoda koja se poziva kada se prozor zatvara, pa neete dobiti eliene rezultate. I po-
red n e p o g o d n o s ti, in te r ie js e g a r a n t o v a ti d a su m e to d e p r a v i ln o re a liz o v a n e .
Izvesno ete reefinisati odredenu metodu ukoliko u gornjem kodu upotrebite ugra-
enu anotaciju @Override.
Veba 9: (5) Na osnovu programa PrikaziMetodeAddListener.java napiite program sa
svim funkcijama programa podaciotipu.PrikaziM etode.java.
1066 Misliti na Javi
//: gu i/ Pr at iD og ad ja j.java
// Prikazuje dogaaje koji se deavaju.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import ja va .u ti l.*;
import static net.mindview.util .SwingKonzola.*;
U Javi 1.0/1.1 ra)'ebilo m ogue izvesti korisne klase iz dugm eta. To je bio sam o jedan od m nogih ve-
likih propusta u projektovanju.
Poglavlje 22: Grafika korisnika okruenja 1067
h.put(dgd, t ) ;
1
add(dl);
add(d2);
}
public static void main(String[] args) {
run(new P r at iD og ad ja j(), 700, 500);
}
1 ///=-
3 . Zbog pravila za imenovanje koja se prim enjuju na Swing dogaaje, prilino se lako
pogaa kako se pie i registruje prijem nik za odredeni tip dogadaja. Upotrebite
program PrikaziMetodeAddListener.java iz ovog poglavlja da biste sebi olakali
traenje odreene komponente.
4 . Kada stvari postanu komplikovanije - vreme je da koristite vizuelne alatke.
Dugmad
Biblioteka Swing sadri veliki broj dugmadi razliitih tipova. Sva dugmad, polja za potvr-
du, radio-dugmad, ak i stavke menija, izvedeni su iz klase A bstractButton (kojoj bi, po-
to obuhvata i stavke menija, bolje odgovaralo ime AbstractSelector" ili neto optije).
Uskoro ete saznati kako se koriste stavke menija, a sledei primer prikazuje razliite do-
stupne tipove dugmadi:
Grupe dugmadi
Ako elite da radio-dugmad iskljuuju jedno drugo, morate ih smestiti u grupu dugma-
di. Meutim, kao to prikazuje sledei primer, svako dugme tipa AbstractButton moe
se dodati grupi tipa ButtonGroup.
Da bi se izbeglo esto ponavljanje koda, u ovom primeru koristi se refleksija za pra
vljenje grupa dugmadi razliitih tipova. To se vidi u metodi n ap rav iP an o() koja pravi
grupu dugmadi i objekat klase JPanel. Drugi argument metode n apraviP ano() jeste niz
objekata tipa String. Za svaki element tog niza na pano se dodaje dugme, a tip dugmadi
odreuje prvi argument metode:
//: giri/GrupeDugmadi.java
// Primenjuje refleksiju za pravljenje grupa
// razliitih tipova dugmadi AbstractButton.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.lang.reflect.*;
import static n e t .m in dview.uti1 .SwingKonzola.*;
bg.add(ab);
jp.add(ab);
}
return jp;
}
public G r u p e D u g m a d i () {
setLayout(new Flow La yo ut () );
add(makeBPanel(JButton.class, ids));
add(makeBPanel(JToggleButton.class, ids));
add(makeBPanel(JCheckBox.class, ids));
add(makeBPanel(JRadioButton.class, i d s));
}
public static void main(String[] args) {
run(new G r u p e D u g m a d i (), 500, 350);
}
} ///:-
Ikonice
Klasu Icon moete da koristite unutar natpisa tipa JLabel ili bilo koje klase koja se izvoi
iz klase AbstractButton (ukljuujui JButton, JCheckBox, JRadioButton i razne vrste
JM enuItem ). Korienje ikonica s klasom JLabel sasvim je jednostavno (kasnije ete vi-
deti prim er). U sledeem primeru istrauju se drugi naini korienja ikonica s dugma-
dima i objektim a koji su iz njih izveeni.
Moete da koristite proizvoljne datoteke u formatu GIF, a one koje se upotrebljavaju u
ovom primeru nai ete u paketu sa izvornim kodom, dostupnom na adresi www.Min-
dVicw.net. Da biste otvorili datoteku i prikazali sliku, napravite objekat klase Im agelcon
i prosledite mu ime datoteke. Nakon toga, moi ete u programu da koristite dobijeni
objekat tipa Icon.
//: g u i / L i k o v i .java
j j Ponaanje lkonica na duyraadima tipa JButton.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net. mi nd vi ew .u ti1 .Sw in gK o n z o l a . * ;
1072 Misliti na Javi
Priruni saveti
U prethodnom primeru dugmetu je dodat i priruni savet (engl. tool tip). Gotovo sve
klase grafikih elemenata izvedene su iz klase JCom ponent koja sadri metodu setTool-
TipText(String). Zbog toga za doslovno sve to stavite na obrazac, treba samo da napiete
(za objekat jc bilo koje klase izvedene iz klase JC om ponent):
jc.setToolTipText("Moj sa v e t " ) ;
i kada se pokaziva mia zadri iznad objekta klase JCom ponent zadato vreme, pored po-
kazivaa e se pojaviti malo polje s vaim tekstom.
//: g u i/ Po lj aZ aT ek st.java
// Polja za tekst i Javini dogaaji.
import javax. sw in g.*;
import j a v a x . s w i n g .e v e n t .*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.uti1 .SwingKonzola.*;
tl.addActionListener(new T I A ());
setLayout(new FlowLa yo ut () );
add(dl);
add(d2);
add(tl);
add(t2);
add(t3);
)
class T1 implements DocumentListener {
public void changedllpdate(DocumentEvent e){)
public void insertUpdate(DocumentEvent e){
t 2 .s et Te xt(tl.getText());
t3.setText("Tekst: "+ tl .g e t T e x t ( ) ) ;
}
public void removeUpdate(DocumentEvent e){
t 2 .s et Te xt(tl.getText());
}
}
class TIA implements Ac ti on Li st en er {
private int broj = 0;
public void actionPerformed(ActionEvent e) {
t3.setText("tl dogadjaj " + broj++);
}
}
class B1 implements Ac tionListener {
public void actionPerformed(ActionEvent e) {
if(tl.getSelectedText() == null)
s = tl .g et Te xt ();
el se
s = tl .g et Se le ct ed Te xt ();
tl.set Ed it ab le (t ru e);
}
}
class B2 implements Ac tionListener {
public void actionPerformed(ActionEvent e) {
dvs.zadajP re tv ar an je( fa ls e);
tl.setText("Ubaceno dugmetom 2: " + s ) ;
dvs.zada jP re tv ar an je( tr ue );
tl.s et Ed it ab le (f al se);
}
}
public static void main(String[] args) {
run(new Po lj aZ aT ek st (), 375, 200);
}
)
Polje t3 tipa JTextFieId slui za izvetavanje o dogaajima polja t l tipa JTextFieId. Vi-
deete da se prijemnik dogaaja za polje JTextField pokree samo kada pritisnete taster
Enter.
S poljem t l povezano je nekoliko prijemnika. T1 je tipa Docum entListener
i odgovara na sve promene ,,dokumenta (u ovom sluaju, sadraja polja). On automatski
kopira sav tekst iz t l u t2. Pored toga, dokument polja t l je tipa DokumentSVelikimSIo-
vima koji je izveden iz klase PlainDocument, a pretvara sva slova u velika. Automatski se
otkrivaju znakovi za brisanje, brie sadraj i pomera pokaziva, pa sve radi kao to se i
oekuje.
Veba 13: (3) Promenite program PoljaZaTekst.java tako da znakovi u t2 zadravaju pr-
vobitni raspored malih i velikih slova kako su bila unesena, umesto da se automatski pre-
tvaraju u velika slova.
Ivice
Klasa JComponent sadri metodu se tB o rd e r() koja om oguuje postavljanje zanimljivih
ivica oko svih vidljivih komponenata. Sledei primer prikazuje razne ivice - metodom
p rik azilvicu () pravi se objekat klase JPanel i na njega postavlja ivica. Prim enjuje se i teh-
nika prepoznavanja tipa tokom izvravanja da bi se ustanovilo ime ivice koja se koristi (uz
izbacivanje svih informacija o putanji), a zatim se to ime stavlja u objekat klase JLabel, u
sredinu panoa.
//: gui/Ivice.java
// Razne ivice iz biblioteke Swing.
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import static ne t. mindview.uti1 .SwingKonzola.*;
jp.setBorder(b);
return jp;
}
public Ivice() {
setLayout(new G r i d L a y o u t ( 2 , 4 ) ) ;
add(prikazilvicu(new Ti t l e d B o r d e r ( " N a s l o v " ) ) ) ;
add(prikazilvicu(new E t c h e d B o r d e r ( ) ) ) ;
add(pri kaziIvi cu(new Li n e B o r d e r ( C o l o r .B L U E ) ));
add(prikaziIvicu(
new M a t t e B o r de r( 5, 5, 30 ,30 ,C ol or .G RE EN )) );
add(prikazilvicu(
new Bevel B o r d e r ( B ev el Bo rd er .RA IS ED )));
add(prikazilvicu(
new SoftBevel Border(Bevel B o r d e r .L 0W ER ED )));
add(pri kaziIvicu(new CompoundBorder(
new Et ch ed Bo rd er (),
new L i n e Bo rd er (C ol or .R ED) )) );
}
public static void main(String[] args) {
run(new Ivice(), 500, 300);
}
} ///:-
Moete da napravite i sopstvene ivice koje ete staviti oko dugmadi, natpisa ili bilo
ega to je izvedeno iz klase JCom ponent.
//: gui/TekstualniPano.java
// Klasa JTextPane kao mali program za ureivanje teksta.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import net.mindview.util.*;
import static ne t. m i n d v i e w . u t i l .SwingKonzola.*;
public class TekstualniPano extends JFra me {
private JButton b = new JButton("Dodaj tekst");
private JTextPane tp = new JTextPane();
private static Ge nerator sg =
new R a n d o m Ge ne ra to r.S t r i n g (7);
public Teks tu aln i P a n o () {
b.addActionListener(new ActionListener() {
public void ac ti on Pe rf or me d( Ac tio nE ve nt e ) {
for(int i = 1; i < 10; i++)
tp.setText(tp.getText() + sg.next() + "\n");
}
Poglavjje 22: Grafika korisnika okruenja 1077
});
add(new JScrollPane(tp));
add(BorderLayout.SOUTH, b ) ;
}
public static void main(String[] args) {
run(new Te ks t u a l n i P a n o ( ) , 475, 425);
}
} ///:-
Polja za potvrdu
Polje za potvrdu om oguuje pravljenje opcije koja moe da bude potvrdena ili nepotvr-
ena; sastoji se od malog polja i oznake. Polje obino sadri malo x (ili neto drugo to po-
kazuje da je opcija potvrena) ili je prazno, u zavisnosti od toga da li je stavka koju
oznaava potvrena ili nije.
O bjekat klase JCheckBox obino se pravi pom ou konstruktora iji je argument nat-
pis. Stanje polja moete da itate i zadajete, ali moete i da itate i menjate njegov natpis
nakon pravljenja.
Kad god se polje tipa JCheckBox potvrdi ili se potvrda ukloni, nastaje dogaaj koji
moete da uhvatite na isti nain kao dogaaj dugmeta, pomou objekta klase ActionLi-
stener. U sledeem primeru koristi se tekstualno polje za brojanje potvrenih polja:
//: gui/PoljaZaPotvrdu.java
// Korienje klase JCheckBoxes.
import javax.swing.*;
import java.awt.*;
iinport j a v a , a w t .e v e n t . * ;
import static ne t. mi nd vi ew .u ti1 .SwingKonzola.*;
Metoda o b ra d i() dodaje ime polja i njegovo tekue stanje u sadraj vierednog polja
za tekst metodom ap p en d (), pa e se prikazati zbirni spisak odabranih polja i njihovih
stanja.
Veba 15: (5) Dodajte polje za potvrdu u aplikaju napravljenu u vebi 5, uhvatite doga-
aj i umetnite drugaiji tekst u polje.
Radio-dugmad
Ime radio-ugme u programiranju grahkih korisnikih okruenja izvedeno je aso-
cijacijom na radija iz starinskih autom obila koji su imali mehaniku dugmad. Kada bi se
jedno dugme pritisnulo, iskakalo bi dugme koje je ranije bilo pritisnuto. Na taj nain mo-
gla je da se odabere samo jedna mogunost.
Poglav[je 22: Grafika korisnika okruenja 1079
Da biste napravili povezanu grupu dugmadi tipa JRadioButton, treba samo da ih do-
date u grupu tipa ButtonGroup. (U obrascu moe da postoji proizvoljan broj grupa dug-
madi.) Jednom dugmetu moe da se (drugim argumentom konstruktora) zada poetno
stanje tako da bude potvreno. Ako vie radio-dugmadi u grupi ukljuite konstruktorom,
poslednje dugme e iskJjuiti sva prethodna.
Evo jednostavnog prim era korienja radio-dugmadi. O bratite panju na to da se do-
gaaji radio-dugmadi obrauju isto kao i svi drugi dogaaji:
//: gui/Radiougmad.java
// Korienje klase JRadioButtons.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import static ne t. m i n d v i e w . u t i l .SwingKonzola.*;
//: gui/PadajuceListe.java
// Korienje padajuih lista.
import javax.swing.*;
import java.avvt.*;
import java.awt.event.*;
import static net.mi nd vi ew .u ti l.SwingKonzola.*;
add(b);
}
public static void main(String[] args) {
run(new Padaju ce Li st e( ), 200, 175);
}
} III--
Tekstualno polje prikazuje odabrani indeks (redni broj elementa koji je trenutno iza-
bran u nizu), kao i tekst stavke koja je odabrana u kom binovanoj listi.
Grafike liste
Polja tipa JList prilino se razlikuju od polja tipa JCom boBox, i to ne samo po izgledu. Za
razliku od polja tipa JCom boBox koje pada kada ga aktivirate, JList uvek zauzima tano
odreen broj redova na ekranu i ne m enja se. Ako elite da vidite elemente liste, samo po-
zovite metodu getSelectedValues() koja vraa niz izabranih stavki.
Lista JList omoguuje viestruki izbor: ako uz pritisnut taster Ctrl miem pritisnete
vie od jedne stavke, stavka koj u ste prvu izabrali ostae istaknuta, a nakon toga moete da
izaberete jo proizvoljan broj elemenata. Ukoliko izaberete neki element, a zatim uz pri-
tisnut taster Shift miem pritisnete jo jedan element, bie izabrani svi elementi izmeu
njih. Da biste uklonili stavku iz izabrane grupe, pritisnite je miem, istovremeno drei
pritisnut taster Ctrl.
b. se tE nab1ed(false);
}
}
};
private ListSelectionListener 11 =
new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e .g et Va lu el sA dj ust in gO ) return;
t.se tT ex t( "" );
for (Object stavke : Is t. ge t S e l e c t e d V a l u e s O )
t.append(stavke[i] + "\n");
}
};
private int broj = 0;
public Lista() {
t.setEditable(false);
setLayout(new FlowLayout());
// Pravi ivice za komponente:
Border brd = BorderFactory.createMatteBorder(
1, 1, 2, 2, Co lo r. BL AC K);
1 s t .se tB or de r( br d);
t.se tB or de r( br d);
// Dodavanje prve etiri stavke u listu
for(int i = 0; i < 4; i++)
elementi Liste.addElem en t( uk us i[ br oj ++ ]);
// Dodavanje stavki u pano sadraja radi prikaza
add(t);
ad d ( l s t ) ;
add(b);
// Registrovanje slualaca dogaaja
1 st.addLi stSelectionLi st en er (1 1);
b.ad dA ct io nL is te ne r(b l);
}
public static void m a i n ( S t r i n g [] args) {
run(new Lista(), 250, 375);
}
} ///:-
Okno s jezicima
Klasa JTabbedPane om oguuje pravljenje okna u kom e se du gornje ivice prikazuju je-
zici. Pritiskom na odredeni jeziak prikazaete njegov poddijalog.
Kada izvrite program, videete da JTabbedPane autom atski prenosi jezike u sledei
red ako ih ima previe da bi stali u isti red. To ete vidieti kada u toku rada prom enite ve-
liinu prozora.
Okviri za poruke
G r a f i k o o k r u e n j e o b i n o s adri s t a n d a r d a n s k u p o k v i r a za p o r u k e koji o m o g u u j u b r z o
dostavljanje informacija korisniku ili uzim anje inform acija od njega. U grafikoj biblio-
teci Svving, polja za poruke realizuje klasa JOptionPane. Postoje brojne m ogunosti (od
kojih su neke vrlo napredne), ali najee ete koristiti dijalog poruke i dijalog za potvrdu
koji se dobijaju pozivom statikih m etoda JO ptionPane.showM essageDialog( ) i JOpti-
onPane.show C onfirm D ialog( ). Sledei primer prikazuje neke od okvira za poruke koji
postoje u klasi JOptionPane:
1084 Misliti na Javi
//: gui/OkviriZaPoruke.java
// Prikazuje klasu JOptionPane.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.util.SwingKonzola.*;
};
public OkviriZaPoruke() {
setl_ayout(new FlowLayout());
for(int i = 0; i < b.length; i++) {
b[i] . a d d A c t i o n L i s t e n e r ( a O ;
a d d( b[ i]);
}
add(txt);
}
public static void main(String[] args) {
run(new O k v i r i Z a P o r u k e O , 200, 200);
}
} ///= -
Da bih napisao sam o jedan prijem nik ogaaja, koristio sam donekle rizinu proveru
natpisa na dugm adim a. Pri takvoj proveri esto se pogrei u pisanju, obino u rasporedu
velikih i m alih slova, a takva greka se teko uoava.
Obratite panju na to da su rezultati m etoda sh ow O ption D ialog( ) i showInputDia-
lo g ( ) objekti s vrednou koju je uneo korisnik.
Veba 17: (5) Napravite aplikaciju p o m ou klase SwingKonzola. U HTML dokum enta-
ciji na lokaciji java.sun .com pronaite klasu JPasswordField i dodajte je u program. Ako
korisnik otkuca tanu lozinku, prikaite poruku o uspehu p om ou objekta klase JOpti-
onPane.
Veba 18: (4) Prom enite program PoljaZaPotvrdu.java tako da ima zaseban prijemnik
tipa ActionListener za svako dugm e (um esto da trai tekst na dugm etu).
Meniji
Svaka kom ponenta koja m oe da sadri m eni, ukljuujui JApplet, JFrame, JDialog i kla-
se koje su iz njih izvedene, im a m etodu setJMenuBar( ). Toj m etodi se prosleuje linija
menija - objekat klase JMenuBar (m oe da postoji sam o jedan objekat klase JMenuBar
za odreenu k om p on entu ). M eniji tipa JMenu dodaju se na liniju menija, a objekti klase
JMenuItem su stavke menija i oni se dodaju u m enije. Sa svakim elem entom tipa JMenu-
Item m oe da bude povezan poseban prijem nik dogaaja, i on se aktivira kada se izabere
ta stavka menija.
Kada koristite Javu i biblioteku Swing, m orate runo da definiete sve m enije u izvor-
n om kodu. Evo vrlo jednostavnog primera menija:
//: gui/JednostavniMeniji.java
import javax.swing.*;
impnrt java.awt.*;
import java.awt.event.*;
import static net.mindview.uti1.SwingKonzola.*;
public class JednostavniMeniji extends JFrame {
private JTextField t = new JTextField(15);
private ActionListener al = new ActionListener() {
1086 Misliti na Javi
//: gui/Meniji.java
// Podmeniji, polja za potvrdu u meniju, kaskadni
// meniji, preice i komande za pokretanje.
import javax.swing.*;
Pog!av[je 22: Grafika korisnika okruenja 1087
import java.avvt.*;
import java.awt.event.*;
import static net.mindview.util.SwingKonzola.*;
public Meniji() {
ML ml = new ML();
Poglavlje 22: Grafika korisnika okruenja 1089
Ovaj program ne pravi jednu, ve dve linije menija tipa JMenuBar da bi pokazao kako
se linije m enija m ogu aktivno menjati dok se program izvrava. Vidite da je linija sasta-
vljena od objekta klase JMenu, o d n o sn o da je svaki objekat tipa JMenu napravljen od
stavki tipa JMenuItem, JCheckBoxItem ili ak od drugih menija tipa JMenu (p od m en i-
ja). Kada se linija menija sastavi, m oe se prikazati u tekuem prozoru m etodom setJMe-
nuBar( ). Obratite panju na to da se - nakon pritiska dugm eta - m etodom
getJM enuBar( ) proverava koji m eni je trenutno prikazan, a zatim se on zamenjuje dru-
gom linijom menija.
Pravopis i raspored m alih i velikih slova presudno su vani prilikom ispitivanja natpisa
O tvori, ali Java ne ukazuje na greku ako ne nae odgovarajuu stavku. Ovakva vrsta po-
reenja znakovnih nizova est je izvor greaka u programiranju.
Potvrivanje i odjavljivanje stavki m enija obavlja se autom atski. Kod kojim se obra-
uju stavke tipa JCheckBoxMenuItem prikazuje dva naina za odreivanje onoga to je
potvreno: pronalaenje istih znakovnih nizova (kao to je reeno, to nije naroito bez-
bedan pristup iako se s vrem ena na vrem e koristi) i pronalaenje istih ciljnih objekata do-
gaaja. Kao to je pokazano, m etoda getState( ) m oe se koristiti za ustanovljavanje
stanja. Stanje stavke JCheckBoxMenuItem m oete da prom enite i m etodom setS tate().
Dogaaji za m enije su donekle nedosledni i m ogu da izazovu zabunu: stavke tipa JMe-
nultem koriste prijem nike tipa ActionListener, dok stavke tipa JCheckboxMenuItem
koriste prijem nike tipa ItemListener. Objekti tipa JMenu m ogu da podre i prijemnik
tipa ActionListener, ali to ob in o nije korisno. Po pravilu, prijem nici se povezuju sa svim
stavkama JMenuItem, JCheckBoxMenuItem ili RadioButtonM enuItem, ali je u prim e-
ru pokazano kako se objekti klasa ItemListener i ActionListener povezuju s raznim kom -
ponentam a menija.
Biblioteka Swing podrava preice s tastature, to znai da m oete aktivirati bilo koji
objekat klase izvedene iz klase AbstractButton (dugm e, stavku menija itd.) korienjem
tastature um esto mia. To je prilino jednostavno: za stavku JMenuItem m oete da upo-
trebite preklopljeni konstruktor iji je drugi argum ent identifikator tastera. M eutim , ve-
ina dugm adi tipa AbstractButton nem a takve konstruktore, pa je optiji nain za
reavanje problem a da se koristi m etoda setM nem on ic( ). U prethodnom primeru doda-
te su preice u neke stavke menija; indikatori preica autom atski se pojavljuju na kom po-
nentam a.
Vidi se i korienje m etode setA ctionC om m and( ) kojom se zadaje kom anda akcije. To
je m alo neobino zato to je u svim sluajevim a komanda akcije" ista kao natpis na kom -
p onenti m enija. Zato se ne upotrebi postojei natpis um esto novog znakovnog niza?
Zbog internacionalizacije. Ako ovaj program prilagodite drugom jeziku, menjaete sam o
natpise u m eniju, ali ne i kod (to bi bez sum nje prouzrokovalo nove greke). Da bi se kod
koji trai znakovne nizove povezane s kom ponentam a menija lake izvravao, komanda
akcije je neprom enljiva, dok se natpis menija m oe menjati. Ceo kod radi skom andom
akcije", pa na njega ne utiu prom ene natpisa menija. Obratite panju na to da se u ovom
programu ne ispituju sve kom pon en te m enija, pa se onim a koje se ne ispituju ne dode-
ljuje kom anda akcije.
Poglavlje 22: Grafika korisnika okruenja 1091
Najvei deo posla odvija se u prijem nicim a. Klasa BL zamenjuje linije m enija (objeka-
ta tipa JMenuBar). Klasa ML prim enjuje pristup otkrij ko je zvonio" tako to ispituje iz-
vor dogaaja (ActionEventa) i konvertuje ga u JMenuItem, a p otom ispituje znakovni
niz kom ande akcije kroz nadovezane naredbe if.
Prijem nik FL je jednostavan, m ada obrauje sve razliite ukuse u m eniju ukusa. Ovaj
pristup je koristan ako je logika dovoljno prosta, ali ete po pravilu prim enjivati pristup
upotrebljen za FooL, BarL i BazL u kojem se prijem nici povezuju sam o s jedn om stav-
kom m enija, pa nije potrebna nikakva dodatna logika za otkrivanje i zna se tano ko je
pozvao prijem nik. ak i ako se broj klasa koje su napravljene na ovaj nain povea, kod
unutar njih nije dugaak pa je ovakav postupak bezbedniji.
V idite da kod menija brzo narasta i postaje neuredan. I u ovom sluaju treba koristiti
vizuelnu razvojnu alatku. Dobra alatka te vrste istovrem eno e i odravati menije.
Veba 19: (3) Prom enite program Meniji.java tako da se u m eniju koriste radio-dugm ad
um esto polja za potvrdu.
Veba 20: (6) N apiite program koji tekstualnu datoteku deli na rei. Stavite te rei u m e-
nije i podm enije kao stavke.
Iskaui meniji
Najjednostavniji nain za prim enu iskaueg menija tipa JPopupMenu jeste da se napra-
vi unutranja klasa koja proiruje klasu MouseAdapter, i da se zatim po jedan objekat te
unutranje klase pridrui svakoj kom ponenti koja treba da izaziva iskakanje menija:
//: gui/Iskakanje.java
// Pravljenje iskauih menija pomou biblioteke Swing.
import javax.swin g .
import java.awt.*;
import java.awt.event.*;
import static net.mindview.uti1 .SwingKonzola.*;
m.addActionListener(al);
meni.add(m);
m = new JMenuItem("Sutra");
m.addActionl_istener(al);
meni.add(m);
meni,addSeparator();
m = new JMenuItem("Nikad");
m.addActionListener(al) ;
meni.add(m);
PrijemnikMenija pl = new PrijemnikMenija();
addMouseLi stener(pl);
t.addMouseListener(pl);
}
class PrijemnikMenija extends MouseAdapter {
public void mousePressed(MouseEvent e) {
iskociAkoTreba(e);
}
public void mouseReleased(MouseEvent e) {
iskociAkoTreba(e);
}
private void iskociAkoTreba(MouseEvent e) {
if(e.isPopupTrigger()) {
meni.show(e.getComponent(), e.getX(), e.getY());
}
}
}
public static void main(String[] args) {
run(new Iskakanjef), 300, 200);
}
} ///:-
Isti prijemnik tipa A ction L isten er povezuje se sa svim stavkama menija (objektim a
tipa JM enuItem ). Prijemnik uzim a tekst natpisa m enija i um ee ga u tekstualno polje.
Crtanje
U dobroj biblioteci za projektovanje grafikih okruenja crtanje bi trebalo da bude prili-
no lako, a u biblioteci Swing tako i jeste. Problem sa svakim prim erom crtanja jeste to to
su izraunavanja kojima se zadaje gde e se ta crtati ob ino m n ogo sloenija od poziva
procedura za crtanje. Izraunavanja su esto pom eana s p ozivim a procedura, pa pristup
izgleda sloeniji nego to stvarno jeste.
Radi jednostavnosti, razm otrim o problem s predstavljanjem podataka na ekranu;
ovde e podatke obezbeivati ugraena m etoda M a th .s in f), ti. matematika funkcija si-
nus. Ua bi sve biio zammljivije, i da bi se jo jed n om pokazalo koliko se kom ponente bi-
blioteke Swing lako koriste, na dno obrasca bie postavljen kliza za dinam iko
kontrolisanje broja prikazanih perioda sinusoide. Pored toga, ako prom enite veliinu
prozora, videete da se sinusoida prilagoava toj novoj veliini.
Poglav[je 22: Grafika korisnika okruenja 1093
Iako se bilo koja kom ponenta tipa JComponent m oe koristiti kao platno za crtanje,
ako elite jednostavnu povrinu (pano) za crtanje, obino treba izvesti klasu iz klase JPa-
nel. Jedino je potrebno redefinisati m etodu paintC om ponent( ) koja se poziva kad god se
kom ponenta iscrtava na ekranu. (O bino ne m orate da brinete o tom e kada e ova m etoda
biti pozvana, poto o tom e odluuje biblioteka Swing.) Swing prosleuje ovoj m etodi obje-
kat tipa Graphics, a taj objekat zatim m oete da koristite za crtanje ili slikanje p o povrini.
U sledeem prim eru se sva logika povezana s crtanjem nalazi u klasi CrtajSinusoidu;
klasa Sinusoida sam o podeava program i kliza. M etoda zadajCikluse( ) om oguuje
drugom objektu, u ovom sluaju klizau, da kontrolie broj ciklusa.
//: gui/Sinusoida.java
// Crtanje u biblioteci Swing, korienjem klizaa JSlider.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import static net.mindview.uti 1 .SwingKonzola.*;
Okviri za dijalog
Okvir za dijalog je prozor koji iskae iz drugog prozora. N jegova svrha je da se izbori sa
odreenom tem om a da ne zatrpa detaljima poetni prozor. Dijalozi se esto koriste u
grafikim program skim okruenjima.
1096 Misliti na Javi
Da biste napravili okvir za dijalog, treba da nasledite klasu JDialog, to je sam o jedna
vrsta prozora, p op ut klase JFrame. Klasa JDialog im a svoj rasporeiva (podrazum evani
je BorderLayout), a za obradu dogaaja treba da dodate prijemnike. Evo vrlo jednostav-
n o g primera:
//: gui/Dijalozi.java
// Pravljenje i korienje okvira za dijalog.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.util.SwingKonzola.*;
Sledei prim er je sloeniji. Dijalog sadri tabelu dugm adi tipa Ik sO k sD u gm e (napra-
vljena je p o m ou klase GridLayout). Ovo dugm e oko sebe iscrtava okvir i, u zavisnosti od
svog stanja, u sredini ne prikazuje nita, prikazuje x ili o. D u gm e je u poetku prazno, a
zatim se, u zavisnosti od toga ko je na redu da igra, pretvara u x ili o. M eutim , on o na-
izm en ino menja stanja izm eu x i o i kada ga pritiskate. (N a taj nain igra iks-oks se
m alo kom plikuje.) Pored toga, okvir za dijalog m oe da sadri proizvoljan broj redova i
kolona, to se zadaje prom enom brojeva u glavnom prozoru aplikacije.
//: gui/IksOks.java
// Prikaz okvira za dijalog
// i izrade komponenata.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.util.SwingKonzola.*;
Poto sam o spoljanji nivo klase m oe imati statike lanove, unutranje klase ne
m ogu da sadre statike podatke ili ugneene klase.
Metoda p a in tC o m p o n e n t() crta kvadrat oko panoa, kao i oznake x ili o. Taj postupak
je prepun dosadnih izraunavanja, ali je jednostavan.
Poglavlje 22: Grafika korisnika okruenja 1099
Operaciju pritiskanja mia hvata objekat klase MouseListener koji prvo proverava da
li je na p an ou neto ispisano. Ako nije, ispituje se roditeljski prozor da bi se ustanovilo ko
je na potezu i to se koristi za zadavanje stanja objekta IksOksDugme. P om ou m ehani -
zma unutranje klase, IksOksDugm e zatim pristupa svom roditelju i menja igraa koji je
na potezu. Ako dugm e ve prikazuje x ili o, stanje m u se menja. U izraunavanjima se vidi
zgodno korienje ternarnog operatora uslovljavanja koji je opisan u poglavlju Operatori.
Nakon p rom en e stanja, objektu Iks-OksDugme menja se boja.
Konstruktor klase IksOksDijalog je prilino jednostavan: u tabelu tipa GridLayout
dodaje dugm ad po potrebi, a zatim poveava stranu svakog dugm eta za 50 piksela.
Objekat klase IksOks pokree celu aplikaciju tako to pravi tekstualna polja za unoenje
broja redova i kolona tabele dugm adi, dugm e ,,potez i prijemnik tipa ActionListener. Kada
se pritisne dugm e, uzimaju se podaci iz tekstualnih polja, a poto su to znakovni nizovi, m o-
raju se konvertovati u tip int p om ou Integer konstruktora koji prima String argument.
//: gui/TestBiranjaDatoteke.java
// Prikaz dijaloga za rad s datotekama.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.uti1 .SwingKonzola.*;
imeDatoteke.setEditable(fa1se);
p = new JPanel();
p.setLayout(new GridLayout(2,l));
p.add(imeDatoteke);
p.add(di r);
add(p, BorderLayout.NORTH);
}
class OtvoriL implements ActionListener {
public void actionPerformed(ActionEvent e) {
JFileChooser c = new JFileChooser();
// Prikazuje dijalog "Otvori":
int rVrednost = c.showOpenDialog(TestBiranjaDatoteke.this);
if(rVrednost == JFi1eChooser.APPR0VE_0PTI0N) {
imeDatoteke.setText(c.getSelectedFile(),getName());
dir.setText(c.getCurrentDirectory() .toSt r i n g O ) ;
}
if(rVrednost == JFi1eChooser.CANCEL_OPTION) {
imeDatoteke.setText("Pritisnu!i ste dugme Cancel");
dir.setText("");
}
}
}
class SnimiL implements ActionListener {
public void actionPerformed(ActionEvent e) {
JFileChooser c = new JFileChooser();
// Prikazuje dijalog "Snimi":
int rVrednost = c.showSaveDialog(TestBiranjaDatoteke.this);
if(rVrednost == JFileChooser.APPROVE_OPTION) {
imeDatoteke.setText(c.getSelectedFile().getName());
di r.setText(c.getCurrentDi rectory().toStri n g ()) ;
}
if(rVrednost == JFileChooser.CANCEL_OPTION) {
imeDatoteke.setText("Pritisnuli ste dugme Cancel");
di r.setText("");
}
}
}
public static void main(String[] args) {
run(new TestBiranjaDatoteke(), 250, 150);
}
1 ///:-
Zapam tite da postoje razne verzije dijaloga JFileChooser, ukljuujui i one koje kori-
ste filtre za suavanje spiska dozvoljenih im ena datoteka.
M etodom sh o w O p en D ia lo g ( ) poziva se dijalog za otvaranje datoteke, a m etodom
show SaveD ialog( ) dijalog za snim anje datoteke. Iz tih m etoda se izlazi tek kada se dijalog
zatvori. Objekat tipa JFileChooser posle toga i dalje postoji, pa m oete da itate podatke
iz njega. M etode getSelectedF ile( ) i getC urrentD irectory( ) dva su naina za ispitivanje
rezultata operacije. Ako te m etode vrate null, korisnik je u dijalogu pritisnuo dugm e za
odustajanje (C ancel).
Poglavlje 22: Grafika korisnika okruenja 1101
Veba 29: (3) U HTML dokum entaciji za biblioteku java.sw in g potraite klasu JCoIor-
C hooser. N apiite program koji pravi dugm e to, kada se pritisne, prikazuje kom andu za
biranje boja u obliku dijaloga.
//: gui/HTMLDugme.java
// Stavljanje HTML teksta na Swing komponente.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import static net.mindview.util.SwingKonzola.*;
Tekst mora da zapone oznakom < h tm l> , a potom m oete da upotrebljavate uobia-
jene HTML oznake. Obratite panju na to da nije obavezno korienje uobiajenih ozna-
ka za zatvaranje.
Prijemnik tipa A ction L isten er u obrazac dodaje nov natpis tipa JLabel koji sa A i i
1 rn vil. tekst. M eutim , taj nalpis se ne oaje tokom konstruisanja objekta, pa m orateda
pozovete kontejnersku m etodu validate( ) da biste prouzrokovali p on ovn o iscrtavanje
kom ponenata (od n osn o, prikazivanje novog natpisa).
I ITML tekst m oete da koristite i u objektim a klasa JTabbedPane, JM enuItem , JTooI-
Tip, JR adioB utton i JCheckBox.
Veba 30: (3) Napiite program u kojem se HTML tekst ispisuje na svim objektima
nabrojanim u prethodnom pasusu.
1102 Misliti na Javi
//: gui/Napredak.java
// Korienje traka napredovanja, klizaa i monitora napredovanja.
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.awt.*;
import static net.mindview.util.SwingKonzola.*;
} ///:-
Poglavlje 22. Grafika korlsnika okruenja 1103
pb.setModel(sb.getModel());
Ove dve kom p onente m ogli biste da kontroliete i p om ou prijemnika, ali je ovo ree-
nje prostije. ProgressM onitor nem a m odel, pa sam m orao da upotrebim prijemnik. Ve-
rovatno ste prim etili da se ovaj ProgressMonitor kree sam o unapred i da se zatvara kada
d oe do kraja.
Klasa JProgressBar je prilino oigledna, ali klasa JSlider im a m notvo opcija, npr.
orijentisanje, vee i manje zareze na klizau itd. Obratite panju na to kako se lako dodaje
ivica sa natpisom .
V eba31: (8) Napravite indikator asim ptotskog napredovanja koji se usporava s pribli-
avanjem zavrnoj taki. Dodajte mu nasum ino pogreno ponaanje da bi s vremena na
vrem e izgledalo kao da poinje da se ubrzava.
Veba 32: (6) Izm enite program Napredak.java tako da za povezivanje klizaa i trake na-
predovanja ne koristi zajednike m odele, ve prijemnik.
try {
UIManager.setLookAndFeel (
UIManaqer.getSystemLookAndFee1ClassNamef));
/ cdtcn ( c x c e p i 1on ej \
throw new RuntimException(e);
Blok catch m oe da bude prazan zato to e U IM anager uitati podrazum evan izgled
i ponaanje ako pokuaj da zadate drugaiji izgled ne uspe. M eutim , inform acija o izu-
zetku biva veom a korisna pri traenju greaka, pa u bloku catch m oete staviti barem na-
redbu za ispisivanje.
Evo programa koji na osnovu argum enta s kom andne linije zadaje izgled i ponaanje,
i pokazuje kako neke kom ponente u tom sluaju izgledaju:
//: gui/IzgledlPonasanje.java
// Biranje razliitih izgleda i ponaanja.
// {Args: motif}
import javax.swing.*;
irrport java.awt.*;
import static net.mindview.util.SwingKonzola.*;
UIManager.setLookAndFeel(UIManager.
getSystemLookAndFeelClassName());
} catch(Exception e) {
e.printStackTrace();
}
} else if(args[0] .equals("motif")) {
try {
UIManager.setLookAndFeel("com.sun.java.+
"swing.plaf.motif.MotifLookAndFeel");
} catch(Exception e) {
e.printStackTrace();
}
} else greskaKoriscenja();
// Obratite panju na to da se izgled i ponaanje moraju
// zadati pre pravljenja bilo kakvih komponenata.
run(new IzgledIPonasanje() 300, 300);
}
} ///:-
Za eksplicitno zaavanje izgleda i ponaanja koristi se M otifL ookA ndF eel. Sam o se
taj i podrazum evani ,,m etalni izgled sigurno m ogu koristiti na svim platformam a; iako
postoje kom ponente koje oponaaju izgled i ponaanje W indow sa i M acOS-a, one se
m ogu koristiti sam o na odgovarajuim platform am a (dobijaju se kada pozovete m etodu
getSystem L ookA ndF eeIC lassN am e() dok radite na odreenoj platform i).
M ogue je napraviti i sopstveni paket elem enata koji opisuju izgled i ponaanje, na
prim er ako pravite strukturu aplikacije za kom paniju koja eli da ta aplikacija posebno iz-
gleda. To je velik posao i uveliko premauje tem u ove knjige (zapravo, otkriete da se
njom e ne bave ni m noge knjige iskljuivo posveene biblioteci Swing).
je, pom ou ikonice na radnoj povrini ili programa za upravljanje aplikacijama koji je deo
realizacije JNLP-a. Aplikacija se m oe pokretati ak i s Web lokacije s koje je bila preuzeta.
U vrem e izvravanja, JNLP aplikacija m oe dinam iki da preuzim a resurse sa Interne-
ta i da autom atski proverava verziju ako je korisnik povezan sa Internetom . To znai da
im a sve prednosti apleta, a i prednosti sam ostalnih aplikacija.
Korisnikov raunar mora oprezno da tretira JNLP aplikacije, kao i aplete. Zato se
JNLP aplikacije izvravaju sam o u bazenu s peskom , kao apleti. U koliko su u potpisa-
nim JAR datotekama, korisnik m oe odluiti da im ukae poverenje i dopusti korienje
resursa njegovog raunara. (Isto vai i za aplete.) Za razliku od apleta, p o m o u usluga
JNLP interfejsa za programiranje JNLP aplikacije m ogu zatraiti pristup odreenim re-
sursima korisnikovog raunara i kada su u nepotpisanim JAR datotekam a. Tokom izvra-
vanja programa, od korisnika se trai da odobri te zahteve.
JNLP je specifikacija protokola, a ne njegova realizacija. Zato je za korienje neop-
h odna i neka realizacija. Java Web Start (JAWS) Sunova je besplatna zvanina referentna
realizacija koja se isporuuje u sklopu Jave SE5. U koliko elite da je koristite za razvoj,
njena JAR datoteka (javaws.jar) mora biti u putanji klasa vaeg raunara; najjednostav-
nije reenje je dodati datoteku javaw s.jar putanji klasa prem estiti je iz njene uobiajene
putanje Java instalacije na putanju jre/lib. Ako JNLP aplikaciju nameravate da instalirate
s Web servera, on bi trebalo da prepoznaje MIME tip ap p lication /x-java-jn lp -file. To je
unapred konfigurisano u novijim verzijama servera Tomcat {http://jakarta.apache.org/
tom cat). Odgovarajue pojedinosti proitajte u korisnikim uputstvim a za svoj server.
Nije teko napraviti JNLP aplikaciju. Napravite obinu aplikaciju, kom prim ujte je u
JAR arhivu i zatim obezbedite datoteku za pokretanje - jednostavnu XML datoteku koja
korisnikovom raunaru daje sve informacije potrebne za preuzim anje i instaliranje te ap-
likacije. U koliko ne potpiete JAR arhivu, morate da koristite usluge koje interfejs za pro-
gramiranje JNLP aplikacija prua za sve tipove resursa kojima aplikacija treba da pristupi
na raunaru korisnika.
Sledi varijanta programa TestBiranjaD atoteka.java koja za otvaranje biraa datoteka
upotrebljava JNI.P usluge, im e om oguuje da klasa bude distribuirana u obliku JNLP
aplikacije u nepotpisanoj JAR arhivi.
//: gui/jnlp/JnlpBiranjeDatoteka.java
// Otvaranje datoteka na lokalnom raunaru pomou JNLP-a.
// {Requires: javax.jnlp.Fi1eOpenService;
// javaws.jar mora biti u putanji klasa}
// Ovako ete napraviti datoteku jnlpbiranjedatoteka.jar:
// cd ..
// cd ..
// jar cvf gui/jnlp/jnlpbiranjedatoteka.jar gui/jnlp/*.class
package g ui .jnlp;
import javax.jnlp.*:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
Poglavjje 22: Grafika korisnika okruenja 1107
snimi.setEnabled(true);
}
1 108 Misliti na Javi
}
class SnimiL implements ActionListener {
public void actionPerformed(ActionEvent e) {
FileSaveService fs = null;
try {
fs = (FileSaveService)ServiceHanager.lookup(
"javax.jnlp.FileSaveService");
} catch(Unavailab1eServiceException use) {
throw new RuntimeException(use);
}
if(fs != null) {
try {
sadrzajDatoteke = fs.saveFileDialog(".",
new String[]{"txt"},
new ByteArrayInputStream(
ep.getText().getBytes()),
sadrzajDatoteke.getName());
if(sadrzajDatoteke == null)
return;
imeDatoteke.setText(sadrzajDatoteke.getName());
} catch(Exception exc) {
throw new RuntimeException(exc);
}
}
}
}
public static void main(String[] args) {
JnlpBiranjeDatoteka bd = new JnlpBiranjeDatoteka();
bd.setSize(400, 300);
bd.setVisible(true);
}
} ///-
/ / :! gui/jnlp/biranjedatoteka.jnlp
<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec = "1.0+"
codebase="fi1e:C:/AAA-TIJ4/code/gui/jnlp"
href="biranjedatoteka.jnlp">
<information>
<title>Primer FileChooser aplikacije</title>
<vendor>Mindview Inc.</vendor>
<description>
Jnlp aplikacija za biranje datoteka
</description>
<description kind="short">
Pokazuje otvaranje, itanje i upisivanje u tekstualnu datoteku
</description>
<icon href="inindview.gif"/>
<off1ine-all owed/>
</information>
<resources>
<j2se version="1.3+"
href="http://java.sun.com/products/autodl/j2se"/>
<jar href="jnlpbiranjedatoteka.jar" download="eager"/>
</resources>
<application-desc
main-class = "gui.jnlp.JnlpBi ranjeDatoteka"/>
</jnlp>
///:-
N avedenu datoteku za pokretanje nai ete u datoteci izvornog koda ove knjige (m oe
se preuzeti na adresi w w w .M in d V iew .n et) pod im en om biranjedatoteka.jnlp (bez prvog
i poslednjeg reda), u istom direktorijum u kao JAR arhiva. Kao to vidite, radi se o XML
datoteci s jed n om oznakom <jnlp>. Ona im a nekoliko podelem enata, m anje-vie jasnih
po sebi.
Atribut spec elem enta jnlp saoptava klijentskom sistem u koja verzija JNLP-a m oe da
pokrene aplikaciju. Atribut codebase pokazuje na URL adresu na kojoj su resursi i dato-
teka za pokretanje. Ovde pokazuje na direktorijum lokalnog raunara, to je dobar nain
za testiranje ove aplikacije. N a d a m se da shvatate kako tu p u ta n ju n io ra tep ro m en iti tako da
pokazuje na odgovarajui direktorijum vaeg rac'unara tek tada e seprogram uitati. Atri-
but href specificira im e datoteke koju treba uitati.
Oznaka inform ation im a razne p od elem ente koji pruaju inform acije o aplikaciji.
Njih ita adm inistrativna konzola Java Web Start ili druga njoj ekvivalentna realizacija
JNLP-a koja instalira JNLP aplikaciju i om ogu u je korisniku da je pokrene s kom andne
liniie, pravi preice itd.
Svrha oznake resources slina je svrsi oznake <applet> u U'i iVft. datoteci. Podelem ent
j2se specificira verziju J2SE potrebnu za pokretanje aplikacije, a podelem ent jar JAR da-
toteku u kojoj je klasa arhivirana. Elem ent jar im a atribut download ije vrednosti eager
od n osn o lazv kazuju realizaciji JNLP-a da li pre pokretanja aplikacije m ora da uita celu
arhivu ili ne mora.
1110 Misliti na Javi
Atribut application-desc saoptava realizaciji JNLP-a koja klasa je izvrna klasa (ulaz-
na taka) JAR arhive.
D rugi koristan podelem ent oznake jnlp jeste oznaka security koje u gornjoj datoteci
nem a. Evo kako izgleda oznaka security:
<security>
<a11-permissions/>
< secu rity/>
//:! gui/jnlp/biranjedatoteka.html
<html>
Sledite uputstva iz JnlpBiranjeDatoteka.java za pravljenje
jnlpfi1echooser.jar, a zatim:
<a href="biranjedatoteka.jnlp">pritisnite ovde</a>
</html>
///: -
Dugotrajni zadaci
Jedna od osnovnih greaka pri programiranju grafikih korisnikih okruenja jeste upo-
treba rasporedivaa za izvravanje dugotrajnog zadatka. Sledi jednostavan primer:
//: gui/DugotrajanZadatak.java
// Loe projektovan program.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.*;
import static net.mindview.util.SwingKonzoia.*;
/ / : gui/DugotrZadKojiSeMozePrekinuti.java
// Dugotrajni zadaci u nitima.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.*;
import static net.mindview.util.SwingKonzola.*;
setLayout(new FlowLayout());
add(dl);
add(d2);
}
public static void main(String[] args) {
run(new DugotrZadKojiSeMozePrekinuti(), 200, 150);
}
} ///:-
//: net/mindview/util/StavkaZadatka.java
// Objekat tipa Future i Callable koji ga je napravio.
package net.mindview.util;
import j a v a . u t i l .concurrent.*;
//: net/mindview/util/MenadzerZadataka.java
// Upravljanje redom zadataka i njegovo izvravanje.
package net.mindview.util;
import j a v a .ut i1 .co nc u r r e n t .41;
import j a v a . u t i1.*;
// : gui/DugotrCallableKoj1SeMozePrekinuti.java
// Korienje Callable objekata za dugotrajne zadatke.
import javax.swing.*;
import java.awt.*;
Poglav[je 22: Grafika korisnika okruenja 1115
import java.awt.event.*;
import java.uti1.concurrent.*;
import net.mindview.util.*;
import static net.mindview.util.SwingKonzola.*;
public class
DugotrCallableKojiSeMozePrekinuti extends JFrame {
private JButton
dl = new JButtonC'Pokreni dugotrajan zadatak"),
d2 = new JButton("Ugasi dugotrajan zadatak"),
d3 = new JButton("Daj rezultate");
private MenadzerZadataka<String,CallableZadatak> menadzer =
new MenadzerZadataka<String,CallableZadatak>();
public DugotrCallableKojiSeMozePrekinuti() {
dl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Cal 1ableZadatak zadatak = new CallableZadatak();
menadzer.add(zadatak);
System.out.println(zadatak + " dodat u red za ekanje");
}
});
d2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for(String rezultat : menadzer.purge())
System.out.pri ntln (rezul tat);
}
});
d 3 .addActionListener(new ActionListener() {
public void actionPerformed(A*tionEvent e) {
// Primer poziva metode klase Zadatak:
for(StavkaZadatka<String,CallableZadatak> tt :
menadzer)
tt.zadatak.id(); // Nije potrebna eksplicitna konverzija tipa
for(String rezultat : menadzer.getResults())
System.out.println(rezultat);
}
/);
setLayout(new FlowLayout());
add(dl);
add (d2);
add (d3);
1116 Misliti na Javi
}
public static void main(String[] args) {
run(new DugotrCallableKojiSeMozePrekinuti(), 200, 150);
}
} ///: -
Kao to vidite, CallableZadatak radi isto to i Zadatak, sem to vraa i rezultat - u
ovom sluaju String identifikator zadatka.
Za reavanje istog problem a napisane su i n e-Sw ing uslune klase (koje se ne isporuu-
ju u standardnoj distribuciji Jave). To su SwingWorker (nai ete je na Sunovoj Web lo-
kaciji) i F oxtrot (na adresi http://foxtrot.sourceforge.net). D ok sam pisao knjigu, te klase
nisu bile m odifikovane tako da iskoriste m ehanizam Jave SE5 Callable/Future.
esto krajnjem korisniku valja dati nekakav vizuelni znak da se zadatak izvrava i oba-
vestiti ga dokle je odm aklo izvravanje. To se ob in o radi p om o u klasa JProgressBar ili
ProgressMonitor. U narednom prim eru upotrebiu ProgressMonitor:
}
}
);
}
} catch(InterruptedException e) {
monitor.close();
System.out.println(this + " prekinut");
return "Rezultat: " + this + " prekinut";
}
System.out.println(this + " zavren");
return "Rezultat: " + this + " zavren";
}
public String toString() { return "Zadatak " + id; }
};
public class NadziranDugotrCallable extends JFrame {
private JButton
dl = new JButton("Pokreni dugotrajan zadatak"),
d2 = new JButton("Ugasi dugotrajan zadatak"),
d3 = new JButton("Daj rezultate1');
private MenadzerZadataka<String,NadziranCallable> menadzer =
new MenadzerZadataka<String,NadziranCallable>();
public NadziranDugotrCallableO {
dl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
NadziranCal1able zadatak = new NadziranCallable(
new ProgressMonitor(
Nadzi ranDugotrCal1able.thi s ,
"Dugotrajan Zadatak", 0, 0)
);
menadzer.add(zadatak);
System.out.println(zadatak + " dodat u red za ekanje");
}
});
d2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for(String rezultat : menadzer.purge())
System.out.println(rezultat);
}
});
d3.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
for(String rezultat : menadzer.getResults())
System.out.println(rezultat);
)
});
setLayout(new F1owLayout());
add(dl);
add(d2);
1118 Misliti na Javi
add(d3);
}
public static void main(String[] args) {
run(rew NadziranDugotrCallable(), 200, 500);
}
} ///:-
Konstruktor klase NadziranCallable prim a objekat tipa ProgressM onitor kao argu-
m ent, a njegova m etoda c a ll( ) aurira ProgressM onitor svako pola sekunde. Imajte u
vidu da je NadziranCallable zaseban zadatak i da ne bi trebalo da neposredno kontrolie
ulazno/izlazne operacije, pa sam m onitoru m etod om SwingUtilities.invokeLater( )
podneo informacije o prom eni stepena napredovanja. U Sunovom udbeniku za Swing
(Swing Tutorial" na adresi http://java.sun.com ) prikazan je drugaiji pristup; tam o se
upotrebljava Swing Timer, koji proverava status zadatka i aurira m onitor.
Ako se na m onitoru pritisne dugm e cancel, m etoda m onitor.isC anceled( ) vraa true.
Ovde zadatak sam o poziva m etodu in terru p t( ) za sopstvenu nit, to e ga dovesti u od-
redbu catch gde se m onitor gasi m etod om cIo se( ).
Ostatak koda je uglavnom isti kao pre, sem to se pravljenje objekta tipa ProgressMo-
nitor odvija unutar konstruktora zadatka NadziranDugotrCallable.
Veba 33; (6) Izmenite DugotrCallableKojiSeMozePrekinuti.java tako da sve zadatke
izvrava paralelno, a ne sekvencijalno.
//: gui/ObojeneKutije.java
// Vizuelni prikaz vienitnog izvravanja.
// {Args: 12 50}
import javax.swing.*;
import java.awt.*;
import java.util.concurrent.*;
import java.util.*;
import static net.mindview.uti 1 .SwingKonzola.*;
ObojeneKutije konfigurie objekat tipa GridLayout tako da u svakoj dim enziji ima
brojcelija. Zatim dodaje odgovarajui broj ObKut objekata da popuni taj broj elija i sva-
kom prosleuje broj pauza. U m etodi m a in ( ) vidite da pauza i brojcelija imaju podrazu-
m evane vrednosti koje se m ogu menjati prosleivanjem argumenata na komandnoj liniji.
bve se radi u kiasi ObKut. Ona je izvedena iz klase JPanel i realizuje interfejs Runna-
ble, tako da svaki objekat tipa JPanel m oe biti nezavisan zadatak. Tim zadacim a upravlja
grupa niti ExecutorService.
1120 Misliti na Javi
Tekua boja elije je boja. Boje pravi konstruktor klase Color iji ulazni argum ent tre-
ba da bude 24-bitni broj koji u ovom sluaju pravim o nasum ino.
M etoda paintC om ponent( ) sasvim je jednostavna; ona sam o menja boju kako joj
kae boja i ceo pano (objekat tipa JPanel) popunjava njom .
U m etodi r u n ( ) postoji beskonana petlja koja objektu boja zadaje novu nasum ino
napravljenu boju i zatim poziva rep a in t( ) da bi je pokazala. Potom ta nit - prim enom
m etode sle e p () - odlazi na spavanje, za vrem e zadato na kom andnoj liniji.
Poziv m etode repaint( ) unutar m etod e r u n ( ) zasluuje panju. Na prvi pogled izgle-
da da pravim o m nogo niti i da se sve m oraju prebrojiti. M oda vam izgleda da tim e kri-
m o princip na osnovu koga sve zadatke treba poslati rasporeivau, od n osn o redu za
ekanje. M eutim , te niti zapravo ne m odifikuju deljeni resurs. Kada one p ozovu m etodu
rep ain t( ), ona ne preduzim a prebojavanje nego sam o postavlja odreeni indikator
,,zamrljano, kojim pokazuje da je ta oblast kandidat za prebojavanje kada rasporeiva
sledei put bude sprem an za tu akciju. Zato program ne prouzrokuje problem e sa Swin-
govim nitima.
Kada nit rasporeivaa dogaaja pozove m etodu p a in t( ), ona prvo pozove
p aintC om ponent( ), zatim paintB order( ) i onda paintC hildren( ). Ako u izvedenoj
kom ponenti elite da redefiniete m etodu p a in t( ), ne zaboravite da pozovete verziju
p a in t( ) iz osnovn e klase, tako da se uradi ta treba.
Upravo zato to je ovaj dizajn prilagodljiv i niti su vezane za svaki elem ent panoa,
m oete da eksperim entiete i pravite proizvoljan broj niti. (U praksi, ogranienje nam ee
broj niti s kojima vaa JVM m oe da izae na kraj.)
Ovaj program om oguuje zanim ljivo poreenje perform ansi, poto m oe da pokae
velike razlike u ponaanju i perform ansam a raznih realizacija JVM niti i raznih platformi.
Veba 34: (4) Izm enite program ObojeneKutije.java tako da prvo nasum ino prska ta-
ke (,,zvezde) po platnu, a zatim nasum ino menja boje tih ,,zvezda.
vizuelna predstava je esto izgled kom ponente u program u koji se izvrava. Zbog toga
deo postupka vizuelnog programiranja podrazum eva prevlaenje kom ponente s palete i
sputanje na obrazac. Alatka za pravljenje aplikacija pie kod dok vi prevlaite kom p o-
nente, a taj kod prouzrokuje pravljenje kom ponente u izvrnom programu.
Sam o prevlaenje kom ponente u obrazac obino nije dovoljno za kom pletiranje pro-
grama. esto m orate da prom enite neka njena obeleja, npr. boju, tekst koji sadri, bazu
podataka s kojom je povezana itd. Obeleja koja se m ogu prom eniti tokom projektovanja
oznaavaju se kao svojstva (engl. properties). Sa svojstvim a kom ponente m oete da radite
p om o u alatke za pravljenje aplikacija, a kada napravite program , svojstva kom p on en te
e biti snim ljena da bi se m ogla rekonstruisati kada se program pokrene.
D osad ste se sigurno navikli na ideju da objekat nem a sam o svojstva, ve i ponaanje.
Tokom projektovanja, ponaanje vizuelne kom ponente je delim ino predstavljeno doga-
ajim a. Dogaaj znai: Evo neega to bi se m oglo dogod iti kom p on en ti. O bino od lu -
ujete ta treba da se desi nakon dogaaja tako to povezujete kod sa odreenim
dogaajem .
Evo izuzetno vanog dela: alatka za pravljenje aplikacija koristi refleksiju za dinam iko
ispitivanje k om p on ente i otkrivanje svojstava i dogaaja koja kom ponenta podrava.
Kada to sazna, m oe da prikae svojstva i om ogu i a ih m enjate (uz snim anje stanja), ali
m oe i da prikae dogaaje. Po pravilu, vi dvaput pritiskate m iem , a alatka za pravljenje
aplikacija pravi kod i povezuje ga s tim dogaajem . U tom trenutku treba sam o da na-
piete kod koji se izvrava kada se desi dogaaj.
Dakle, alatka za pravljenje aplikacija obavlja najvei deo posla um esto vas. Zbog toga
se m oete usredsrediti na izgled programa i na to ta on treba da radi, a da se oslonite da
e ta alatka obaviti kom pletno povezivanje. Alatke za vizuelno programiranje izuzetno su
popularne zato to prim etno ubrzavaju pravljenje aplikacije. To posebno vai za korisni-
ka okruenja, ali esto i za druge delove aplikacije.
ta je zrno?
Kada se praina slegne, vidi se da je kom ponenta sam o blok koda koji je ob in o predsta-
vljen u obliku klase. Kljuno pitanjeje m ogunost alatke za pravljenje aplikacija da otkri-
va svojstva i dogaaje te kom ponente. Da bi napravio VB kom ponentu, programer je
m orao da pie prilino sloen kod u kom e je potovao odreena pravila za otkrivanje
svojstava i dogaaja. Delphi je bila alatka za vizuelno programiranje druge generacije. Taj
jezik je aktivno koristio vizuelno programiranje pa se vizuelna kom ponenta m n ogo lake
pravila. M edutim , izradu vizuelnih kom ponenata na najvii nivo dovela je Java, i to p o-
m ou zrna (engl. Java BcansJ, poto je zrno sam o klasa. Ne m orate pisati nikakav dodatni
kod niti koristiti specijalna proirenja jezika da bi neto postalo zrno. Zapravo, treba
sam o m alo dn prom enite nain im enovanja metoda. Na osn ovu imena m etode, alatka za
pravljenje aplikacija zna da li se radi o svojstvu, dogadaju ili obinoj m etodi.
U dokum entaciji za Javu ova pravila im enovanja pogreno su oznaena kao projektni
obrazac. To je nesporazum , poto su projektni obrasci dovoljan izazov i bez ove zbrke
(nai ete ih u knjizi T h in kin g in Patterns w ith Java koju m oete preuzeti s lokacije
1 122 Misliti na Javi
w w w .M ind V iew .n et). Zrna Jave nisu opisana projektnim obrascem , ve sam o pravilim a za
im enovanje, i to prilino jednostavnim :
1 . Da bi se neko svojstvo nazvalo xxx, ob in o treba napraviti dve metode: getX xx() i
setX x x ( ). Obratite panju na to da se prvo slovo iza get ili set autom atski pretvara
u m alo da bi se dobilo im e svojstva. Tip koji vraa m etoda get isti je kao tip argu-
m enta m etode set. Im e svojstva i tip ovi koje vraaju m etode get i set ne moraju da
b udu povezani.
2. Za svojstvo tipa boolean m oete da koristite prethodni pristup s m etodam a get i
set, ali um esto get m oete da koristite is.
3. O bine m etode zrna ne potuju prethodna pravila za dodeljivanje im ena, ali su jav-
ne.
4. Za dogaaje se koristi pristup ,,prijemnika iz biblioteke Swing. To je isto on o to
ste ve videli: m etodam a addBounceListener(BounceListener) i removeBounce-
Listener(BounceListener) obrauje se dogaaj BounceEvent. Najee e ugrae-
ni dogaaji i prijem nici zadovoljavati vae potrebe, ali m oete da napravite i
sopstvene dogaaje i prijem nike interfejse.
Ova saznanja m oem o da iskoristim o za pravljenje jednostavnog zrna:
//: frogbean:Frog.java
// Obino zrno Jave.
package frogbean;
import java.awt.*;
import java.awt.event.*;
class Spots {}
Prvo uoavate da je ovo obina klasa. Sva njena polja ob in o e biti privatna i m oi e
da im se pristupa sam o preko m etoda. U skladu s pravilom za im enovanje, svojstva su
jum ps, color, spots i jum per (obratite panju na prom enu veliine prvog slova im ena
svojstva). Iako je im e lokalnog identifikatora isto kao im e svojstva u prva tri sluaja, svoj-
stvo jum per pokazuje da im e svojstva nije uslov za korienje tano odreenog identifi-
katora za lokalne prom enljive. (Lokalne prom enljive za to svojstvo ak ne moraju ni da
postoje.)
Dogaaji koje generie ovo zrno su ActionEvent i KeyEvent, to zakljuujemo po
im enim a m etoda add i rem ove za rad s prijem nicim a. Konano, vidite da je obina m e-
toda cro a k ( ) i dalje deo zrna sam o zato to je javna, a ne zato to potuje pravilo dodelji-
vanja im ena.
//; gui/IspitivanjeZrna.java
// Ispitivanje Zrna klasom Introspector.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.lang.reflect.*;
import static net.mindview.util.SwingKonzola.*;
print("Javne metode:");
for(MethodDescriptor m : bi .getMethodDescriptorsO)
print(m.getMethod() .toSt r i n g O ) ;
print("======================");
print("Podrka za dogaaje:");
for(EventSetDescriptor e : bi .getEventSetDescriptorsO) {
print("Tip pri jemnika:\n 11 + e.getListenerType() .getNameO);
for(Method lm : e.getListenerMethodsO)
print.("Metoda pri jemnika:\n " + lm.getName());
for(MethodDescriptor lmd : e.getListenerMethodDescriptorsO)
print("Opis metode:\n " + lmd.getMethod());
Method dodavanje = e.getAddListenerMethod();
print("Metoda za dodavanje:\n " + dodavanje);
Method uklanjanje = e.getRemoveListenerMethod();
printC'Metoda za uklanjanje:\n " + uklanjanje);
print("====================");
}
}
class Ispitivac implements ActionListener {
public void actionPerformed(ActionEvent e) {
String ime = upit.getText();
C1ass<?>c = nul1;
try {
c = Class.forName(ime);
} catch(ClassNotEoundException ex) {
rezultati.setText("Ne mogu da pronaem" + ime);
return;
}
ispitaj(c);
public IspitivanjeZrnaO {
JPanel p = new JPanel();
p.setLayout(new FlowLayout());
p.add(new JLabel("Puno ime zrna:"));
p.add(upit);
cp.add(BorderLayout.NORTH, p ) ;
cp.add(new JScrollPane(rezultati));
Ispitivac isp = new Ispitivac();
upit.addActionListener(isp);
upi t .setText("frogbean.Frog");
// Prinudna provera
isp.actionPerformed(
new ActionEvent(isp, 0, ""));
}
public static void main(String[] args) {
run(new IspitivanjeZrnaO, 600, 500);
}
} ///:-
1126 Misliti na Javi
Tip svojstva:
Color
Ime svojstva:
color
Metoda za itanje:
public Color getColor()
Metoda za upisivanje:
public void setColor(Color)
Tip svojstva:
boolean
Ime svojstva:
jumper
Metoda za itanje:
public boolean isJumper()
Metoda za upisivanje:
public void setJumper(boolean)
Tip svojstva:
int
Ime svojstva:
jumps
Metoda za itanje:
public int getJumps()
Poglavlje 22: Grafika korisnika okruenja 1127
Metoda za upisivanje:
public void setJumps(int)
Tip svojstva:
frogbean.Spots
Ime svojstva:
spots
Metoda za itanje:
public Spots getSpots()
Metoda za upisivanje:
public void setSpots(Spots)
Javne metode:
public void setSpots(frogbean.Spots)
public void setColor(Color)
public void setJumps(int)
public boolean isJumper()
public frogbean.Spots getSpotsO
public void croak()
public void addActionListener(ActionListener)
public void addKeyListener(KeyListener)
public Color getColor()
public void setJumper(boolean)
public int getJumps()
public void removeActionListener(ActionListener)
public void removeKeyListener(KeyListener)
Podrka za dogaaje:
Tip prijemnika:
KeyLi stener
Metoda prijemnika:
keyTyped
Metoda prijemnika:
keyPressed
Metoda prijemnika:
keyReleased
Opis metode:
public void keyTyped(KeyEvent)
Opis metode:
public void keyPressed(KeyEvent)
Opis metode:
public void keyReleased(KeyEvent)
Metoda za dodavanje:
public void addKeyListener(KeyListener)
Metoda za uklanjanje:
public void removeKeyListener(KeyListener)
Tip prijemnika:
Acti onLi stener
1128 Misliti na Javi
Metoda prijemnika:
actionPerformed
Opis metode:
public void actionPerformed(ActionEvent)
Metoda za dodavanje:
public void addActionListener(ActionListener)
Metoda za uklanjanje:
public void removeActionListener(ActionListener)
Ovaj program otkriva najvei d eo svojstava koje vidi klasa Introspector dok na osno -
vu zrna pravi objekat tipa Beanlnfo. Prim etiete da su tip svojstva i njegovo im e nezavi-
sni. Obratite panju na to da su sva slova u im enu svojstva mala. (Jedino se odstupa kada
im e svojstva poinje s nekoliko uzastopnih velikih slova.) Zapamtite i to da se im ena m e-
toda kakva ovde vidite (npr. m etod e za itanje i upisivanje) zapravo dobijaju iz objekta
tipa M ethod koji se m oe koristiti za pozivanje odgovarajue m etode.
Spisak javnih m etoda sadri m etod e koje nisu povezane s nekim svojstvom ili dogaa-
jem , kakva je m etoda croak ( ), ali i o n e koje jesu povezane sa svojstvima i dogaajima. To
su sve m etode zrna koje m oete da pozovete iz programa, a alatka za pravljenje aplikacija
m oe ih sve prikazati dok piete program da bi vam olakala posao.
Konano, prim euje se da su dogaaji p otp u n o analizirani i razdvojeni na interfejs
prijemnika, njegove m etod e i m etod e za dodavanje i uklanjanje prijemnika. U osnovi,
kada im ate objekat tipa Beanlnfo, m oete da saznate sve to je vano o zrnu. M oete i da
pozivate m etode zrna, ak i ako nem ate nikakve druge inform acije osim ovog objekta (to
je jo jedna osobina refleksije).
Naprednije zrno
Sledei prim er je sam o neto m alo napredniji, mada je frivolan. To je objekat klase JPanel
koji iscrtava mali krug oko mia kad god se on pom eri. Kada pritisnete taster mia, re
Bang! se pojavljuje u sredini ekrana i pokree se prijem nik dogaaja.
M oete da prom enite sledea svojstva: veliinu kruga, boju, veliinu i re koja se pri-
kazuje kada se pritisne taster mia. Objekat BangBean takode ima sopstvene m etode ad-
dActionListener( ) i rem oveA ctionListener( ) p om ou kojih m oete da poveete zrno sa
svojim prijem nikom koji se pokree kada korisnik pritisne m iem . Sada bi ve trebalo da
um ete prepoznati podrku za svojstva i dogaaje:
//: bangbean:BangBean.java
// Grafiko zrno.
package bangbean;
import javax. swi ng
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.uti1.*;
Poglavlje 22: Grafika korisnika okruenja 1129
Prvo ete prim etiti da klasa BangBean realizuje interfejs Serializable. To znai da alat-
ka za pravljenje aplikacija m oe da uita sve inform acije o zrnu p om ou serijalizacije, na-
kon to projektant programa podesi vrednosti svojstava. Kaa se zrno napravi kao deo
izvrne aplikacije, snim ljena svojstva se rekonstruiu pa se dobija tano on o to ste pro-
jektovali.
U potpisu m etode addA ctionListener( ) vidite da ona m oe da generie izuzetak To-
oManyListenersException. To znai da je dogaaj jcdnosm eran, tj. da se sam o jedan pri-
jem nik obavetava o tom e da se desio. O b in o ete koristiti viesm erne dogaaje tako da
o dogaaju bude obaveteno vie prijem nika. M eutim , ovde ve uiazim o u tem e koje e
biti razm otrene u odeljku Zrna Jave i sinhronizacija. Jednosm ernim dogaajem zasad
em o zaobii ovaj problem .
Kada pritisnete taster mia, u zrnu se ispisuje tekst, a ako polje actionListener nije
null, pravi se nov objekat tipa ActionEvent i alje se prijem niku. Kad god se pom eri mi,
pam te se njegove nove koordinate i pozadina menja boju (uz brisanje teksta koji se nalazi
na pozadini, kao to ete videti).
Evo klase BangBeanTest koja om ogu u je testiranje zrna kao apleta ili aplikacije:
//: gui/BangBeanTest.java
// {Timeout: 5} U testiranju, ugasi nakon 5 sekundi
package bangbean.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.uti1 .*;
import static net.mindview.util.SwingKonzola.*;
Poglavlje 22: Grafika korisnika okruenja 1131
Ova klasa se nee koristiti kada se zrno nalazi u razvojnom okruenju, ali je korisna
kao nain za brzo testiranje svih zrna. BangBeanTest stavlja zrno BangBean u aplet, po-
vezujui s njini jednostavan prijem nik tipa ActionListener koji ispisuje broj ogaaja u
tekstualnom polju kad god se desi dogaaj. Alatka za izradu aplikacija obino pravi naj-
vei deo koda koji koristi zrno.
Kada ispitate ovo zrno Idasom IspitivanjeZrna ili ga stavite u razvojno okruenje koje
podrava zrna, prim etiete da ima m n ogo vie svojstava i akcija nego to se vidi u gor-
njem kodu. Razlog je to to je klasa BangBean izvedena iz klase JPanel, a JPanel je takoe
zrno, pa se prikazuju i njegova svojstva i dogadaji.
Veba 35: (6) Pronadite na Internetu i preuzm ite jednu ili vie besplatnih vizuelnih alatki
za pravljenje grafikih korisnikih okruenja, ili kupite neku. Saznajte ta je neophodno
da bi se zrno BangBean unelo i koristilo u tom okruenju.
//: gui/BangBean2.java
// Trebalo bi da svoja zrna ovako piete,
// kako bi mogla da se izvravaju u okruenju s vie niti.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import net.mindview.uti1 .SwingKonzola.*;
}
public synchronized Color getTextColor() { return tColor;}
public synchronized void setTextColor(Color newColor) {
tColor = newColor;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawOval(xm - cSize/2, ym - cSize/2, cSize, cSize);
}
// Ovo zrno ima vie prijemnika to se ee koristi
// od obavetavanja samo jednog prijemnika,
// kako je bilo uraeno u programu BangBean.java:
public synchronized void
addActionListener(ActionListener 1) {
actionListeners.add(l);
}
public synchronized void
removeActionListener(ActionListener 1) {
actionLi steners.remove(l);
}
// Pazite, ovo nije sinhronizovano:
public void notifyListeners() {
ActionEvent a = new ActionEvent(BangBean2.this,
ActionEvent.ACTION_PERFORMED, null);
ArrayLi st 1v = nul 1 ;
// Napravi povrnu kopiju spiska za sluaj
// da neko doda jedan prijemnik tokom
// pozivanja drugih prijemnika:
synchronized(this) {
lv = new ArrayList<ActionListener>(actionListeners);
}
// Obavesti sve metode prijemnike:
for(ActionListener al : 1v)
a l .actionPerformed(a);
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Graphics g = getGraphics();
g.setColor(tColor);
g.setFont(
new FontC'TimesRoman", Font.BOLD, fontSize));
int width = g.getFontMetricsO .stringWidth(text);
g.drwString(text, (getSize().width - width) / 2,
getSizeO .height/2);
g.disposeO;
noti fyListeners();
1134 Misliti na Javi
}
class MM extends MouseMotionAdapter {
public void mouseMoved(MouseEvent e) {
xm = e.getX();
ym = e.getY();
repaint();
}
}
public static void main(String[] args) {
BangBean2 bb2 = new BangBean2();
bb2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
System.out.println("ActionEvent'' + e ) ;
}
} );
bb2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
System.out.println("BangBean2 action");
}
});
bb2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
System.out.println("More action");
}
});
JFrame frame = new JFrameO;
frame.add(bb2);
run(bb, 300, 300);
}
} ///:-
Dodavanje rezervisane rei synchronized m etodam a jeste mala i laka izm ena. M eu-
tim , uoite da se u m etodam a addActionListener( ) i rem oveActionListener( ) prijem-
nici sada dodaju na listu i uklanjaju s nje kako bi zrno m oglo da ima vie prijemnika.
Vidi se da m etoda notifyL isteners( ) nije sinhronizovana. Nju m oe istovrem eno da
pozove vie niti. M ogue je i da m etode addA ctionListener( ) i rem oveActionListener( )
budu pozvane usred poziva m etode notifyListeners( ), to predstavlja problem jer ta m e-
toda prolazi kroz listu prijemnika. Da bi se taj problem ublaio, spisak je unutar sinhro-
nizovanog dela koda kloniran p om ou konstruktora spiska prijem nika ArrayList koji
kopira elem ente svog argumenta, pa se prolazi kroz klon. Tako se m oe raditi sa original-
nim spiskom prijemnika, a da se pri tom ne utie na tnetodu notifyListeners( ).
N i m etoda paintComponent( ) nije sinhronizovana. Odiuiti da li treba sinhro-
nizovati redefm isane m etode nije tako lako kao kad se sam o dodaju sopstvene m etode.
o\'oni prim eru ispostavlja se da m etoda p ain tC o m p o n en t( ) naizgled dobro radi, bila
sinhronizovana ili ne. Ali m orate uzeti u obzir i sledea pitanja:
Poglavlje 22: Grafika korisnika okruenja 1135
T. D a li ta m etoda menja stanje kritinih prom enljivih unutar objekta? D a biste otkrili
koje su prom enljive kritine, m orate utvrditi da li e ih druge niti u program u itati
ili im zadavati vrednosti. (U ovom sluaju, itanje i zadavanje gotovo se uvek oba-
vlja unutar sinhronizovanih m etoda, pa m oete da ispitate sam o njih.) M etoda
paintCom ponentO nem a takvih izm ena stanja.
2 . Da li m etoda zavisi od stanja tih kritinih promenljivih? Ako neka sinhronizovana
m etoda m odifikuje prom enljivu koju vaa m etoda koristi, trebalo bi da i nju
sinhronizujete. Na osnovu toga m ogli biste uoiti da prom enljivu cSize m odifikuju
sinhronizovane m etode, pa bi stoga m etodu paintC om ponent( ) trebalo sinhroni-
zovati. U ovom sluaju, m eutim , m oete da se zapitate: ta se najgore m oe d o-
goditi ako se sadraj prom enljive cSize prom eni tokom izvravanja m etode
p aintC om p onent( )? Ako zakljuite da to to se m oe desiti nije tako strano, a uz
to je i prolazno, m oete da ostavite m etodu p aintC om ponent( ) nesinhronizovanu
kako biste izbegli dodatne reijske trokove koje izaziva pozivanje sinhronizovane
m etode.
3. Da li je verzija m etode u osnovnoj klasi sinhronizovana? M etoda paintC om po-
nent( ) nije sinhronizovana u osnovnoj klasi. To nije ba besprekoran argum ent
nego sam o povod za razmiljanje. U ovom sluaju, recim o, postoji jedno polje (cSi-
ze) koje m odifikuje sinhronizovana m etoda, a njem u pristupa m etoda paintCom-
p o n e n t( ), pa je to m oglo a izm eni situaciju. Imajte u vidu, m eutim , da se atribut
synchronized ne nasleuje - znai, ukoliko je neka m etoda sinhronizovana u os-
novnoj klasi, ona nepostajc autom atski sinhronizovana u redefinisanoj verziji izve-
dene klase.
4. M etode paint( ) i paintComponent( ) moraju biti najbre m ogue. Izuzetno se
preporuuje korienje svega to iz njih uklanja reijske trokove, pa ako smatrate
da te m etode treba da sinhronizujete, to m oe biti znak loeg projekta.
Kod za testiranje unutar m etode m a in ( ) drugaiji je nego onaj u program u BangBe-
anTest, kako bi se pokazala sposobnost klase BangBean2 da o dogadajim a obavetava
vie prijemnika.
Pakovanje zrna
Pre nego to se zrno uveze u vizuelnu alatku, mora se staviti u standardan paket za zrna,
a to je JAR arhiva koja sadri sve klase zrna i m anifest datoteku. M anifest datoteka je tek-
stualna datoteka odreenog oblika. Za zrno BangBean, ta datoteka izgleda ovako:
Manifest-Version: 1.0
Name: bangbean/BangBean.class
Java-Bean: True
Prvi red prikazuje broj verzije manifest datoteke koji, do daljeg obavetenja iz kom pa-
nije Sun, iznosi 1.0. Drugi red (prazni redovi se zanemaruju) navodi datoteku Bang-
Bean.class, a trei kae ,,To je zrno. Bez treeg reda, alatka za pravljenje programa ne bi
prepoznavala klasu kao zrno.
1136 Misliti na Javi
O ovom e uglavnom ne m orate da vodite rauna, a ako neto menjate, m oete sam o da
prom enite prvobitnu manifest datoteku i da p on ovo pozovete alatku jar da biste napra-
vili novu arhivu. U JAR arhivu m oete da dodate i nova zrna tako to ete informacije o
njima staviti u m anifest datoteku.
D obro je da se svako zrno stavi u sopstveni poddirektorijum , jer kada pravite arhivu
m oete da arhivirate ceo direktorijum. Vidi se da i Frog i BangBean imaju sopstvene pod-
direktorijume.
Kada pravilno sm estite zrno u arhivu, m oete da ga unesete u alatku za izradu progra-
ma koja podrava zrna. Nain na koji se to radi razlikuje se od alatke do alatke, ali kom-
panija Sun obezbeuje besplatno okruenje za testiranje Javinih zrna koje se zove Bean
Builder. (M oete ga preuzeti s lokacije h ttp ://ia va .iu n .co m /b ea n s.) Da biste sm estili zrno
u Bean Builder, kopirajte njegovu JAR datoteku u odgovarajui poddirektorijum .
Veba 36: (4) D odajte datoteku Frog.class u manifest datoteku kao to je prikazano u
ovom poglavlju i pokrenite program jar da biste napravili JAR arhivu koja sadri zrna
Frog i BangBean. Zatim sa Interneta preuzm ite i instalirajte Bean Builder ili upotrebite
svoju alatku za pravljenje programa koja podrava zrna. Dodajte novu arhivu u to okru-
enje kako biste m ogli da testirate ta dva zrna.
Poglav[je 22: Grafika korisnika okruenja 1137
Vie o zrnima
M nogi su pisali o zrnim a Jave; na primer, Flliote Rusty Harold autor je knjige JavaBeans
(IDG , 1998).
Alternative za Svving
Iako je biblioteka Swing GKO alatka koju preporuuje Sun, to nikako ne znai da ne
postoie i d ru g e alatke za pravljenje gralikih korisnikih okruenja. Dve vane alternative
su Flash kom panije A dobe, u kojem se za pravljenje klijentskih GKO preko Weba koristi
Flashov sistem za programiranje Flex, i biblioteka otvorenog izvornog koda Eclipse Stan-
dard W idget Toolkit (SW T) za aplikacije nam enjene stonim raunarima.
1 138 Misliti na Javi
Zdravo, Flex
Proitajte ovaj MXML kod, koji definie korisniko okruenje (imajte u vidu da prvog i
poslednjeg reda nema u kodu koji preuzim ate u paketu izvornog koda ove knjige):
giii/flex/zdravoflexl.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xml n s :mx="http://www.mac romedi a .com/2003/mxml1111
backgroundCol or="#ffffff">
<mx:Natpis id="output" tekst="Zdravo, Flex!" />
</mx:Applicati on>
III--
M XML datoteke su XML dokum enti, te stoga poinju op isom XML verzije i kodi-
ranja; to su atributi version i encoding. Krajnji spoljanji MXML elem ent je Application
koji se vizuelno nalazi na vrhu i logiki je kontejner za Flex korisniko okruenje. Unutar
elem enta Application rnoete eklarisati oznake koje predstavljaju vizuelne kontrole kao
to je gornji elem ent Natpis. Kontrole uvek sm etam o u kontejnere, a kontejner pored
ostalih m ehanizam a kapsulira i rasporediva (engl. layout tnanager) koji upravlja raspo-
redom kontrola u kontejneru. U najjednostavnijem sluaju, kao u gornjem prim eru, Ap-
plication deluje kao kontejner. Podrazum evani rasporediva elem enta Application
smeta kontrole vertikalno niz prozor, redosledom kojim su bile deklarisane.
ActionScript je verzija ECMAScripta, ili JavaScripta, koja p otp u n o lii na Javu i p o-
drava klase i strogu proveru tipova, kao i dinam iko pravljenje skriptova. Kada prim eru
dodam o skript, uveem o ponaanje. Ovde MXML kontrola Script sm eta ActionScript
neposredno u MXML datoteku:
//:! gui/flex/zdravoflex2.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.macromedia.com/2003/mxml"
backgroundColor="#ffffff">
< m x :Script>
< ! [CDATA[
function update0utput() {
output.tekst = "Zdravo! " + input.tekst;
}
]]>
</mx:Script>
< m x:TextInput id="input" width="200"
change="updateOutput()" />
<mx:Natpis id="output" tekst="Zdravo!" />
</mx:Appli cati on>
///: -
11 N aveena adresa vie nije do stu p n a . Vie inform acija o M X M L-u nai ete na adresi w\vw\adobe.cotn/
licvnc t/flex/n ixrnl_as.htm l
1140 Misliti na Javi
Textlnput kontrola prima korisnikov unos, a Natpis (ve tokom unosa) prikazuje une-
sene podatke. Vodite rauna o tom e da je atribut id svake kontrole u skriptu dostupan kao
im e promenljive, pa skript m oe da referencira instance M XM L oznaka. U polju Text-
Input vidite da je atribut change povezan s funkcijom updateO utput( ) - dakle, ta funk-
cija se poziva kad god se desi bilo kakva prom ena (engl. change).
Prevoenje MXML-a
Najbolje je da sa adrese w w w .adobe.com /products/flex/trial preuzm ete besplatnu probnu
verziju Flexa.12 Taj proizvod postoji u vie izdanja - od besplatnih probnih do serverskih
za velika preduzea a za razvoj Flex aplikacija A dobe nudi jo neke alatke. Poto se
izdanja stalno menjaju, proitajte pojedinosti na Web lokaciji proizvoaa Adobe.
Takoe, imajte u vidu da ete m oda m orati da m odifikujete datoteku jvm.config u
direktorijum u bin Flexove instalacije.
Za prevoenje MXML koda u Flashov bajtkod im ate dve opcije:
1. M XML datoteku m oete sm estiti u neku Java Web aplikaciju, pored JSP i HTML
stranica u WAR datoteci, i dati da se u vrem e izvravanja zahtevi za .m x m l datote-
kom prevode kad god bilo koji ita zatrai URL adresu tog MXML dokum enta.
2 . MXML datoteku m oete prevesti p om o u Flexovog prevodioca m xm lc koji se po-
kree s kom andne linije.
Prva opcija, prevoenje na W ebu u vrem e izvravanja, sem Flexa zahteva i neki konte-
jner servleta (kao to je A pacheovT om cat). WAR datotekekontejnera servleta moraju biti
aurirane p o m o u informacija iz Flexove konfiguracije, kao to su mapiranja servleta do-
data deskriptoru w eb.xm l, i m oraju obuhvatati Flexove JAR datoteke - sve se to obavlja
autom atski kada instalirate Flex. Nakon konfigurisanja WAR datoteke, MXML datoteke
m oete sm estiti u Web aplikaciju i zatraiti URL adresu tog dokum enta bilo kojim i-
taem . Flex e prevesti aplikaciju nakon prvog takvog zahteva, slino kao u m odelu Javi-
nih serverskih stranica (JSP), i p otom e isporuivati prevedeni i keirani SWF unutar
HTM L ljuske.
U drugoj opciji server nije potreban. SWF datoteke pravite pozivom Flexovog prevo-
dioca m x m lc na kom andnoj liniji. Njih m oete upotrebiti kako god elite. Izvrna dato-
teka m xm lc je u direktorijum u b in FIexove instalacije, i kada je pozovete bez argumenata,
ispisae spisak validnih opcija u kom andnoj liniji. O bino se lokacija Flexove biblioteke
klijentskih kom ponenata zadaje kao vrednost opcije -flexlib, ali u veom a jednostavnim
sluajevim a kao to su dva prethodna, Flexov prevodilac e pretpostaviti gde je biblioteka
kom ponenata. Zato prva dva prim era m oete prevesti ovako:
mxmlc.exe zdravoflexl.mxml
mxmlc.exe zdravoflex2.mxml
Tim e se proizvodi datoteka z d rav oflex 2 .sw f koja se m oe pokrenuti u Flashu ili sm e-
stiti uz HTM L na neki HTTP server. (N akon uitavanja Flasha u ita Weba, esto je do-
voljno dvaput pritisnuti SWF datoteku da biste je pokrenuli u itau.)
MXML i ActionScript
MXML je deklarativna stenografija za ActionScript klase. Za svaku MXML oznaku posto-
ji istoim ena ActionScript klasa. Kada Flexov prevodilac leksiki analizira (ralanjuje i
razreava) MXML, prvo transform ie XML u ActionScript i uitava referencirane Ac~
tionScript klase, a potom prevodi i povezuje taj ActionScript u SWF datoteku.
Celu Flex aplikaciju m oete napisati u sam om A ctionScriptu, a da uopte ne u po-
trebite MXML. Dakle, MXML nije neophodan, ali je pogodan. MXML se ob in o upotre-
bljava za deklarisanje kom ponenata korisnikog okruenja kao to su kontejneri i
kontrole, dok se ActionScript i Java koriste za obradu dogaaja i ostalu klijentsku logiku.
Imate m ogunost da pravite sopstvene MXML kontrole i da ih referencirate u Ac-
tionScript klasama. Postojee MXML kontejnere i kontrole m oete da kom binujete u no-
vom MXML dokum entu koji m oe biti referenciran kao oznaka u drugim MXML
dokum entim a. Vie informacija o tom e potraite na Web lokaciji kom panije Adobe.
Kontejneri i kontrole
V izuelno jezgro biblioteke Flex kom ponenata je skup kontejnera koji upravljaju raspore-
dom i niz kontrola koje idu 11 te kontejnere. M eu kontejnerim a su panoi, vertikalni i ho-
rizontalni pravougaonici, pravougaonici koji se slau kao ploice, pravougaonici koji se
ire poput harm onike, pravougaonici sa unutranjom m reom , tabele itd. Kontrole su
spravice (engl. widgets) korisnikog okruenja kao to su dugm ad, tekstualna polja, kli-
zai, kalenari, tabele podataka itd.
Sada em o napraviti Flex aplikaciju koja prikazuje i ureuje listu audio datoteka. Vi-
d e e t a p r i m e r e kontejnera, kontrola i otkriete kako a ih iz Flasha poveete s Javom.
Na poetak MXML datoteke postaviem o kontrolu DataGrid (koja spada u sofistici-
ranije Flex kontrole) u kontejner tipa Panel:
//:! gui/f1ex/pesme.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application
1142 Misliti na Javi
xmlns:mx="http://www.macromedi a .com/2003/mxml"
backgroundColor="#B9CAD2" pageTitle="Flex program za rukovanje pesmama"
initialize="dajPesme()">
<mx:Script source="skriptPesama.as" />
<mx:Style source="sti1ovi Pesama.css"/>
<mx:Panel id="panoListePesama"
ti tleStyleDeclarati on="headerText"
title="Flex MP3 biblioteka">
< m x :HBox verticalA1i gn="bottom">
<mx:DataGrid id="tabelaPesama"
c e n P r e s s = izaberiPesmu(dogadjaj)" rowCount="8">
<mx:columns>
<mx:Array>
<mx:DataGri dColumn columnName="naslov"
headerText="Naslov pesme" width="120" />
< mx :DataGri dColumn columnName="i zvodja"
headerText="Izvodja" width="180" />
<mx:DataGridColumn columnName="album"
headerText="Album" width="160" />
</mx:Array>
</mx:columns>
</mx:DataGrid>
<mx:VBox>
<mx:HBox height="100" >
<mx:Slika id="sl ikaAlbuma'' source=""
height="80" width="100"
mouseOverEffect="promVelPovecaj"
mouseOutEffect="promVelSmanji" />
<mx:TextArea id="podaciOPesmi"
styleName="boldText" height="100%" width="120"
vScrol1Policy="off" borderStyle="none" />
</mx:HBox>
<mx:MediaPlayback id="plejerZaPesme"
contentPath=""
mediaType="MP3"
height="70"
width="230"
control 1erPolicy="on"
autoPlay="false"
visible="false" />
< / mx:VBox>
</mx:HBox>
<mx:ControlBar horizontalAlign="right">
<mx:Button id="dugme0svezi Pesme"
1 abel ="0svei pesme" w M t h = "100"
toolTip=" Osvei listu pesama"
cl ick="uslugaPesama.dajPesmeO" />
</mx:ControlBar>
Poglavjje 22: Grafika korisnika okruenja 1143
</mx:Panel>
<mx:Effect>
<mx:PromVel name="promVelPovecaj" heightTo="100"
duration="500"/>
<mx:PromVel name="promVelSmanji" heightTo="80"
duration="500"/>
</mx:Effect>
<mx:RemoteObject id=''uslugaPesama"
source="gui.f1ex.UslugaPesama"
rezul tat="onPesme(dogadjaj.rezultat)"
fault="alert(dogadjaj.fault.faultstring, 'Greka')">
<mx:method name="dajPesme"/>
</mx:RemoteObject>
</mx:Application>
///:-
Kontejner tipa DataGrid sadri ugneene oznake za svoj niz kolona. Svaki atribut ili
ugneeni elem ent na kontroli odgovara nekom svojstvu, dogadaju ili kapsuliranom ob-
jektu pripadne ActionScript klase. Taj DataGrid ima atribut id ija je vrednost tabelaPe-
sama, pa ActionScript i MXML oznake m ogu programski da referenciraju tu tabelu
koristei tabelaPesama kao im e prom enljive. DataGrid eksponira m n ogo vie svojstava
nego to sam ja ovde pokazao; celokupni API za MXML kontrole i kontejnere m oete nai
na adresi http://livcdocs.adobe.eom /flex/l/asdocs.
Iza kontejnera DataGrid sledi VBox sa elem entom Slika koji pokazuje prednju stranu
album a i podatke o pesm i, kao i s kontrolom MediaPlayback za reprodukciju MP3 dato-
teka. U ovom primeru sadraj se em ituje u realnom vrem enu, da bi se smanjila prevedena
SWF datoteka. Ukoiiko slike, audio i video datoteke ugradite u Flex aplikaciju um esto da
ih em itujete u realnom vrem enu, te datoteke postaju deo prevedenog SWF-a i isporuuju
se zajedno s korisnikim okruenjem; u tom sluaju, u vrem e izvravanja nem a em ito-
vanja u realnom vrem enu na zahtev.
Flash plejer sadri ugraene kodeke za reprodukciju i em itovanje audio i video dato-
teka raznih formata u realnom vrem enu. Flash i FIex podravaju najkorienije form ate
slika na Webu, a Flex um e da konvertuje datoteke skalabilne vektorske grafike (SVG) u
SWF resurse koji se m ogu ugraditi u Flex klijentc.
Efekti i stilovi
Flash plejer iscrtava grafiku vektorski, pa u vrem e izvravanja m oe da obavi veom a iz-
raajne transformacije. Flexovi efekti om oguuju da steknem o uvid u takve animacije.
Efekti su transformacije koje p om ou MXML sintakse m oete prim eniti na kontrole i
kontejnere.
Oznaka Ettect prikazana u prethodnom MXML kodu proizvodi dva rezultata: prva
ugnedena oznaka dinam iki poveava sliku kada se mi nalazi iznad nje, a druga je di-
nam iki sm anjuje kada mi ode s nje. Ti efekti se prim enjuju na dogadaje mia dostupne
za kontrolu Slika nazvanu slikaAlbuma.
1144 Misliti na Javi
//:! gui/flex/stiloviPesama.css
.headerText {
font-family: Arial, "_sans";
font-size: 16;
font-weight: bold;
}
,boldText {
font-family: Arial, "_sans";
font-size: 11;
font-weight: bold;
}
III--
Aplikacija biblioteke pesama uvozi tu datoteku i upotrebljava je preko oznake Style u
MXML datoteci. Nakon uvoza opisa stilova, njegove deklaracije se m ogu prim eniti na
Flex kontrole u MXML datoteci. Na prim er, deklaraciju boldText iz opisa stilova upotre-
bljava kontrola TextArea iji je identifikator (id) podaciOPesm i.
Dogaaji
Korisniko okruenje je maina stanja; ono obavlja radnje kada se m enja stanje. U Flexu
se te prom ene prijavljuju pom ou dogaaja. Flexova biblioteka klasa sadri m notvo na-
jrazliitijih kontrola koje podravaju m notvo dogaaja za sve aspekte kretanja mia i ko-
rienja tastature.
Prim era radi, atribut click elem enta Button predstavlja jedan od dogaaja dostupnih
za tu kontrolu. Vrednost dodeljena atrib u tu click m oe biti neka funkcija ili um etnut
skript. Prim era radi, u gornjoj MXML datoteci, elem ent ControlBar sadri dugm e-
OsveziPesme za osveavanje liste pesama. Iz oznake vidite da dogaaj click izaziva poziv
m etode uslugaPesam a.dajPesm e(). U tom prim eru, dogaaj click dugm eta Button re-
ferencira RemoteObject (udaljeni objekat) koji odgovara toj Java metodi.
Povezivanje s Javom
Oznaka RemoteObject na kraju MXML datoteke uspostavlja vezu sa spoljnom Java kla-
som, gui.flex.UslugaPesama. Pom enuti Flex klijent - m etodom dajPesm e() te Java klase -
pribavlja podatke za DataGrid. Da bi to m ogao da radi, m ora izgledati kao usluga -k ra jn ja
Poglavlje 22: Grafika korisnika okruenja 1145
taka s kojom klijent moe da razmenjuje poruke. Usluga definisana u oznaci RemoteOb-
ject im a atribut source koji naznauje Java klasu oznake RemoteObject, i specificira Ac-
tionScript povratnu funkciju, on P esm e(), koja e biti pozvana kada se Java m etoda vrati.
U gneena oznaka m ethod deklarie m etodu dajPesm e(), to tu Java m etodu ini dostup-
n om ostatku Flex aplikacije.
U Flexu se svi pozivi usluga vraaju asinhrono, preko dogaaja koji p rouzrokuju (iza-
zivaju) te povratne funkcije. U sluaju greke, isti RemoteObject prikazuje dijalog
upozorenja.
M etodu dajPesm e() sada m oem o pozvati iz Flasha pom ou ActionScripta:
uslugaPesama.dajPesme();
Zbog konfiguracije MXML-a tim e e biti pozvana m etoda dajPesm e() u klasi Usluga-
Pesama:
//: gui/flex/UslugaPesama.java
package gui,flex;
import java.uti1.*;
//: gui/flex/Pesma.java
package gui.flex;
//: gui/flex/skriptPesama.as
function dajPesme() {
uslugaPesama.dajPesmeO;
}
function izaberiPesmu(dogadjaj) {
var pesma = tabelaPesama.getItemAt(dogadjaj.itemIndex);
pri kazi podatkeOPesmi(pesma);
}
function prikazipodatkeOPesmi(pesma) {
po da c i O P e s m i .tekst = pesma.naslov + nevvline;
podaciOPesmi.tekst += pesma.izvodjac + newline;
podaciOPesmi.tekst += pesma.album + newline;
slikaAlbuma.source = pesma.urlS1ikeNaAlbumu;
Poglavlje 22: Grafika korisnika okruenja 1147
plejerZaPesme.contentPath = pesma.urlNosacaZvuka;
plejerZaPesme.visible = true;
}
function onPesme(pesme) {
tabelaPesama.dataProvider = pesme;
) ///:-
Da bism o obradili izbor D ataG rid elija, atrib u t dogaaja cellPress dodajem o dekla-
raciji elem enta D ataG rid u MXML datoteci:
<mx:Slider id="mojKlizac"/>
<mx:Text tekst="{moj K1 i z a c . v a l ue}"/>
Podatke povezujete kada smestite reference u vitiaste zagrade. Sve u n u tar tih vitia-
stih zagrada Flex sm atra izrazom koji treba izraunati.
Vrednost prve kontrole, elem enta Slider (klizaa), prikazuje druga kontrola - jedno
tekstualno polje. S prom enom vrednosti klizaa, svojstvo tekst tekstualnog polja auto-
matski se aurira. Na taj nain, program er ne m ora da obrauje dogaaje prom ena vred-
nosti elem enta Slider da bi aurirao tekstualno polje.
Ima i sofisticiranijih kontrola, kao to su Tree (stablo) i DataGrid u aplikaciji biblio-
teke pesama. Te kontrole imaju svojstvo dataprovider koje olakava povezivanje s kolek-
cijama podataka. A ctionScript funkcija on P esm e() prikazuje kako je m etoda
UslugaPesam a.dajPesm ef) povezana sa svojstvom dataprovider Flexovog elementa Da-
taG rid. l\ao to je deklarisano u oznaci RemoteObject MXML datoteke, tu povratnu
funkciju poziva A ctionScript kada se Java m etoda vrati.
Sofisticiranija prim ena sloenijeg m odela podataka, kao to je in tran et aplikacija koja
upotrebljava objekte za prenos podataka (Data Transfer Objects) ili dostavljae poruka
1148 Misliti na Javi
Izgradnja i primena
U prethodnim prim erim a mogli sm o da se provuem o bez indikatora -flexlib na kom an-
dnoj liniji, ali da bism o preveli ovaj program , indikatorom -flexlib m oram o specificirati
mesto datoteke flex-config.xml. Sledea kom anda je prikladna za m oju instalaciju, a vi
ete m orati da je m odifikujete u skladu sa sopstvenom konfiguracijom. (Kom anda se pie
u jednom redu koji se zbog duine nastavlja i u narednom ):
//:! gui/flex/bui1d-command.txt
mxmlc -flexlib C:/"Program Files"/Adobe/Flex/jrun4/servers/default/flex/
WEB-INF/flex pesme.mxml
///-
Ta e kom anda izgraditi aplikaciju u obliku SWF datoteke koju moete prikazati u i-
tau Weba, ali poto u datoteci za istribuciju koda ove knjige nem a ni MP3 datoteka niti
JPG slika, kada pokrenete aplikaciju neete uti nijednu pesm u niti ete videti om ote al-
bum a, nego sam o osnovnu stru k tu ru (engl. fram eivork).
Pored toga, m orate konfigurisati neki server da biste iz Flex aplikacije mogli da kom u-
nicirate s Java datotekam a. Flexov probni paket obuhvata i server JRun, a njega nakon
instalacije Flexa m oete pokrenuti bilo koristei menije operativnog sistema, bilo s ko-
m andne linije:
Proverite da li je server uspeno p o k ren ut tako to ete u itau Weba otvoriti http://lo-
calhost:8700/samples i p r ik n z a ti r n z n e u z o r k e (engl. samplcs). To ie i d o b n r nnin za u p o -
znavanje m ogunosti Flexa.
Umesto da aplikaciju prevodite na kom andnoj liniji, moete da je prevedete posredst-
vom servera. To se radi tako to izvorne datoteke pesama, CSS opise stilova itd. smestite
u direktorijum jrun4/servers/default/flex i pristupite im u itau Weba otvaranjem adre-
se http://localhost:8700/flex/pesm e.m xm l.
Poglavlje 22: Grafika korisnika okruenja 1 149
Instaliranje SWT-a
Za SWT aplikacije potrebno je da preuzm ete i instalirate SWT biblioteku projekta Eclip-
se. Izaberite neki od preslikanih servera na lokaciji www.eclipse.org/dow nloads/. Sledite
veze do tekueg builda Eclipsea i pronaite kom prim ovanu datoteku ije ime poinje sa
swt i sadri ime vae platform e (na prim er, win32). U toj datoteci nai ete swt.jar. Da-
toteku swt.jar najlake ete instalirati ukoliko je smestite u direktorijum jre/lib/ext (jer u
tom sluaju neete m orati da m enjate svoju p u tan ju klasa). Kada dekom prim ujete biblio-
teku SWT, m oda ete nai jo datoteka koje treba instalirati na m estim a odgovarajuim
za vau platform u. Na prim er, W in32 distribucija obuhvata i DLL datoteke koje treba
smestiti negde u java.Iibrary.path. (O bino je ta putanja jednaka onoj koju opisuje si-
stemska prom enljiva PATH, ali stvarnu vrednost java.Iibrary.path moete saznati po-
m ou program om object/ShowProperties.java). Kada to uradite, trebalo bi da moete
transparentno da prevodite i pokreete SWT aplikacije, kao sve druge Java programe.
D okum entacija za SWT preuzim a se zasebno.
D ruga m ogunost je da instalirate program za ureivanje teksta Eclipse; on obuhvata
i SWT i SWT dokum entaciju koju m oete prikazati pom ou Eclipseovog sistema pomoi.
Zdravo, SW T
Ponim o najjednostavnijom m oguom aplikacijom u stilu zdravo sviina":
//: swt/ZdravoSWT.java
// {Requires: o r g . e c l i ps e. sw t. wi dge ts.D i s p l a y ; Morate
// instalirati SWT biblioteku s lokacije http://www.eclipse.org }
import org.eclipse.swt.widgets.*;
//: swt/ljuskeSuGlavniProzori.java
import org.eclipse.swt.widgets.*;
Kada pokrenete ovaj program , dobiete deset glavnih prozora. Zbog naina na koji je
program napisan, ako zatvorite bilo koji od tih prozora, zatvoriete i sve ostale.
I SWT koristi rasporeivae - razliite od onih u Svvingu, ali iste u principu. U nared-
nom neznatno sloenijem prim eru dodaem o ljusci tekst rezultata m etode
S y stem .g e tP ro p ertie s():
//: swt/SvojstvaKlaseDisplay.java
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
import java.io.*;
1juska.setLayout(new FillLayout());
Text tekst = new Text(ljuska, SWT.WRAP | SWT.V_SCROLL);
StringWriter svojstva = new StringWriter();
System.getProperti e s ().1i st(new Pri ntWri ter(svojstva));
tekst.setText(svojstva. t o S t r i n g O ) ;
1juska.open();
wh i1e (!1juska.isDisposed())
i f (!prikaz.readAndDi spatch())
p r i k az. s lee pO ;
prikaz.disposeO;
}
} III--
U SW T-u svi videti m oraju im ati roditeljski objekat opteg tipa C o m p o site koji kon-
struktoru videta m orate proslediti kao prvi argum ent. To vidite u k o n struktoru klase
Text kojem je prvi argum ent ljuska. Gotovo svi konstruktori prim aju i indikatorski argu-
m ent pom ou kojega moete zadati proizvoljan broj direktiva u vezi sa stilom , u zavisno-
sti od toga ta videt zahteva. Sve direktive u vezi sa stilom podvrgavaju se logikoj
disjunkciji po bitovim a (operator I), kao u preth od no m prim eru.
Prilikom pravljenja T e x t() objekta dodao sam indikatore stila koji prelam aju tekst
(engl. w rap) i autom atski m u dodaju vertikalnu traku za pom eranje (engl. scroll bar), ako
treba. Videete da se u SWT-u m nogo toga radi pom ou konstruktora; m noge atribute
videta teko je iii nem ogue menjati sem pom ou konstruktora. U dokum entaciji vide-
tovog konstruktora uvek m orate proveriti koji su dozvoljeni indikatori. Neki konstrukto-
ri zahtevaju indikatorski argum ent ak i kada u dokum entaciji nem aju nijedan
dozvoljen" indikator. Time se om oguuje budue proirenje, a da se interfejs ne menja.
Izbegavanje redundantnosti
Pre nego to nastavimo, naveemo ta m orate da uradite u svakoj SWT aplikaciji.
U SWT-u uvek m orate da napravite prikaz tj. objekat klase Display, od tog prikaza na-
pravite ljusku tj. objekat kiase Shell, napiete petlju rea d A n d D isp a tc h () itd. Naravno, u
nekim posebnim sluajevima to ne m orate da radite, ali o n i su toliko retki da se isplati
sabrati sav taj kod u jedan program i izbei ponavljanje, kao to sm o za Swing uradili u
program u net.mindvievv.util.SvvingKonzoIa.
N ateraem o svaku aplikaciju da se usaglasi sa interfejsom :
//: swt/util/SWTAplikacija.java
package swt.uti1 ;
import org.eclipse.swt.widgets.*;
Aplikaciji se predaje objekat tipa C om posite (ija je Shell potklasa), pom ou kojeg ap-
likaja m etodom createC ontents() m ora da napravi sav svoj sadraj. U odgovarajuem
trenutku, SW TKonzola.run() poziva m etodu createC ontents(), zadaje veliinu Ijuske u
skladu sa argum entom koji je korisnik prosledio m etodi r u n (), otvara tu Ijusku, pokree
petlju dogaaja i na kraju uklanja Ijusku kada program zavri s radom :
//: swt/util/SWTKonzola.java
package swt.uti1;
import org.eclipse.swt.widgets.*;
Pored ve navedenog, tim e se na naslovnoj traci ispisuje im e klase kojoj pripada SW-
TAplikacija i zadaje vrednost param etara sirina i visina za ljusku tipa Shell.
N apisaem o varijaciju program a SvojstvaKlaseDisplay.java koji pom ou objekta tipa
SWTKonzoIa prikazuje sistemsko okruenje:
//: swt/PrikaziSistemskoOkruzenje.java
import swt.uti1 .*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
import java.util.*;
Meniji
Prikazaem o osnovne menije tako to e sledei prim er uitati sopstveni izvorni kod i
razdeliti ga na rei, a zatim njim a pop un iti menije:
//: swt/Meniji.java
// Zabava s menijima.
import swt.util.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import java.util.*;
import net.mindview.util.*;
}
}
static Listener prijemnik = new Listener() {
public void handleEvent(Event e) {
System.out.println(e.toString());
void
addItem(Menu linija, Iterator<String> it, Menultem stavkaMenija) {
Menultem stavka = new MenuItem(stavkaMenija.getMenu(),SWT.PUSH);
stavka.addListener(SWT.Selection, prijemnik);
stavka.setText(it.next());
}
public static void main(String[] args) {
SWTKonzola.run(new Meniji(), 600, 200);
}
} ///= -
Meni (objekat tipa Menu) m o ra biti sm eten u neku ljusku tj. objekat tipa Shell, a nat-
klasa C om posite om oguuje da tu Ijusku pribavite m etodom getS h ell(). TextFile je deo
paketa net.m indview .util i opisana je u p reth od no m delu knjige; ovde se reima po-
punjava skup tipa TreeSet, pa e njihov poredak biti ureen. Poetni elementi su brojevi,
koji se potom odbacuju. Pom ou toka rei daju se im ena m enijim a najvieg nivoa u traci
menija, zatim se prave podm eniji i popunjavaju reima dok ih ne ponestane.
Kao odgovor na izbor stavke menija, prijem nik (objekat tipa Listener) samo ispisuje
taj dogaaj tako da m oete videti vrstu inform acija koje sadri. Kada pokrenete program ,
videete da te inform acije obuhvataju i natpis na m eniju, pa na osnovu njega moete na-
praviti odgovor m e n ija -ili ete za svaki m eni napraviti zaseban prijem nik (to jebezbed-
nije u pogledu internacionalizacije).
//; swt/0knoSKarticama.java
// Smetanje SWT komponenata u okna s karticama.
import swt.uti1 .*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.browser.*;
Poglavjje 22: Grafika korisnika okruenja 1157
M etoda buttonTab() prikazuje raznu osnovnu dugm ad. M etoda sIiderTab() pona-
vlja Swing prim er iz prethodnog dela poglavlja u kojem se kliza vee s trakom za prika-
zivanje napredovanja.
M etoda scribbleTab() aljivo prikazuje grafike m ogunosti. Program za crtanje je
napravljen pom ou nekoliko redova koda.
Najzad, m etoda browserTab() prikazuje snagu SWT kom ponente Browser - to je
potpuni ita Weba u jednoj kom ponenti.
Grafika
Ovo je Swing progrSm Sinusoida.java preveden u SWT:
//: swt/Sinusoida.java
// Swing program Sinusoida.java preveden u SWT.
import swt.uti1 .* ;
import org.ecl1pse.swt.*;
import org.eclipse.swt.widgets.*;
import o rg.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
setCycles(5);
}
public void zadajCikluse(int noviCiklusi) {
ciklusi = noviCiklusi;
tacke = FAKTORSKALE * ciklusi * 2;
sinusi = new double[tacke];
for(int i = 0; i < tacke; i++) {
double radijani = (Math.PI / FAKTORSKALE) * i;
sinusi[i] = Math.sin(radijani);
}
redraw();
}
}
//: swt/ObojeneKutije.java
// SWT prevod Swing programa ObojeneKutije.java.
import swt.util.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.* ;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.1ayout.*;
import java.util.concurrent.*;
import java.util.*;
import net.mindview.util.*;
getDisplay().asyncExec(new Runnable() {
public void run() {
try { redraw(); } catch(SWTException e) {}
// Izuzetak SWTException ne smeta kada je roditelj
// okonan na niem nivou izvravanja.
}
});
Timellni t.MILLISECONDS.sleep(pauza);
}
} catch(InterruptedException e) {
// Prihvatljiv nairl izlaska
} catch(SWTException e) {
// Prihvatljiv nain 'ilaska: roditelj
// okonan na niem nivou izvravanja.
}
}
}
Saetak
Od svih biblioteka u Javi, biblioteka grafikih okruenja pretrpela je najvee izmene.
AWT iz Jave 1.0 esto je kritikovan kao jedan od najgorih projekata koji su se ikada poja-
vili, i m ada je om oguavao izradu prenosivih program a, dobijeno grafiko korisniko
okruenje bilo je podjednako osrednje na svim platformama". Bilo je ogranienih m o-
gunosti i nezgrapno, a koristilo se tee nego m atine alatke za razvoj aplikacija dostupne
za razne platforme.
Kada su u Javu 1.1 uvedeni nov model dogaaja i zrna Jave, stanje je poboljano: sada
je m ogue napraviti kom ponente grafikog okruenja koje se lako prevlae u n u tar alatki
za vizuelno pravljenje aplikacija. O sim toga, m odel dogaaja i zrna jasno je pokazao kako
se vodilo rauna o lakoi program iranja i odravanja koda (to nije bilo oigledno u bi-
blioteci AWT Jave 1.0). M eutim , tek kada su se pojavile klase IFC/S\ving, posao je okon-
an. Uz kom ponente biblioteke Svving, program iranje grafikih okruenja prenosivih na
razne platform e postalo je relativno bezbolno.
Prava revolucija odigrala se u oblasti alatki za pravljenje aplikacija. Ako elite da se po-
bolja neka kom ercijalna alatka za pravljenje aplikacija, m orate da drite paleve i nadate
Poglavlje 22: Grafika korisnika okruenja 1165
se da e vam autori okruenja dati ono to elite. Ipak, Java je otvoreno okruenje, to
znai da dozvoljava konkurentska okruenja za pravljenje aplikacija, i podrava takav pri-
stup. D a bi te alatke iko uzeo u obzir, one m oraju da podravaju Javina zrna. To podra-
zum eva otvoreno igralite: ako se pojavi bolja alatka za pravljenje aplikacija, vie neete
m orati da koristite o nu koju ste dotad koristili, ve moete da preete na novu i tim e po-
veate produktivnost. Ovakva vrsta konkurentskog okruenja za vizuelne alatke ranije
nije postojala, a trite koje se na ovaj nain bude form iralo m oe dati sam o pozitivne re-
zultate u pogledu produktivnosti program era.
Ovo poglavlje trebalo je da vas uvede u osnove program iranja GKO i da vam prikae
osnovne tehnike za prilino lako pronalaenje sopstvenog p u ta kroz biblioteku. O no to
ste dosad videli verovatno e zadovoljiti dobar deo vaih potreba pri projektovanju kori-
snikih okruenja. M eutim , Swing, SWT i Flash/Flex m ogu i m nogo vie od toga, jer sa-
dre p o tp u n asortim an alatki za grafika okruenja. Verovatno postoji nain da
postignete gotovo sve to m oete da zamislite.
Resursi
M rene prezentacije Bena G albraitha na adresi w w w .galbraiths.org/presentationslepo ob-
janjavaju i Swing i SWT.
Reenja odabranih vcbi data su u elektronskom dokumentu The Thinking in Java Annotated Solu-
tion Gtiide, koji se moe kupiti na lokaciji www.MindView.cotn.
A: Docfaci
Ova knjiga im a vie dodataka, m e u kojim a su i sadraji, sem inari i usluge dostupni na Web
lokaciji M indView .
Te d o p u n e s u o p i s a n e u o v o m d o d a t k u k a k o b i s t e m o g l i d a p r o c e n i t e d a l i v a m
one m ogu koristiti.
O bratite panju na to da se sem inari obino dre javno, ali m ogu biti drani i privatno,
na vaoj lokaciji, sam o za vae osoblje.
Knjige
Efikastto program iranje na Javi, Joshua Bloch (M ikro knjiga, 2004). Obavezna lektira.
Napisao ju je ovek koji je popravio Javinu biblioteku kolekcija. Pisano po u zoru na klasik
Effective C++ koji je napisao Scott Meyer.
Core Java 2, sedm o izdanje, H orstm ann & Cornell, u dva tom a (Prentice Hall, 2005).
Velika, sveobuhvatna, prva knjiga koju uzm em u ruke kada m i zatrebaju odgovori. Pre-
poruujem vam ovu knjigu kada proitate M isliti na Javi i poelite da preete na vii nivo.
The Java Class Libraries: An A nnotated Reference, Patrick C han i Rosana Lee (Addi-
son-Wesley, 1997). Naalost, zastarela je i rasprodata. Takva je trebalo da bude Sunova
HTM L okum entacija razvojnog program skog paketa za Javu: sa dovoljno opisa da bude
upotrebljiva. O bim na je, skupa, a ni kvalitet prim era m e ne zadovoljava. Pa ipak, m oe
vam posluiti kada zapadnete u nevolje, a izgleda da su navedena detaljnija objanjenja
nego u veini drugih knjiga. M eutim , Core Java 2 im a aurnija objanjenja m nogih
kom ponenata biblioteka.
Java N etw ork Programming, drugo izdanje, Eliotte Rusty H arold ( 0 Reilly, 2000).
Nisam razum eo umreavanje u Javi (niti um reavanje uopte, to se toga tie) sve dok ni-
sam pronaao ovu knjigu. Sm atram i da Web lokacija autora knjige, Cafe au Lait, prua
stim ulativan, struan i aktuelan pogled na poboljanja u Javi, neoptercen obavezama
prem a bilo kom proizvoau. Zbog redovnih auriranja, lokacija je u toku s novinam a u
Javi koje se javljaju veoma brzo. Posetite lokaciju w w w .cafeaulait.org.
Design Patterns, Gamm a, Helm, Johnson & Vlissides (Addison-Wesley, 1995). O rigi-
nalna knjiga koja je zapoela razm atranje projektnih obrazaca i koja se spom inje na vie
mesta u ovoj knjizi.
Refactoring to Patterns, Joshua Kerievsky (Addison-Wesley, 2005). Spaja preradu
program a (ponovnu podelu na proste faktore) i projektne obrasce. Najvredniji aspekt
ove knjige jeste to to pokazuje kako dalje razviti projekat korienjem projektnih obra-
zaca po potrebi.
The A rt o f UNIX Programming, Eric Raymond (Addison-Wesley, 2004). Iako je Java
jezik za pisanje program a koji se izvravaju na svim platform am a, U nix/Linux treba znati
zbog dom inacije Jave na serverima. Ericova knjiga je odlian uvod u istoriju i filozofiju
ovog operativnog sistema. Zanimljivo tivo i za one koji sam o ele da saznaju neto o ko-
renim a raunarstva.
Analiza i projektovanje
Extreme Program m ing Explained, drugo izdanje, Kent Beck uz pom o Cynthiae Andres
(Addison-Wesley, 2005). Oduvek sam oseao da bi m orao postojati m nogo drugaiji,
m nogo bolji postupak razvijanja program a, i mislim da m u je XP priao veom a blizu. Je-
dina kniiga koia je ostavila slian utisak na m ene bila je Peopleware (opisana u nastavku),
koja se pretezno bavi okruenjem i opstankom u poslovnom svetu. E xtrem e Program niing
Explained govori o program iranju i posm atra m nogo toga, ak i najnovija dostignua, iz
1172 Misliti na Javi
tog ugla. A utori ak tvrde da su slike u redu sve dok ne provodite m nogo vrem ena gleda-
jui ih i sprem ni su da ih izbace. (Prim etiete da se na knjizi ne nalazi peat UML.) Od-
luivao sam se da li u raditi za neku kom paniju iskljuivo na osnovu toga da li koriste XP.
Mala knjiga, kratka poglavlja koja se lako itaju, a teraju na razmiljanje. Poeete da za-
miljate kako radite u takvoj atm osferi i otvorie vam se novi vidici.
UML ukratko, M artin Fovvler (M ikro knjiga, 2004). Kada se prvi p u t sretnete s jezi-
kom UML, uplaiete se jer im a m nogo dijagram a i detalja. Prem a Fowleru, vei deo toga
je nepotreban i on e vam objasniti o n o osnovno. Za veinu projekata potrebno je da po-
znajete sam o nekoliko alatki za crtanje dijagram a, a Fowlerov cilj je da dobije dobar pro-
gram , a n e da brine o tom e kako je stigao do njega. Lepa, tanka, itljiva knjiga; prva koju
treba da nabavite ako elite da razum ete UML.
D om ain-D riveti Design, Eric Evans (Addison-Wesley, 2004). Bavi se tnodelom dom ena
kao prvenstvenim obelejem postupka projektovanja. Na osnovu sopstvenog iskustva
uvideo sam da je to prem etanje naglaska vano, jer pom ae program erim a da ostanu na
pravom nivou apstrakcije.
The Unified Sofhvare D evelopm ent Process, Ivar Jacobsen, G rady Booch i James
Rum baugh (Addison-Wesley, 1999). Bio sam p o tp u n o siguran da mi se ova knjiga nee
svideti. Izgledalo je kao da ima sva obeleja dosadnog fakultetskog udbenika. Ali, prijat-
no sam se iznenadio: na vrlo malo mesta sreu se objanjenja za koja bi se m oglo pomisliti
da ni autorim a nisu jasna. Vei deo knjige ne sam o da je jasan, ve je i prijatan. Najbolje
od svega je to to su objanjenja prilino praktina. To ipak nije E xtrem e Program m ing (i
nije toliko jasna u pogledu testiranja), ali je takoe deo UML menaerije: ak i ako vam se
ne svia XP, veina program era je sada usvojila stavU M L je d o b a r (bez obzira na njihov
stvarni nivo iskustva s tom m etodom ). Na kraju, i vi ete m orati da se ukrcate u taj voz.
M islim da je ova knjiga najbolja za prouavanje UML-a, i trebalo bi da je proitate ako
posle Fowlerove knjige U M L ukratko poelite da saznate vie detalja.
Pre nego to se odluite za bilo koju m etodu, korisno je da se posavetujete s nekim ko
ne eli da vas ubedi da je koristite. esto se deava da se neka m etoda usvoji, a da se pri
tom ne razum e zaista ta se eli od nje ili koje e prednosti ostvariti. Drugi je koriste, to
izgleda kao dovoljno privlaan razlog. Ljudi im aju jednu udnu osobinu: ako ele da ve-
ruju kako e neto reiti njihove problem e, oni e to i probati. (To je eksperimentisanje,
to je dobro.) M eutim , ako ne ree svoje problem e, m oda e udvostruiti napore i na
sva usta objaviti kako su otkrili neto sjajno. (To je nepriznavanje stvarnosti, to nije do-
bro.) M oda je pouka da neete biti usam ljeni, ako nagovorite druge ljude da se ukrcaju
na isti brod, ak i ako taj brod ne ide nikuda (ili tone).
Ovo ne znai da nijedna m etoologija nikuda ne vodi, ve da treba da budete
oprem ljeni m entalnim alatkam a koje e vam pom oi da ostanete na nivou eksperimen-
tisanja (Ovo ne radi: hajde da probam o neto drugo.), a da izbegavate odricanje (,,To
zapravo i nije problem . Sve ie divno, ne m oram o nita da m eniam o"). Mislim da e vam
sledee knjige, ako ih proitate pre nego to izaberete neku m etodu, obezbediti te alatke.
Softvvare Creativity, Robert Glass (Prentice Hall, 1995). Ovo je najbolja knjiga koja
razm atra perspektivu celog problem a m etodologije. To je zbirka kratkih radova koje je
Glass pisao, ponekad i dobijao od drugih (jedan od saranika je P. J. Plauger), a koji izra-
avaju njegovo dugogodinje razm iljanje i prouavanje ove teme. Dovoljno su zabavni,
Dodatak B: Resursi 1173
a dugaki sam o toliko koliko je potrebno da kau ono to je neophodno. Takoe, radovi
nisu sam o uplja pria; nude na stotine referenci na druge radove i istraivanja. Svi pro-
gram eri i m enaderi trebalo bi da proitaju ovu knjigu pre nego to se zapute na klizav te-
ren m etodologije.
Softw are Runaways: M onum ental Software Disasters, Robert Glass (Prentice Hall,
1997). O dlina osobina ove knjige je ta to naglas govori o onom e o em u se ne pria: ko-
liko projekata ne sam o da je propalo, ve je propalo spektakularno. U stanovio sam da ve-
ina program era misli: ,,To m eni ne moe da se desi (ili ,,Ne moe da se desi ponovo') i
sm atram da to nije dobro. Ako im ate na um u da neto uvek moe da krene naopako, u
m nogo ste boljem poloaju da uinite da sve radi.
Peopleware, drugo izdatije, Tom DeM arco i T im othy Lister (Dorset H ouse, 1999).
Ovu knjigu m orate da proitate. Ne sam o da je zabavna, ona e uzdrm ati svet u kojem
prebivate i unititi pretpostavke na kojim a poiva. Iako su autori projektanti softvera, ova
knjiga je posveena projektim a i tim ovim a uopte. M eutim , istaknuta je vanost Ijudi i
njihovih potreba, a ne tehnologije i njenih potreba. A utori govore o pravljenju okruenja
u kom e e ljudi biti zadovoljni i produktivni, a ne donose pravila koja bi ljudi trebalo da
potuju kako bi bili odgovarajui delovi maine. Mislim da je ovaj stav najvie doprineo
tom e se program eri podsm evaju usvajanju m etode XYZ i da nastave da rade kako su od-
uvek radili.
Secrets o f Consulting: A Guide to G iving & G etting Advice Successfully, Gerald M.
VVeinberg (D orste H ouse, 1985). Izvanredna knjiga, jedna od najboljih koju sam proitao.
Savrena je ukoliko pokuavate da radite kao konsultant ili plaate konsultante i niste za-
dovoljni njihovim rezultatim a. Iz kratkih poglavlja ispunjenih priam a i anegdotam a,
uite kako doi do sutine uz najm anje napora. Proitajte i nastavak M ore Secrets o f Con-
sulting objavljen 2002. ili gotovo bilo koju drugu W einbergovu knjigu.
Com plexity, M. Mitchell W aldrop (Sim on & Schuster, 1992). Knjiga opisuje sastanke
grupe naunika razliitih struka u gradu Santa Fe u Meksiku, koji su raspravljali o razli-
itim problem im a to u njihovim disciplinam a nisu reeni (berza u ekonom iji, nastanak
ivota u biologiji, zato Ijudi rade to to rade u sociologiji itd.). Suoavanjem gledita fi-
zike, ekonom ije, hem ije, m atem atike, raunarstva, sociologije i drugih nauka, razvijen je
m ultidisciplinarni p ristup tim problem im a. M eutim , vanije je bilo to to se poelo na
drugi nain razm iljati o pom enutim , veom a sloenim problem im a: udaljavanje od ma-
tem atikog determ inizm a i iluzije da se m oe napisati jednaina koja predvia ponaanje,
i pribliavanje stavu da treba prvo posm a tra ti i traiti neku pravilnost, a p otom je opona-
ati na sve m ogue naine. (Knjiga dokum entuje, na prim er, pojavljivanje genetskih al-
goritam a.) Sm atram da je ovakav nain razm iljanja koristan jer ukazuje na naine
upravljanja sve sloenijim softverskim projektim a.
Jezik Python
L e a rn in g P y th o n , d ru g o izd a n je, M ark Lutz i David Ascher ( 0 Reilly, 2003). Lep uvod za
program ere na m om om iljenom jeziku, odlinom pratiocu Jave. Knjiga sadri i kratak
uvod u Jython koji om oguuje kom binovanje Jave i Pythona u istom program u (inter-
pretator jezika Jvthon pravi ist Javin bajtkod, pa vam ne treba nita posebno da biste to
postigli). U jedinjenje ova dva jezika obeava velike m ogunosti.
1174 Misliti na Javi
Kompletan spisak tcrmina koji se koriste u izdanjim a Mikro knjigc nalazi se na adresi www.mk. c o .y u /r e c m k.
Indeks
i @TestObjectCreate, >
za @Unit, 869
!>75 >, 73
@throws, 61
!=, 73 >=, 73
@Unit, 864
,8 0
upotreba, 864
= ,8 1
& @version, 60
&, 79
&&, 75 A
&=, 80 f abecedno uredivanje, 325
[], operator indeksiranja,
abstract (apstraktna)
145
klasa, 239
nasleivanje od
.NET, 39 A apstraktnih klasa, 240
.new, sintaksa, 270
A, 80 rezervisana re, 240
.this, sintaksa, 270 u odnosu na interfejs, 253
^ = ,8 0
AbstractButton, 1069
@ AbstractSequentialList, 684
I AbstractSet, 629
@, simbol za anotacije, 845
@author, 60 I,79 ActionEvent, 1091, 1130
l= , 80 ActionListener, 1055
@Deprecated, anotacija, 845
@deprecated, Javadoc II,75 ActionScript, za Adobe Flex,
oznaka, 62 1139
@docRoot, 60 Adapter, projektni obrazac,
+
250,257, 338,495,582,
@inheritDoc, 60 +,71
@interface, i rezervisana re 585,631
konverzija u tip String adapteri prijemnika, 1065
extends, 854 operatorom +, 67, 85,
@link, 60 adapterska metoda, 338
393 a d d ( ), m etoda klase
@Override, 845
@param, 61 ArrayList, 303
< addActionListener( ), 1128,
@Retention, 846
@return, 61 1134
< ,73
addChangeListener, 1094
@see, 60 <=, 73
@since, 61 addListener, 1060
, 80
Adler32, 777
@SuppressWarnings, 845 = , 81
@Target, 846 Adobe Flex, 1138
<''l'est, 8 16
Adobe, proizvoa sistema
Flex, 1138
@Test, za @Unit, 864
@TestObjectCleanup, ==,73 agentski orijentisano
program iranje, 1042
oznaka za alatku @Unit,
872 agregacija, 21
1178 Misliti na Javi
LinkedList, ulanana lista, Map, klasa, 302, 306, 326 pojava pseudonim a pri
311,319, 329,649 EnumM ap, 821 pozivanju metoda, 68
List, klasa, 302, 306, 311, iscrpno istraivanje, 661 polim orfni pozivi metoda,
649,1081 poreenje performansi, 211
poreenje performansi, 698 ponaanje polim orfnih
688 Map.Entry, 673 m etoda unutar
ureivanje i pretraivanje, MappedByteBuffer, 769 konstruktora, 230
705 m a rk (), 737 preklapanje, 117
lista m arker anotacija, 847 prim ena m etode na
grafike liste, 1081 maine stanja i nabrojani sekvencu, 577
padajua lista, 1080 tipovi, 830 privatna, 232
Lister, Timothy, 1173 matcher( ), m etoda za razlikovanje preklopljenih
Listlterator, 649 pronalaenje metoda, 119
literal regularnog izraza, 414 redefinisanje privatnih,
double, 78 matches( ), m etoda klase 221
float, 78 String, 409 rekurzivna, 398
klase, 439,451 matematiki operatori, 69, statina, 129, 215
long, 78 773 ugraivanje poziva
vrednosti, 77 M ath.random ( ), metoda metoda direktno
little endian, 763 opseg rezultata, 695 u kod, 204
logaritmi, prirodni, 79 M ath.random ( ), metoda unutranje klase
logika za generisanje sluajnih u m etodam a
konjunkcija, 86 brojeva, 326 i oblastima vaenja,
disjunkcija, 86 mehanizam za raspodelu 273
operator i nepotpuno procesorskog vremena vezivanje poziva metoda,
izraunavanje, 76 nitim a, 891 214
operatori, 75 meni zatiene metode, 198
lokalna JDialog, JApplet, JFrame, Meyer, Jeremy, 845, 879,
unutranja klasa, 274 1085 1105
promenljiva, 50 JPopupM enu, 1091 Meyers, Scott, 20
long metaanotacije, 848 Microsoftov Visual BASIC,
i vienitni rad, 926 Metapodaci, 845 1120
marker (L) literala, 78 Method, 1126 migracijska kompatibilnost,
LRU, algoritam najdavnijeg klasa za refleksiju, 462 516
korienja, 667 M ethodDescriptor, 1126 m ikroporeenje
Ivrednost, 67 metoda perform ansi, 694
alatka za pronalaenje, miksin, 565
1061 mkdirs( ), 730
M dodavanje metoda mnemonici (preice
main( ), 184 program u, 179 s tastatiiff), ! 090
manitest datoteka, za JAR finalna, 204,215,232 mnoenje, 69
datoteke, 779, 1135 generika, 496 modulo, 69
manje ili jednako (<=), 73 inicijalizacijapromenljivih m ogunost ponovnog
manje od (<), 73 u metodam a, 136 korienja, 21
Indeks 1189