Darmowy fragment publikacji:
IDZ DO
IDZ DO
PRZYK£ADOWY ROZDZIA£
PRZYK£ADOWY ROZDZIA£
SPIS TREĎCI
SPIS TREĎCI
Java. Potrzaski
KATALOG KSI¥¯EK
KATALOG KSI¥¯EK
KATALOG ONLINE
KATALOG ONLINE
ZAMÓW DRUKOWANY KATALOG
ZAMÓW DRUKOWANY KATALOG
TWÓJ KOSZYK
TWÓJ KOSZYK
DODAJ DO KOSZYKA
DODAJ DO KOSZYKA
CENNIK I INFORMACJE
CENNIK I INFORMACJE
ZAMÓW INFORMACJE
ZAMÓW INFORMACJE
O NOWOĎCIACH
O NOWOĎCIACH
ZAMÓW CENNIK
ZAMÓW CENNIK
CZYTELNIA
CZYTELNIA
FRAGMENTY KSI¥¯EK ONLINE
FRAGMENTY KSI¥¯EK ONLINE
Wydawnictwo Helion
ul. Chopina 6
44-100 Gliwice
tel. (32)230-98-63
e-mail: helion@helion.pl
Autorzy: Michael C. Daconta, Eric Monk,
J Paul Keller, Keith Bohnenberger
T³umaczenie: Jaromir Senczyk
ISBN: 83-7361-121-5
Tytu³ orygina³u: Java Pitfalls
Format: B5, stron: 310
Przyk³ady na ftp: 68 kB
Choæ Java to jêzyk gwarantuj¹cy efektywn¹ pracê, to jednak kryje w sobie wiele
pu³apek, które mog¹ zniweczyæ jej efekty. Ksi¹¿ka ta ma za zadanie oszczêdziæ Twój
czas i zapobiec frustracji przeprowadzaj¹c Ciê bezpiecznie przez skomplikowane
zagadnienia. Zespó³ ekspertów od jêzyka Java pod wodz¹ guru programowania
w osobie Michaela Daconta proponuje Ci zestaw sprawdzonych rozwi¹zañ 50 trudnych
problemów pojawiaj¹cych siê w praktyce ka¿dego programisty. Rozwi¹zania te pozwol¹
Ci unikn¹æ problemów wynikaj¹cych z niedostatków jêzyka Java oraz jego interfejsów
programowych, w tym pakietów java.util, java.io, java.awt i javax.swing. Autorzy dziel¹
siê tak¿e z Czytelnikiem swoimi sposobami na poprawê wydajnoġci aplikacji pisanych
w Javie.
Oto niektóre z omawianych zagadnieñ:
• Sk³adnia jêzyka: zastosowanie metody equals() zamiast operatora ==
do porównywania obiektów klasy String
• Funkcjonalnoġæ wbudowana w jêzyk: rozdzia³ metod a mechanizm refleksji,
interfejsy i klasy anonimowe
• U¿yteczne klasy i kolekcje: wybór klasy PropertyFile i ResourceBundle
• Wejġcie i wyjġcie, w tym subtelnoġci zwi¹zane z przesy³aniem serializowanych
obiektów za pomoc¹ gniazd sieciowych
• Graficzny interfejs u¿ytkownika: sposoby unikniêcia typowej pu³apki polegaj¹cej
na zastosowaniu metody repaint() zamiast metody validate() w celu uzyskania
nowego uk³adu komponentów
• Graficzny interfejs u¿ytkownika -- sterowanie: m.in. bardziej funkcjonalna kontrola
danych wprowadzanych przez u¿ytkownika
• Wydajnoġæ: m.in. zastosowanie odroczonego ³adowania, tak by zwiêkszyæ
szybkoġæ uruchamiania programów
Spis treści
Wstęp ...................................................z............................................ 9
Rozdział 1. Składnia języka...................................................z............................. 13
Zagadnienie 1. Przesłanianie metod statycznych .........................................................14
Zagadnienie 2. Zastosowanie metody equals() i operatora ==
dla obiektów klasy String .......................................................................................16
Zagadnienie 3. Kontrola zgodności typów w języku Java ...........................................19
Konwersja typów...............................................................................................20
Rozszerzanie .....................................................................................................21
Zawężanie ..........................................................................................................22
Niejawne konwersje typów .................................................................................22
Zagadnienie 4. Czy to jest konstruktor? .....................................................................23
Zagadnienie 5. Brak dostępu do przesłoniętej metody ................................................25
Zagadnienie 6. Pułapka ukrytego pola........................................................................27
Rodzaje zmiennych w języku Java ......................................................................29
Zakres deklaracji zmiennej..................................................................................29
Które zmienne mogą być ukrywane? ...................................................................30
Ukrywanie zmiennych instancji i zmiennych klas.................................................30
Dostęp do ukrytych pól.......................................................................................32
Różnice pomiędzy ukrywaniem pól i przesłanianiem metod..................................33
Zagadnienie 7. Referencje wyprzedzające..................................................................34
Zagadnienie 8. Konstruktory i projektowanie klas.......................................................35
Zagadnienie 9. Przekazywanie typów prostych przez referencję..................................42
Zagadnienie 10. Wyrażenia i operatory logiczne .........................................................45
Rozdział 2. Funkcjonalność wbudowana w język Java ......................................... 47
Zagadnienie 11. Odzyskiwanie pamięci za pomocą obiektów SoftReference ................48
Odzyskiwanie pamięci........................................................................................48
Klasa SoftReference...........................................................................................50
Kolejki referencji ...............................................................................................55
Zagadnienie 12. Zakleszczenie na skutek wywołania metody synchronizowanej
przez metodę synchronizowaną ..............................................................................57
Wątki, monitory i słowo kluczowe synchronized..................................................57
Przykładowy scenariusz zakleszczenia .................................................................61
Zagadnienie 13. Klonowanie obiektów ......................................................................65
Zagadnienie 14. Przesłanianie metody equals .............................................................71
Zastosowanie obiektów klasy StringBuffer jako kluczy kodowania mieszającego ...73
Zagadnienie 15. Unikajmy konstruktorów w implementacji metody clone() .................74
6
Java. Potrzaski
Zagadnienie 16. Rozdział metod a mechanizm refleksji, interfejsy
i klasy anonimowe.................................................................................................79
Zagadnienie 17. Obsługa wyjątków i błąd OutOfMemoryError ...................................88
Składnia wyjątków.............................................................................................89
Hierarchia wyjątków ..........................................................................................89
Obsługa wyjątków .............................................................................................90
Błąd braku pamięci ............................................................................................90
Rozdział 3. Użyteczne klasy i kolekcje ...................................................z............ 93
Zagadnienie 18. Uporządkowane klucze właściwości? ...............................................94
Zagadnienie 19. Obsługa kolekcji o znacznych rozmiarach
za pomocą mechanizmów buforowania i trwałości....................................................97
Zagadnienie 20. Plik właściwości czy zestaw zasobów? ........................................... 109
Zagadnienie 21. Pułapki klasy Properties ................................................................. 112
Zagadnienie 22. Klasa Vector i nowe kolekcje.......................................................... 117
Rozdział 4. Wejście i wyjście ...................................................z........................ 121
Zagadnienie 23. Serializacja.................................................................................... 122
Jak działa serializacja?...................................................................................... 123
Interfejs Externalizable ..................................................................................... 124
Zagadnienie 24. Unicode, UTF i strumienie.............................................................. 125
Unicode ........................................................................................................... 126
UTF ................................................................................................................ 126
Strumienie........................................................................................................ 128
Konfigurowanie kodowania .............................................................................. 131
Zagadnienie 25. Przesyłanie serializowanych obiektów
za pomocą gniazd sieciowych ............................................................................... 131
Zagadnienie 26. Try, catch … finally? ..................................................................... 135
Zagadnienie 27. Opróżnianie zasobów związanych z obrazami ................................. 138
Rozdział 5. Graficzny interfejs użytkownika — prezentacja................................ 143
Zagadnienie 28. Informowanie o postępach.............................................................. 144
Kursor zajętości ............................................................................................... 145
Monitor postępu............................................................................................... 147
Zagadnienie 29. Zastosowanie metody repaint() zamiast metody validate()
do aktualizacji układu komponentów..................................................................... 149
Zagadnienie 30. Uporządkowanie nakładających się komponentów........................... 153
Menedżery układu............................................................................................ 154
JLayeredPane .................................................................................................. 158
Zagadnienie 31. Zagadka metod validate(), revalidate() i invalidate()......................... 160
Zagadnienie 32. Pionowy układ komponentów ......................................................... 164
Zagadnienie 33. Właściwe sposoby użycia menedżera GridBagLayout ...................... 172
Zagadnienie 34. Zapobieganie migotaniu obrazu ...................................................... 179
Rysowanie w AWT.......................................................................................... 180
Rysowanie i Swing........................................................................................... 183
Zagadnienie 35. Komponenty z zagnieżdżonymi etykietami HTML .......................... 184
Rozdział 6. Graficzny interfejs użytkownika — sterowanie ................................ 189
Zagadnienie 36. Kontrola danych wprowadzanych przez użytkownika ...................... 190
Komponenty tworzone na miarę ........................................................................ 191
Filtrowanie ...................................................................................................... 191
Konsumowanie zdarzeń.................................................................................... 192
Kontrola po wprowadzeniu danych.................................................................... 194
Problemy projektowania ................................................................................... 194
Spis treści
7
Asynchroniczna kontrola poprawności ............................................................... 195
Adapter kontroli danych ................................................................................... 196
Techniki kontroli poprawności danych............................................................... 198
Kontrola poprawności danych z wykorzystaniem wyjątków................................ 198
Łańcuchy kontroli poprawności danych ............................................................. 200
Uwagi końcowe ............................................................................................... 201
Zagadnienie 37. Uaktywnianie komponentów interfejsu użytkownika
w zależności od stanu aplikacji ............................................................................. 201
Pierwsze rozwiązanie ....................................................................................... 202
Rozwiązanie siłowe.......................................................................................... 202
Rozwiązanie przez abstrakcję — klasa StateMonitor .......................................... 203
ListViewer ...................................................................................................... 205
Adaptacyjna deaktywacja komponentów............................................................ 208
Zagadnienie 38. Wielowątkowa obsługa zdarzeń ...................................................... 208
Skuteczna implementacja obsługi przycisku Cancel
z wykorzystaniem wątków.............................................................................. 210
Skuteczna implementacja obsługi przycisku Cancel
wykorzystująca klasę SwingWorker ................................................................ 212
Zagadnienie 39. Wzorzec „model widok kontroler” i komponent JTree ..................... 214
Zagadnienie 40. Przekazywanie danych innych niż tekst .......................................... 217
Pakiet java.awt.datatransfer .............................................................................. 218
Trzy scenariusze przekazywania danych ............................................................ 219
Przykład przekazywania danych w obrębie jednej maszyny wirtualnej ................. 219
Określanie sposobu przekazywania danych ........................................................ 223
Przekazywanie danych poza maszynę wirtualną................................................. 224
Zagadnienie 41. KeyListener, który nie słucha? ........................................................ 238
Zagadnienie 42. Drukowanie tekstu, dokumentów HTML i obrazów
za pomocą komponentu JEditorPane ..................................................................... 241
Rozdział 7. Efektywność...................................................z............................... 251
Zagadnienie 43. Odroczone ładowanie sposobem na poprawę efektywności............... 252
Zagadnienie 44. Zastosowania puli obiektów............................................................ 254
Odzyskiwanie obiektów.................................................................................... 255
Porównanie puli obiektów i buforowania............................................................ 255
Implementacja ................................................................................................. 256
Zalety .............................................................................................................. 257
Wady............................................................................................................... 258
Kłopoty............................................................................................................ 258
Zagadnienie 45. Efektywność tablic i klasy Vector.................................................... 260
Dlaczego klasa Vector jest wolniejsza od zwykłych tablic? ................................. 262
Kiedy używać klasy Vector? ............................................................................. 263
Klasa ArrayList................................................................................................ 264
Zagadnienie 46. Zagadnienie dynamicznego wzrostu tablic ...................................... 265
Zagadnienie 47. Konkatenacja łańcuchów znakowych w pętli
— porównanie klas String i StringBuffer ............................................................... 270
Rozdział 8. Rozmaitości...................................................z................................ 273
Zagadnienie 48. Czy istnieje lepszy sposób uruchamiania? ....................................... 273
Zagadnienie 49. Hermetyzacja wywołań JNI za pomocą interfejsów ......................... 275
Koncepcja ........................................................................................................ 276
Przykład interfejsu ........................................................................................... 277
Implementacja w języku Java............................................................................ 279
Implementacja w kodzie macierzystym .............................................................. 281
Kod specyficzny dla platformy Windows ........................................................... 285
8
Java. Potrzaski
Zagadnienie 50. Asercje ......................................................................................... 289
Asercje w języku Java ...................................................................................... 290
Stosowanie asercji............................................................................................ 290
Jak nie należy stosować asercji.......................................................................... 290
Przykładowa implementacja.............................................................................. 291
Skorowidz ...................................................z....................................... 295
Rozdział 3.
Użyteczne klasy i kolekcje
W językach C++ i Java implementacja list jest dostępna w standardowych
bibliotekach, co nie zwalnia nas od znajomości sposobów ich stosowania.
— Brian W. Kernighan i Rob Pike „The Practice Of Programming”
Aby z powodzeniem używać jakiekolwiek klasy, należy dobrze znać sposób, w jaki zo-
stały zaprojektowane ich zadania i ograniczenia. Wymaga to czasu i doświadczenia. Dla-
tego, aby zaoszczędzić Czytelnikowi czas przedstawiamy w niniejszym rozdziale własne
doświadczenia — niektóre klasy pakietu LCXCWVKN ujęte w pięć następujących zagadnień:
Zagadnienie 18. Uporządkowane klucze właściwości? — opisuje sposób udoskona-
lenia klasy 2TQRGTVKGU dający uporządkowany zbiór właściwości.
Zagadnienie 19. Obsługa kolekcji o znacznych rozmiarach za pomocą mechani-
zmów buforowania i trwałości — szczegółowo omawia sposób implementacji ko-
lekcji wykorzystujący mechanizmy buforowania i trwałości stanowiącej rozwiązanie
rzeczywistego problemu zaczerpniętego z praktyki programistycznej.
Zagadnienie 20. Plik właściwości czy zestaw zasobów? — przedstawia różnice po-
między rozwiązaniami wymienionymi w tytule. Mimo że pliki właściwości stanowią
często stosowane rozwiązanie, to nie zawsze jest ono optymalne. W zagadnieniu przed-
stawiono przykład ilustrujący taką sytuację.
Zagadnienie 21. Pułapki klasy Properties — stanowi dokładny przegląd zagadnień
i pułapek związanych z zastosowaniem właściwości do przechowywania informacji
o konfiguracji programów. W szczególności omawia sposoby umożliwiające pracę apli-
kacji w różnych systemach niezależnie od sposobu jej instalacji.
Zagadnienie 22. Klasa Vector i nowe kolekcje — szczegółowo opisuje modyfikacje
klasy 8GEVQT na skutek włączenia jej do szkieletu kolekcji udostępnionego w nowszych
wersjach języka Java. Zagadnienie ma zachęcić Czytelnika do korzystania z nowego
szkieletu kolekcji.
94
Java. Potrzaski
Zagadnienie 18.
Uporządkowane klucze właściwości?
Załóżmy, że Czytelnik wrócił właśnie z udanych wakacji i zamierza pochwalić się ro-
dzinie zdjęciami, które zrobił nowym aparatem. Odkurzając rzutnik i zawieszając ekran,
zaczyna się jednak zastanawiać, czy taka technologia prezentacji zdjęć nie jest już
przestarzała? Zamiast niej decyduje się napisać program w języku Java, który będzie
zarządzać pokazem zdjęć. Łącząc umiejętności programowania z cyfrowymi zdjęcia-
mi, można zrobić na rodzinie jeszcze większe wrażenie.
Program jest skończony i nadszedł właśnie długo oczekiwany dzień pokazu. Wujek Bob
i inni zasiedli wokół komputera. Zostaje uruchomiony program, który wyświetla tytuł
pokazu „Wycieczka na Grenadę, wyspę pieprzu”.
Autor zdjęć rozpoczyna opowieść o wakacjach, mówiąc: „Następne zdjęcie obrazuje
moment, gdy z Patty wsiadamy do samolotu”. Jednak po naciśnięciu klawisza, które
to wyświetli, pojawia się zdjęcie twoich przyjaciół, Drew i Suzy, w hotelu. Okazuje
się, że zdjęcia zupełnie się pomieszały. Gdy wujek Bob zaczyna rzucać pomidorami
w ekran monitora, łatwo się domyśleć, że pokaz nie udał się. Jednak zostaje złożone
postanowienie dopracowania programu, aby spróbować jeszcze raz.
Każdy byłby zdeterminowany, aby znaleźć błąd, który stał się przyczyną porażki. Klu-
czową koncepcją programu SlideShow jest abstrakcja ścieżek dostępu do zdjęć. Dzię-
ki temu stworzenie kolejnego pokazu będzie wymagać jedynie zmiany pliku właściwo-
ści zawierającego ścieżki dostępu do wyświetlanych zdjęć. Rozwiązanie takie jest o wiele
lepsze niż konieczność modyfikowania kodu źródłowego za każdym razem, gdy chce
się stworzyć nową prezentację. Ponieważ w pliku właściwości oprócz ścieżek dostępu
do poszczególnych zdjęć są zapisane także inne informacje, to trzeba przyjąć pewną
konwencję pozwalającą ustalić, która właściwość dotyczy zdjęcia, a która nie. W tym
celu wszystkie właściwości zdjęć poprzedzimy przedrostkiem +OCIGA. Wydaje się to
dobrym rozwiązaniem, jednak zdjęcia nie są wyświetlane we właściwej kolejności.
Sprawdźmy zatem, czy plik właściwości zawiera rzeczywiście opis zdjęć w odpowied-
niej kolejności. Zawartość pliku wygląda następująco:
KOCIG4QQVE KOCIGU
VKVNG)TGPCFC8CECVKQP
VKVNG2CIG1WT6TKRVQ)TGPCFCVJG+UNCPFQH5RKEGE
+OCIGAFGRCTVKPIRNCPGLRI
+OCIGAJQVGNJQVGNLRI
+OCIGAHTKGPFUFTGYAUW[LRI
+OCIGADGCEJDGCEJLRI
+OCIGATGVWTPRCVV[AMKTUVGPAMGKVJLRI
Ponieważ kolejność zdjęć w pliku właściwości jest prawidłowa, powodem ich przy-
padkowego wyświetlania musi być błąd w programie. Przyjrzyjmy się więc fragmento-
wi kodu, który jest odpowiedzialny za tworzenie obiektów +OCIG+EQP na podstawie
właściwości zdjęć zapisanych w pliku:
Rozdział 3. ♦ Użyteczne klasy i kolekcje
95
RWDNKE+OCIG+EQP=?IGV+OCIGU
]
+OCIG+EQP=?KOCIGUPWNN
#TTC[.KUVCNPGY#TTC[.KUV
5VTKPIKOCIG4QQVRTQRGTVKGUIGV2TQRGTV[
KEOCIG4QQV
PWOGTCVKQPMG[URTQRGTVKGUMG[U
9JKNG
MG[UJCU/QTG NGOGPVU
]
5VTKPIMG[
5VTKPIMG[UPGZV NGOGPV
KH
MG[UVCTVU9KVJ
+OCIGA
]
+OCIG+EQPKEQPPGY+OCIG+EQP
KOCIKG4QQV
(KNGUGRCTCVQT
RTQRGTVKGUIGV2TQRGTV[
MG[
CNCFF
KEQP
_
_
KPVUKGCNUKG
KH
UKG
]
KOCIGUPGY+OCIG+EQP=UKG?
CNVQ#TTC[
KOCIGU
_
TGVWTPKOCIGU
_
Metoda IGV+OCIGU
zwraca tablicę obiektów +OCIG+EQP. Tablica ta jest wypełniana
w miarę przeglądania kluczy właściwości i sprawdzania, czy rozpoczynają się one od
przedrostka +OCIGA (wiersz 10.). Jeśli klucz zawiera taki przedrostek, to tworzony jest
obiekt klasy +OCIG+EQP i wstawiany do tablicy klasy #TTC[.KUV (wiersze 12. – 14.). Po
zakończeniu analizy pliku właściwości tablica #TTC[.KUV jest konwertowana do zwykłej
tablicy obiektów klasy +OCIG+EQP i zwraca jako wynik wykonania metody.
Wydaje się więc, że kod programu jest napisany prawidłowo. Jednak skoro także plik
właściwości jest prawidłowy, to program powinien wyświetlać zdjęcia w odpowiedniej
kolejności, a tak nie jest. Należy więc raz jeszcze sprawdzić kod programu, dodając poniż-
szą instrukcję wewnątrz bloku instrukcji warunkowej, rozpoczynającej się w wierszu10.:
5[UVGOQWVRTKPVNP
MG[
MG[
Dzięki niej dowiemy się, czy pobieramy ścieżki dostępu do zdjęć w tej samej kolejno-
ści, w której zostały one zapisane w pliku właściwości. Uruchamiając program, uzy-
ska się następującą informację:
MG[ +OCIGAJQVGN
MG[ +OCIGAHTKGPFU
MG[ +OCIGAFGRCTVKPI
MG[ +OCIGATGVWTP
MG[ +OCIGADGCEJ
Widzimy więc, że kolejność uzyskiwania zdjęć różni się od kolejności ich występowa-
nia w pliku. Czy to oznacza, że metoda MG[U
klasy 2TQRGTVKGU posiada błędy? Od-
powiedź na to pytanie jest krótka: nie. Źródłem problemu jest przyjęte założenie, że
klucze obiektu 2TQRGTVKGU są widziane w tej samej kolejności, w której występują w pli-
ku. Założenie to nie jest prawdziwe. Ponieważ klasa 2TQRGTVKGU stanowi klasę pochodną
96
Java. Potrzaski
klasy *CUJVCDNG, to klucze właściwości przechowywane są w tablicy mieszającej, a nie
na uporządkowanej liście. Klasa *CUJVCDNG przyznaje każdemu kluczowi indeks zależny
od wyniku funkcji mieszającej dla danego klucza i od bieżącego rozmiaru tablicy. In-
deks ten nie zależy od kolejności, w której klucze są umieszczane w tablicy. Natomiast
metoda MG[U
zwraca klucze zgodnie z numerycznym porządkiem ich indeksów. Dla-
tego też porządek ich oglądania może różnić się od kolejności, w której zostały umiesz-
czone w tablicy mieszącej.
Czy oznacza to, że musimy umieścić informacje o zdjęciach w kodzie programu, aby
uzyskać pożądaną kolejność ich wyświetlania? Na szczęście nie. Istnieją inne sposo-
by, dzięki którym można osiągnąć pożądany efekt, np. umieścić ścieżki dostępu do
zdjęć w zwykłym pliku tekstowym nieposiadającym żadnej struktury i wczytywać je-
go zawartość. Ponieważ jednak program SlideShow korzysta także z innych właści-
wości, to musielibyśmy dostarczać mu dwóch różnych plików. Poza tym możliwość
przeglądania kluczy obiektu 2TQRGTVKGU w kolejności, w której występują one w pliku
właściwości, może okazać się przydatna w wielu innych zastosowaniach.
W jaki sposób zatem uzyskać uporządkowaną listę kluczy z obiektu 2TQRGTVKGU? Nie
jest to możliwe. Możemy jednak stworzyć własną klasę pochodną klasy 2TQRGTVKGU,
która zrealizuje to zadanie. Klasa ta będzie posiadać zmienną instancji, która prze-
chowa uporządkowane klucze. Aby móc dodawać klucze i usuwać je z uporządkowanej
listy, musimy także przesłonić metody RWV
i TGOQXG
własną implementacją oraz do-
dać metodę, za pomocą której będzie można uzyskać uporządkowaną listę kluczy.
Nową klasę nazwiemy PJCPEGF2TQRGTVKGU (w zagadnieniu 21. przedstawiono szereg
przydatnych metod tej klasy). Definicja klasy PJCPEGF2TQRGTVKGU może wyglądać na-
stępująco:
RWDNKEENCUU PJCPEGF2TQRGTVKGUGZVGPFU2TQRGTVKEGU
]
MQPUVTWMVQT[
#TTC[.KUVQTFGTGF-G[UPGY#TTC[.KUV
RWDNKEU[PEJTQPKGF1DLGEVRWV
1DLGEVMG[1DLGEVEXCNWG
]
1DLGEVQDLGEVUWRGTRWV
MG[XCNWG
QTFGTGF-G[UCFF
MG[
TGVWTPQDLGEV
_
RWDNKEU[PEJTQPKGF1DLGEVTGOQXG
1DLGEVMG[
]
1DLGEVQDLGEVUWRGTTGOQXG
MG[
QTFGTGF-G[UTGOQXG
MG[
TGVWTPQDLGEV
_
RWDNKEU[PEJTQPKGF+VGTCVQTIGV1TFGTGF-G[U
]
TGVWTPQTFGTGF-G[UKVGTCVQT
_
_
Rozdział 3. ♦ Użyteczne klasy i kolekcje
97
Zmienna instancji QTFGTGF-G[U w wierszu 5. jest kontenerem, w którym przechowuje się
uporządkowaną listę kluczy. Metoda RWV
, której definicja rozpoczyna się w wierszu 8.,
wywołuje najpierw metodę UWRGTRWV
, która umieszcza klucz w tablicy mieszającej
w sposób właściwy klasie 2TQRGTVKGU. Natomiast wywołanie QTFGTGF-G[UCFF
MG[
w wierszu 9. wstawia ten klucz na uporządkowaną listę kluczy. Wywołanie metody RWV
spowoduje za każdym razem dodanie klucza do tablicy mieszającej *CUJVCDNG i wsta-
wienie go do uporządkowanej listy kluczy. Metoda TGOQXG
, której definicja rozpoczy-
na się w wierszu 13., działa w podobny sposób do metody RWV
. Za każdym razem,
gdy wywołana jest metoda TGOQXG
, klucz zostaje najpierw usunięty z tablicy mieszą-
cej, a następnie z uporządkowanej listy kluczy. Dostęp do tej listy umożliwia metoda
IGV1TFGTGF-G[U
, która zwraca iterator czytający tę listę.
Ta dość prosta w implementacji klasa pozwoli przeglądać ścieżki dostępu do zdjęć do-
kładnie w tym samym porządku, w którym zostały one zapisane w pliku właściwości.
Metoda IGV+OCIGU
tworząca tablicę obiektów klasy +OCIG+EQP na podstawie właści-
wości, których klucz rozpoczyna się od przedrostka +OCIGA, musi zostać zmodyfikowana
w niewielkim stopniu. Wiersze 6. – 9. trzeba zatem zastąpić następującymi wierszami:
+VGTCVQTQTFGTGF-G[URTQRGTVKGUIGV1TFGTGF-GE[U
9JKNG
MG[UJCU0GZV
]
5VTKPIMG[
5VTKPIMG[UPGZV
Jedyną zmianą, której będziemy musieli wykonać w pozostałej części programu, bę-
dzie zastąpienie instancji klasy 2TQRGTVKGU tworzonej podczas wczytywania zawartości
pliku właściwości za pomocą instancji nowej klasy PJCPEGF2TQRGTVKGU. Po wykona-
niu tych zmian i uruchomieniu programu uzyskamy następującą informację o dodawa-
nych kluczach:
MG[ +OCIGAFGRCTVKPI
MG[ +OCIGAJQVGN
MG[ +OCIGAHTKGPFU
MG[ +OCIGADGCEJ
MG[ +OCIGATGVWTP
Ścieżki dostępu do plików są teraz uporządkowane w odpowiedni sposób. Wiadomo już,
że klasa 2TQRGTVKGU jest pochodną klasy *CUJVCDNG, a sposób przyznawania indeksów
kluczom umieszczanym w tablicy mieszającej nie jest związany z kolejnością ich wsta-
wiania. Dzięki temu można spokojnie zaprosić wujka Boba na powtórny, udany po-
kaz zdjęć.
Zagadnienie 19. Obsługa kolekcji
o znacznych rozmiarach za pomocą
mechanizmów buforowania i trwałości
Czasami zdarza się, że program napisany w języku Java, który wyświetla wyniki za-
pytań wysyłanych do systemu baz danych, działa doskonale w 9 przypadkach na 10.
98
Java. Potrzaski
W tym jednym nie wyświetla żadnych efektów zapytania, sygnalizując jednocześnie
wystąpienie błędu 1WV1H/GOQT[. Wyniki zapytań są umieszczane w klasie LCXCWVKN
8GEVQT, która stanowi efektywną i wygodną metodę krótkotrwałego przechowywania
danych. W jaki sposób można pogodzić efektywność tego rozwiązania z konieczno-
ścią zapewnienia jego niezawodności w przypadku sporadycznie pojawiających się
wyników zapytań o znacznych rozmiarach? Rozwiązaniem będzie struktura danych
stanowiąca kombinację bufora LRU (Least Recently Used) z trwałym składem obiek-
tów. Jego implementację stanowić będzie klasa 2GTUKUVGPV CEJG8GEVQT, którą omówi-
my w tym zagadnieniu.
Rysunek 3.1 przedstawia strukturę klasy 2GTUKUVGPV CEJG8GEVQT z zaznaczeniem, że
składa się ona z czterech głównych komponentów: wektora proxy zawierającego namiast-
ki, tablicy mieszającej buforowanych obiektów, listy LRU i obiektu klasy 1DLGEV(KNG
umożliwiającego serializację obiektów.
Rysunek 3.1.
Architektura klasy
PersistentCacheVector
Architektura przedstawiona na rysunku 3.1 posiada następujące zalety:
Prostota użycia podobna do klasy LCXCWVKN8GEVQT.
Możliwość osiągania znacznych rozmiarów przez kolekcję (na przykład ponad
50 000 elementów) bez obawy wystąpienia błędu 1WV1H/GOQT[ TTQT.
Dostępność najczęściej wykorzystywanych elementów kolekcji w pamięci.
Szczegóły implementacji związane z obsługą kolekcji znacznych rozmiarów
nie są widoczne dla użytkownika klasy.
Rozdział 3. ♦ Użyteczne klasy i kolekcje
99
Architekturę tę będzie implementować kod umieszczony w dwóch plikach źródłowych:
PersistentCacheVector.java i ObjectFile.java. Najpierw zostaną omówione najistotniej-
sze ich fragmenty, a pełny kod źródłowy — pod koniec bieżącego zagadnienia. Zanim
przejdziemy do analizy kodu, przyjrzyjmy się zaproponowanemu interfejsowi klasy
2GTUKUVGPV CEJG8GEVQT. Posiada on następujące metody o dostępie publicznym:
RWDNKE2GTUKUVGPV CEJG8GEVQT
KPVK CEJG5KG
RWDNKEHKPCNXQKFCFF
5GTKCNKCDNGQVJTQYU+1 ZEGRVKQP
RWDNKEHKPCN1DLGEVIGV
KPVKFZVJTQYU+PFGZ1WVQH$QWPFU ZEEGRVKQP
+1 ZEGRVKQP
RWDNKEHKPCN1DLGEVTGOQXG
KPVKPFGZVJTQYU+PFGZ1WV1H$QWEPFU ZEGRVKQP
+1 ZEGREVKQP
RWDNKEHKPCNXQKFEQR[6Q
1DLGEVQ#TTC[=?VJTQYU+1 ZEGRVKQPE
RWDNKEHKPCNXQKFENQUG
RWDNKEHKPCNXQKFHKPCNKG
RWDNKEHKPCNKPVUKG
Pomiędzy interfejsem klasy 2GTUKUVGPV CEJG8GEVQT i metodami klasy 8GEVQT wystę-
pują cztery istotne różnice:
Konstruktor klasy 2GTUKUVGPV CEJG8GEVQT wymaga określenia maksymalnego
rozmiaru bufora. Inaczej niż w przypadku klasy 8GEVQT, konstruktorowi
której przekazujemy początkowy rozmiar wektora, dla klasy 2GTUKUVGPV CEJG
8GEVQT parametr konstruktora oznacza maksymalną liczbę obiektów, które
mogą być przechowywane w pamięci. Obiekty nadmiarowe będą przechowane
na dysku.
Niektóre z metod wyrzucają wyjątek +1 ZEGRVKQP ze względu
na przechowywanie obiektów w plikach. Z punktu widzenia zgodności
z klasą 8GEVQT najlepiej obsługiwać ten wyjątek wewnątrz metod, zamiast
przekazywać go do kodu wywołującego metody. Jednak wystąpienie błędu
dysku spowodowałoby wtedy nieprzewidziane zachowanie klasy 8GEVQT. Druga
możliwość polega na przechwyceniu wyjątku +1 ZEGRVKQP i wyrzuceniu wyjątku
4WPVKOG ZEGRVKQP, który nie musi być obsługiwany. W ten sposób również
uzyskalibyśmy przezroczystość fasady klasy 8GEVQT, gdyż kod wywołujący
metody nie musiałby obsługiwać żadnych wyjątków.
Pominięte zostały niektóre metody dostępne w klasie 8GEVQT. Ich implementację
pozostawiono Czytelnikowi jako ćwiczenie do wykonania. Inna możliwość
udawania klasy 8GEVQT polega na utworzeniu jej klasy pochodnej i przesłonięciu
wszystkich metod klasy bazowej. Dzięki temu będziemy mogli używać obiektów
klasy 2GTUKUVGPV CEJG8GEVQT zamiast obiektów klasy 8GEVQT, jednak w istotny
sposób zwiększy to rozmiary implementacji klasy 2GTUKUVGPV CEJG8GEVQT.
Parametrem metody CFF
mogą być tylko obiekty implementujące
interfejs 5GTKCNKCDNG. Ograniczenie to wynika z konieczności zapewnienia
trwałości buforowanych obiektów i oczywiście nie występuje ono w klasie
8GEVQT. Dla zapewnienia zgodności z klasą 8GEVQT metoda CFF
mogłaby
przyjmować dowolne obiekty, a następnie za pomocą refleksji sprawdzać
możliwość ich serializacji. Jednak wydaje się, że lepiej zapewnić kontrolę
zgodności typów parametrów kosztem pełnej zgodności z klasą 8GEVQT.
100
Java. Potrzaski
Implementacja interfejsu klasy 2GTUKUVGPV CEJG8GEVQT wymaga zarządzania struktura-
mi przedstawionymi na rysunku 3.1: wektorem proxy zawierającym obiekty namiastek
5VWD PVT[, tablicą mieszającą obiektów CEJG PVT[, listą LRU i obiektem 1DLGEV(KNG.
Zagadnienia te omówimy szczegółowo.
Klasa wewnętrzna 5VWD PVT[ stwarza iluzję korzystania z obiektów klasy 8GEVQT. Użyt-
kownik spodziewa się zwykłego obiektu klasy 8GEVQT, w którym będzie umieszczać swoje
obiekty. Jednak w rzeczywistości będą umieszczane tam instancje klasy 5VWD PVT[ wska-
zujące, gdzie znajdują się właściwe obiekty. Natomiast właściwe obiekty zostaną umiesz-
czone w buforze lub na dysku (w obiekcie 1DLGEV(KNG). Klasa 5VWD PVT[ posiada tylko
dwie składowe: znacznik informujący o tym, czy obiekt znajduje się w buforze oraz in-
deks dostępu do obiektu znajdującego się na dysku:
ENCUU5VWD PVT[
]
PCEPKMKPHQTOWLæE[E[GNGOGPVPCLFWLGUKúYDWHEQTGE[PCF[UMW
DQQNGCPKP CEJG
9UMCļPKMRQ[ELKRNKMWIF[GNGOGPVPCLFWLGUKúPECF[UMW
NQPIHKNG2QKPVGT
_
Klasa wewnętrzna CEJG PVT[ wykorzystywana jest do przechowywania obiektów użyt-
kownika w buforze. Umieszcza także klucz w tablicy mieszającej, w której będzie prze-
chowywany obiekt oraz referencje poprzedniego i następnego elementu listy LRU. Każdy
obiekt klasy CEJG PVT[ jest umieszczany w tablicy mieszającej *CUJVCDNG przy zastoso-
waniu klucza, który przechowywany jest także wewnątrz danego obiektu klasy CEJG
PVT[. Efektywność takiego rozwiązania zmniejsza nieco fakt, że klucz tablicy mie-
szającej musi być obiektem, gdy w rzeczywistości jest on zwykłym indeksem obiektu
5VWD PVT[ w tablicy. Użycie indeksów tablicy jako kluczy zapewnia przy tym dosko-
nały, bezkolizyjny wynik funkcji mieszającej. Inna, nieco bardziej efektywna możli-
wość polegałaby na przechowywaniu kluczy w postaci obiektów klasy +PVGIGT w obiek-
tach klasy 5VWD PVT[. W ten sposób zostałaby ograniczona liczba generowanych kluczy.
Umieszczenie w obiektach klasy CEJG PVT[ referencji poprzedniego i następnego ele-
mentu listy sprawia, że pełnią one podwójna funkcję elementu tablicy mieszającej i ele-
mentu dwukierunkowej listy LRU.
ENCUU CEJG PVT[
]
-NWEGNGOGPVWDWHQTC5VQUWLGO[QDKGMV+PVGIGET
QFRQYKCFCLæE[KPFGMUQYKGNGOGPVWYGMVQTC
+PVGIGTMG[
1DKGMVRTGEJQY[YCP[YDWHQTG
1DLGEVQ
4GHGTGPELGRQRTGFPKGIQKPCUVúRPGIQGNGOGPEVWNKUV[
CEJG PVT[RTGXPGZV
_
Dostęp do dwukierunkowej listy LRU jest możliwy dzięki referencjom znajdującym
się w klasie 2GTUKUVGPV CEJG8GEVQT. Jedna z nich wskazuje początek listy (HKTUV CEJG
PVT[), a druga jej koniec (NCUV CEJG PVT[). Zadaniem listy dwukierunkowej jest okre-
ślenie najrzadziej wykorzystywanego elementu bufora. Za każdym razem, gdy korzysta-
my z pewnego elementu bufora, zostaje on przesunięty na początek listy. W ten sposób
Rozdział 3. ♦ Użyteczne klasy i kolekcje
101
ostatni element listy reprezentuje najrzadziej używany element. Większość kodu klasy
2GTUKUVGPV CEJG8GEVQT właśnie zarządza listą dwukierunkową. Poniżej zaprezentowano
fragment umieszczający instancję klasy CEJG PVT[ (o nazwie EG) na liście LRU. Działa
on w następujący sposób: jeśli lista nie jest pusta, to umieszcza nowy element na jej po-
czątku i w nim referencje obiektu, który dotychczas stanowił czoło listy jako referencję
następnego obiektu listy. Po czym referencję obiektu EG umieszcza w obiekcie, który
dotychczas stanowił czoło listy jako referencję poprzedniego elementu listy. Na koniec
nadaje nową wartość referencji wskazującej początek listy. Natomiast w przypadku,
gdy lista jest pusta, inicjuje referencje początku i końca listy za pomocą referencji no-
wego elementu.
YUVCYKCGNGOGPVFQNKUV[
KH
NCUV CEJG PVT[PWNN
]
WOKGUECIQPCRQEæVMWNKUV[
EGPGZVHKTUV CEJG PVT[
HKTUV CEJG PVT[RTGXEG
HKTUV CEJG PVT[EG
_
GNUG
]
NKUVCLGUVRWUVC
HKTUV CEJG PVT[NCUV CEJG PVT[EG
_
Klasa 1DLGEV(KNG przechowuje serializowane obiekty w pliku o dostępie swobodnym,
reprezentowanym przez klasę 4CPFQO#EEGUU(KNG. Serializowany obiekt jest przechowy-
wany w postaci tablicy bajtów. Aby zapisać tablicę bajtów za pomocą obiektu klasy
4CPFQO#EEGUU(KNG nie są potrzebne żadne dodatkowe dane. Jednak, aby odczytać ta-
blicę bajtów z pliku, musimy znać jej wielkość. Dlatego też w pliku jest zapisywana naj-
pierw wartość całkowita, a następnie tablica bajtów. Wartość ta określa liczbę bajtów
tablicy. Klasa 1DLGEV(KNG zawiera instancję klasy 4CPFQO#EEGUU(KNG i implementuje
metody zapisu i odczytu obiektów w omówionej postaci.
RWDNKEENCUU1DLGEV(KNG
]
4CPFQO#EEGUU(KNGFCVC(KNG
5VTKPIU(KNG0COG
RWDNKE1DLGEV(KNG
5VTKPIU0COGVJTQYU+1 ZEGRVKQP
]
U(KNG0COGU0COG
FCVC(KNGPGY4CPFQO#EEGUU(KNG
U0COGTY
_
Dla potrzeb naszego przykładu klasa 2GTUKUVGPV CEJG#TTC[ posiada dodatkowo metodę
OCKP
umożliwiającą jej przetestowanie. Poniżej przedstawiamy efekt wykonania te-
stów umieszczonych w tej metodzie:
CFFKPIQDLGEVU
5KG
6GUVKPIIGV
0QYVJGGNGOGPVCVKPFGZKU
102
Java. Potrzaski
5KGKU
6GUVKPITGOQXG
5KG
4GOQXKPI
5KG
(KTUV
Oto pełny kod źródłowy klasy 2GTUKUVGPV CEJG8GEVQT:
2GTUKUVGPV CEJG8GEVQTLCXC
RCEMCIGLYKNG[GHHGEVKXG
KORQTVLCXCKQ
KORQTVLCXCWVKN
1FRQYKGFPKMMNCU[8GEVQTWľ[YCLæE[DWHQTC.47KWOKGUEECLæE[
PCF[UMWPCFOKCTQYGQDKGMV[
RWDNKEENCUU2GTUKUVGPV CEJG8GEVQTKORNGOGPVU NQPEGCDNG5GTKCNKCDNG
]
.KEPKMWVYQTQP[EJQDKGMVÎY
UVCVKENQPIN QWPV
/CMU[OCNP[TQOKCTDWHQTC
KPVK/CZ CEJG5KG
$KGľæE[TQOKCTDWHQTC
KPVK CEJG5KG
$WHQT
*CUJVCDNGECEJGPGY*CUJVCDNG
1FDKEKGMNCU[8GEVQT2TGEJQYWLGLGF[PKG
QDKGMVMNCU[8GEVQT PVT[FNCMCľFGIQYUVCYKCPGIQEQDKGMVW
8GEVQTTQYUPGY8GEVQT
1DLGEV(KNGRTGEJQYWLGQDKGMV[PCF[UMW
UGG1DLGEV(KNG
1DLGEV(KNGQH
0CYCRNKMWYMVÎT[ORTGEJQY[YCPGUæQDKGMV[
5VTKPIU6OR0COG
2QEæVGMNKUV[.472KGTYU[GNGOGPVTGRTGGPVWLG
PCLEúħEKGL
QUVCVPKQWľ[YCP[GNGOGPVDWHQTC
CEJG PVT[HKTUV CEJG PVT[
-QPKGENKUV[.471UVCVPKGNGOGPVTGRTGGPVWLG
PCLTCFKGL
QUVCVPKQWľ[YCP[GNGOGPVDWHQTC
CEJG PVT[NCUV CEJG PVT[
-NCUCYGYPúVTPCPCOKCUVMK
ENCUU5VWD PVT[
]
PCEPKMKPHQTOWLæE[E[GNGOGPVPCLFWLGUKúYDWEHQTGE[PC
F[UMW
DQQNGCPKP CEJG
9UMCļPKMRQ[ELKRNKMWIF[GNGOGPVPCLFWLGUKúPECF[UMW
Rozdział 3. ♦ Użyteczne klasy i kolekcje
103
NQPIHKNG2QKPVGT
_
-NCUCYGYPúVTPCTGRTGGPVWLæECGNGOGPVDWHQTC
ENCUU CEJG PVT[
]
-NWEGNGOGPVWDWHQTC5VQUWLGO[QDKGMV+PVGIGET
QFRQYKCFCLæE[KPFGMUQYKGNGOGPVWYGMVQTC
+PVGIGTMG[
1DKGMVRTGEJQY[YCP[YDWHQTG
1DLGEVQ
4GHGTGPELGRQRTGFPKGIQKPCUVúRPGIQGNGOGEPVWNKUV[
CEJG PVT[RTGXPGZV
_
-QPUVTWMVQTQMTGħNCLæE[TQOKCTDWHQTC2NKMPKGLGUEVQVYKGTCP[
FQRÎMKPKGQUVCPKGRTGMTQEQP[TQOKCTDWHQTC
RCTCOK CEJG5KG/CMU[OCNP[TQOKCTDWHQTC
RWDNKE2GTUKUVGPV CEJG8GEVQT
KPVK CEJG5KG
]
VJKUK/CZ CEJG5KGK CEJG5KG
_
RTKXCVGHKPCNXQKFQRGP6GOR(KNG
VJTQYU+1 ZEGRVKQEP
]
DQQNGCPD+P8CNKFVTWG
YJKNG
D+P8CNKF
]
U6OR0COGVOR
5[UVGOEWTTGPV6KOG/KNNKU
E
N QWPV
QDH
(KNGHPGY(KNG
U6OR0COG
KH
HGZKUVU
D+P8CNKFHCNUG
_
QHPGY1DLGEV(KNG
U6OR0COG
_
/GVQFCYUVCYKCPKCGNGOGPVWFQYGMVQTC NGOGPVQEUVCLG
WOKGUEQP[YDWHQTGNWDPCF[UMW
RCTCOQ1DKGMVFQFCYCP[FQYGMVQTC
RWDNKEHKPCNXQKFCFF
5GTKCNKCDNGQVJTQYU+1 ZEGREVKQP
]
5VWD PVT[GPGY5VWD PVT[
TQYUCFF
G
KH
K CEJG5KGK/CZ CEJG5KG
]
GKP CEJGVTWG
104
Java. Potrzaski
CEJG PVT[EGPGY CEJG PVT[
EGQQ
EGMG[PGY+PVGIGT
TQYUUKG
ECEJGRWV
EGMG[EG
K CEJG5KG
YUVCYKCGNGOGPVFQNKUV[
KH
NCUV CEJG PVT[PWNN
]
WOKGUECIQPCRQEæVMWNKUV[
EGPGZVHKTUV CEJG PVT[
HKTUV CEJG PVT[RTGXEG
HKTUV CEJG PVT[EG
_
GNUG
]
NKUVCLGUVRWUVC
HKTUV CEJG PVT[NCUV CEJG PVT[EG
_
_
GNUG
]
KH
QHPWNN
QRGP6GOR(KNG
GHKNG2QKPVGTQHYTKVG1DLGEV
Q
_
_
/GVQFCFQUVúRWFQGNGOGPVWYGMVQTCQRQFCP[OKEPFGMUKG
1DKGMVRQDKGTCP[LGUVDWHQTCNWDRNKMW
RCTCOKFZ+PFGMURQDKGTCPGIQGNGOGPVW
TGVWTPUQDKGMVWOKGUEQP[YYGMVQTG
RWDNKEHKPCN1DLGEVIGV
KPVKFZVJTQYU+PFGZ1WV1H$EQWPFU ZEGRVKQP
+1 ZEGERVKQP
]
KH
KFZ^^KFZ TQYUUKG
VJTQYPGY+PFGZ1WV1H$QWPFU ZEGRVKQP
+PFGZE
KFZ
QWVEQHDQWPFU
5VWD PVT[G
5VWD PVT[TQYUIGV
KFZ
1DLGEVQPWNN
KH
GKP CEJG
]
RQDKGTCGNGOGPV
CEJG PVT[EGPWNN
EG
CEJG PVT[ECEJGIGV
PGY+PVGIGT
KFZ
KH
EGPWNN
VJTQYPGY+1 ZEGRVKQP
NGOGPVCVKFZ
KEFZ
KU07..
KH
EGPWNNEGQPWNN
Rozdział 3. ♦ Użyteczne klasy i kolekcje
105
VJTQYPGY+1 ZEGRVKQP
CEJG NGOGPV UQDLGEEVCVKFZ
KFZ
016KPEECEJG
QEGQ
KH
EGHKTUV CEJG PVT[
]
WUWYCIQNKUV[
KH
EGPGZVPWNN
EGPGZVRTGXEGRTGX
GNUGQUVCVPKGNGOGPVNKUV[
NCUV CEJG PVT[EGRTGX
EGRTGXPGZVEGPGZV
KYUVCYKCPCRQEæVGMNKUV[
EGPGZVHKTUV CEJG PVT[
EGRTGXPWNN
HKTUV CEJG PVT[RTGXEG
HKTUV CEJG PVT[EG
_
_
GNUG
]
QDKGMVYDWHQTG
GKP CEJGVTWG
RQDKGTCPKGKYUVCYKCPKGFQDWHQTC
VT[
]
QQHTGCF1DLGEV
GHKNG2QKPVGT
_ECVEJ
NCUU0QV(QWPF ZEGRVKQPEPHG
]VJTQYPGY+1 ZEGRVKQP
EPHGIGV/GUUCIG
_
5RTCYFCE[DWHQTPKGLGUVRGđP[
KH
K CEJG5KGK/CZ CEJG5KG
]
WUWYCGNGOGPVPCLFWLæE[UKúPCMQēEWNKUEV[
CEJG PVT[NGCUV7UGFNCUV CEJG PVT[
KH
NGCUV7UGFRTGXPWNN
]
NGCUV7UGFRTGXPGZVPWNN
NCUV CEJG PVT[NGCUV7UGFRTGX
NCUV CEJG PVT[PGZVPWNN
_
GNUG
]
WUWYCLGF[P[GNGOGPVNKUV[
HKTUV CEJG PVT[NCUV CEJG PVT[PWENN
_
YUVCYKCRQDTCP[GNGOGPVFQDWHQTC
CEJG PVT[EGPGY CEJG PVT[
EGQQ
EGMG[PGY+PVGIGT
KFZ
ECEJGRWV
EGMG[EG
106
Java. Potrzaski
WOKGUECIQPCNKħEKG.47
KH
NCUV CEJG PVT[PWNN
]
YUVCYKCPCRQEæVGMNKUV[
EGPGZVHKTUV CEJG PVT[
HKTUV CEJG PVT[RTGXEG
HKTUV CEJG PVT[EG
_
GNUG
]
NKUVCLGUVRWUVC
HKTUV CEJG PVT[NCUV CEJG PVT[EGE
_
RQDKGTC5VWD PVT[WUWYCPGIQQDKGMVW
5VWD PVT[QWV5VWD PVT[
5VWD PVT[
TQYUIGV
NGCUV7UGFMG[KPV8CNWG
WUWYCQDKGMVDWHQTC
CEJG PVT[QWV CEJG PVT[
CEJG PVT[
ECEJGTGOQXG
NGCUV7UGFMG[
KH
QWV CEJG PVT[PWNN
VJTQYPGY4WPVKOG ZEGRVKQP
CEJG PVT[ECV
NGCUV7UGFMG[
KUE0WNN
KH
QWV CEJG PVT[PWNNQWV CEJG PVT[QEPWNN
VJTQYPGY4WPVKOG ZEGRVKQP
CEJGQDLGEEVCV
NGCUV7UGFMG[
KUE0WNN
1DLGEVQWV1DLGEVQWV CEJG PVT[Q
QWV5VWD PVT[KP CEJGHCNUG
KH
QWV5VWD PVT[HKNG2QKPVGT
]
WOKGUEQP[YDWHQTG
QWV5VWD PVT[HKNG2QKPVGT
QHYTKVG1DLGEV
5GTKCNKCDNEGQWV1DLGEV
_
GNUG
]
PCLFWLGLWľUKúYRNKMWŌOKCPCTQOKCETW!
KPVK WTTGPV5KG
QHIGV1DLGEV.GPIVJ
QWV5VWD PVT[HKNG2EQKPVGT
$[VG#TTC[1WVRWV5VTGCODCQUPGY$[VG#TETC[1WVRWV5VTGCO
1DLGEV1WVRWV5VTGCOQQUPGY1DLGEVE1WVRWV5VTGCO
DCQU
QQUYTKVG1DLGEV
5GTKCNKCDNGQWV1DLGEVE
QQUHNWUJ
KPVFCVCNGPDCQUUKG
KH
FCVCNGPK WTTGPV5KG
QHTGYTKVG1DLGEV
QWV5VWD PVT[HKNG2EQKPVGT
DCQUVQ$[VG#TTCE[
GNUG
QWV5VWD PVT[HKNG2QKPVGT
Rozdział 3. ♦ Użyteczne klasy i kolekcje
107
QHYTKVG1DLGEV
5GTKECNKCDNGQWV1DLGEV
DCQUPWNN
QQUPWNN
QWV1DLGEVPWNN
_
_
GNUG
]
CEJG PVT[EGPGY CEJG PVT[
EGQQ
EGMG[PGY+PVGIGT
KFZ
ECEJGRWV
EGMG[EG
K CEJG5KG
YUVCYKCPCNKUVú.47
KH
NCUV CEJG PVT[PWNN
]
PCRQEæVGMNKUV[
EGPGZVHKTUV CEJG PVT[
HKTUV CEJG PVT[RTGXEG
HKTUV CEJG PVT[EG
_
GNUG
]
NKUVCLGUVRWUVC
HKTUV CEJG PVT[NCUV CEJG PVT[EGE
_
_
_
TGVWTPQ
_
/GVQF[RQOKPKúVGGYINúFWPCDTCMOKGLUEC
_
Poniżej przedstawiamy kod źródłowy klasy 1DLGEV(KNG:
1DLGEV(KNGLCXC
RCEMCIGLYKNG[GHHGEVKXG
KORQTVLCXCKQ
KORQTVLCXCWVKN
RWDNKEENCUU1DLGEV(KNG
]
4CPFQO#EEGUU(KNGFCVC(KNG
5VTKPIU(KNG0COG
RWDNKE1DLGEV(KNG
5VTKPIU0COGVJTQYU+1 ZEGRVKQP
]
U(KNG0COGU0COG
FCVC(KNGPGY4CPFQO#EEGUU(KNG
U0COGTY
_
YTCECRQ[ELúRNKMWPCMVÎTGLCRKUCPQQDKGMV
108
Java. Potrzaski
RWDNKEU[PEJTQPKGFNQPIYTKVG1DLGEV
5GTKCNKCDNGQDELVJTQYU+1 ZEGRVKQP
]
$[VG#TTC[1WVRWV5VTGCODCQUPGY$[VG#TTC[1WVRWV5EVTGCO
1DLGEV1WVRWV5VTGCOQQUPGY1DLGEV1WVRWV5VTGCEO
DCQU
QQUYTKVG1DLGEV
QDL
QQUHNWUJ
KPVFCVCNGPDCQUUKG
FQđæECTGMQTF
NQPIRQUFCVC(KNGNGPIVJ
FCVC(KNGUGGM
RQU
CRKUWLGTQOKCTFCP[EJ
FCVC(KNGYTKVG+PV
FCVCNGP
FCVC(KNGYTKVG
DCQUVQ$[VG#TTC[
DCQUPWNNQQUPWNN
TGVWTPRQU
_
RQDKGTCDKGľæE[TQOKCTQDKGMVW
RWDNKEU[PEJTQPKGFKPVIGV1DLGEV.GPIVJ
NQPIN2QUEVJTQYU+1 ZEGRVKQP
]
FCVC(KNGUGGM
N2QU
TGVWTPFCVC(KNGTGCF+PV
_
RWDNKEU[PEJTQPKGF1DLGEVTGCF1DLGEV
NQPIN2QU
VJTQYU+1 ZEGRVKQP NCUU0QV(QWPF ZEGRVEKQP
]
FCVC(KNGUGGM
N2QU
KPVFCVCNGPFCVC(KNGTGCF+PV
KH
FCVCNGP FCVC(KNGNGPIVJ
VJTQYPGY+1 ZEGRVKQP
CVCHKNGKUEQTTWRVGEFFCVCNGP
FCVCNGP
D[VG=?FCVCPGYD[VG=FCVCNGP?
FCVC(KNGTGCF(WNN[
FCVC
$[VG#TTC[+PRWV5VTGCODCKUPGY$[VG#TTC[+PRWV5VTGECO
FCVC
1DLGEV+PRWV5VTGCOQKUPGY1DLGEV+PRWV5VTGCO
EDCKU
1DLGEVQQKUTGCF1DLGEV
DCKUPWNNKVGO
QKUPWNN
FCVCPWNN
TGVWTPQ
_
RWDNKENQPINGPIVJ
VJTQYU+1 ZEGRVKQP
]
TGVWTPFCVC(KNGNGPIVJ
_
RWDNKEXQKFENQUG
VJTQYU+1 ZEGRVKQP
Rozdział 3. ♦ Użyteczne klasy i kolekcje
109
]
FCVC(KNGENQUG
_
/GVQF[RQOKPKúVGGYINúFWPCDTCMOKGLUEC
_MQPKGEMNCU[1DLGEV(KNG
W zagadnieniu tym przedstawiono połączenie bufora .47 i klasy umożliwiającej trwałe
przechowywanie obiektów (1DLGEV(KNG), w wyniku którego uzyskano efektywne rozwią-
zanie problemu obsługi sporadycznie pojawiających się kolekcji o znacznych rozmia-
rach. Potrafi ono wydajnie obsłużyć typowy przypadek, w którym występuje niewiele
danych oraz charakteryzuje się niezawodnością w momencie pojawienia się wyjątkowo
dużej ilości danych. Tworzenie takich niezawodnych, choć nie zawsze efektownych roz-
wiązań cechuje najlepszych programistów.
Zagadnienie 20. Plik właściwości
czy zestaw zasobów?
Proszę sobie wyobrazić, że ktoś rozpoczął właśnie pracę dla nowo powstałej firmy
LOA, która zamierza odebrać część internetowego tortu America Online. Dowiedział
się, że Sun Microsystems zgodziła się reklamować usługi firmy, w której ten ktoś za-
cznie pracować, użytkownikom swojego nowego systemu operacyjnego napisanego
w całości w Javie. System będzie sprzedawany na całym świecie, a dołączana do nie-
go aplikacja firmy LOA na razie pracuje jedynie w języku angielskim. Zadaniem no-
wego pracownika jest wyposażenie jej w możliwości obsługi innych języków. Ma czas
do końca tygodnia.
Ponieważ jako programista jest on odpowiedzialny jedynie za okno pokazywane użyt-
kownikowi podczas uruchamiania programu, to powierzone zadanie wydaje się wyko-
nalne. W obecnej wersji okno to pobiera wyświetlane informacje z pliku właściwości.
Wystarczy więc utworzyć takie pliki zawierające informacje w innych językach i opra-
cować wymienne moduły wyświetlającego je kodu. Jednak menedżer informuje, że
jeden i ten sam moduł kodu powinien obsługiwać wszystkie języki. Dlatego kolejnym
pomysłem jest wczytywanie właściwości systemu zawierających informacje o wybranym
języku. Dzięki tej informacji możliwe będzie następnie wczytanie zawartości odpowied-
niego pliku właściwości. W czasie przerwy w pracy nowy pracownik zwierza się ze
swojego pomysłu jednemu z bardziej doświadczonych programistów. Pochwala on ta-
kie rozwiązanie, informując jednocześnie, że firma Sun dawno je opracowała. Poleca
więc zapoznanie się z klasą 4GUQWTEG$WPFNG.
Klasa 4GUQWTEG$WPFNG różni się od klasy 2TQRGTVKGU w wielu aspektach. Klasa 4GUQWTEG
$WPFNG i jej klasy pochodne .KUV4GUQWTEG$WPFNG i 2TQRGTV[4GUQWTEG$WPFNG zaprojek-
towano tak, by wykorzystywały klasę .QECNG do obsługi danych zależnych od kraju,
w którym mieszka użytkownik programu. Natomiast klasa 2TQRGTVKGU nie używa klasy
.QECNG, ponieważ jej zadaniem jest jedynie przechowywanie par obiektów klasy 5VTKPI
reprezentujących klucz i odpowiadającą mu wartość. Dlatego też klasę 2TQRGTVKGU,
w przeciwieństwie do klasy 4GUQWTEG$WPFNG, stosujemy do przechowywania łańcuchów
110
Java. Potrzaski
znaków 5VTKPI, które nie podlegają lokalizacji. W ten sposób powinno się oddzielić
w programie dane, które podlegają lokalizacji od tych, które są niezależne od języka
aplikacji. Kolejna różnica pomiędzy klasami 4GUQWTEG$WPFNG i klasą 2TQRGTVKGU polega
na tym, że klasa .KUV4GUQWTEG$WPFNG umożliwia przechowywanie klucza klasy 5VTKPI
i wartości klasy 1DLGEV. W praktyce oznacza to, że można przechowywać w niej war-
tość będącą obiektem dowolnej klasy. Natomiast klasa 2TQRGTVKGU umożliwia przecho-
wywanie jedynie łańcuchów znakowych klasy 5VTKPI.
Pierwszym krokiem związanym z internacjonalizacją okna programu będzie określe-
nie, które dane zależą od lokalizacji użytkownika. Aby lepiej zrozumieć jakich danych
może to dotyczyć, przyjrzyjmy się bliżej klasie .QECNG. Klasa ta musi uwzględniać nie
tylko język, którym posługuje się użytkownik programu, ale także kraj, w którym on
mieszka. W wielu krajach używa się bowiem tego samego języka, ale zapisuje liczby
i daty w różnych formatach. Trzecim parametrem klasy .QECNG jest wariant. Umożliwia
on programiście wyspecjalizowanie dodatkowych różnic w stosunku do podstawowych
formatów. W naszym przypadku internacjonalizacji będzie podlegać jedynie tekst wy-
świetlany w oknie i na przyciskach.
W celu wyświetlania tekstu w różnych językach trzeba stworzyć zestaw zasobów klasy
4GUQWTEG$WPFNG zawierający pliki właściwości. Przez zestaw zasobów rozumiemy w tym
przypadku grupę plików zawierających te same dane poddane procesowi lokalizacji
dla różnych krajów i języków. Takich zestawów zasobów możemy opracować dowolnie
wiele. W naszym przykładzie stworzymy dwa: jeden zawierający tekst powitania wy-
świetlany w oknie oraz drugi, w którym umieścimy opisy wszystkich przycisków okna.
Ponieważ internacjonalizacji podlega jedynie tekst, to zestawy zasobów zawierać będą
tylko pliki właściwości (w ogólnym przypadku mogą to być pliki właściwości i klasy
języka Java). Zaletą takiego rozwiązania jest to, że, oddzielając w ten sposób kod od
danych, możemy przekazać tłumaczom tylko same pliki właściwości.
Zestaw zasobów uzyskujemy, wywołując metodę 4GUQWTEG$WPFNGIGV$WPFNG
. Prze-
kazuje się jej jako parametr obiekt klasy .QECNG lub pozwala skorzystać z domyślnego
obiektu .QECNG. Aby klasa 4GUQWTEG$WPFNG mogła znaleźć odpowiedni plik właściwo-
ści lub klasę, trzeba zachować odpowiednią konwencję tworzenia nazw plików właści-
wości i klas. Dokumentacja javadoc wyjaśnia dokładnie sposoby tworzenia takich nazw.
Poniżej przedstawiono konwencję nazw w kolejności, w której poszukuje jej kod klasy
4GUQWTEG$WPFNG, aby odnaleźć odpowiedni zasób:
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
A
XCTKCPV
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
A
XCTKCPV
ERTQRGTVKGU
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
RTQRGTVKGU
DCUGENCUU
A
NCPIWCIG
DCUGENCUU
A
NCPIWCIG
RTQRGTVKGU
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
A
XCTKCPV
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
A
XCTKCPV
ERTQRGTVKGU
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
DCUGENCUU
A
NCPIWCIG
A
EQWPVT[
RTQRGTVKGU
DCUGENCUU
A
NCPIWCIG
DCUGENCUU
A
NCPIWCIG
RTQRGTVKGU
DCUGENCUU
DCUGENCUU
RTQRGTVKGU
Rozdział 3. ♦ Użyteczne klasy i kolekcje
111
Załóżmy na przykład, że metodzie IGV$WPFNG
przekazaliśmy obiekt klasy .QECNG za-
wierający kod języka niemieckiego (FG) i kod Szwajcarii ( *). Domyślny obiekt klasy
.QECNG zawiera natomiast kod języka angielskiego (GP) i Stanów Zjednoczonych (75).
Przypuśćmy, że klasę bazową tekstu powitania nazwaliśmy 5VCTVWR/GUUCIG. Aby ustalić,
jakich nazw zasobów będzie poszukiwać klasa 4GUQWTEG$WPFNG, musimy zastąpić w po-
wyższym schemacie parametr DCUGENCUU nazwą 5VCTVWR/GUUCIG, parametr NCPIWCIG
— łańcuchem FG, parametr EQWPVT[ — łańcuchem *, parametr NCPIWCIG — łań-
cuchem GP i parametr EQWPVT[ — łańcuchem 75. Ustalimy w ten sposób, że program
będzie próbować znaleźć kolejno następujące zasoby: 5VCTVWR/GUUCIGAFGA *, 5VCTVWR
/GUUCIGAFGA *RTQRGTVKGU, 5VCTVWR/GUUCIGAFG, 5VCTVWR/GUUCIGAFGRTQRGTVKGU,
5VCTVWR/GUUCIGAGPA75, 5VCTVWR/GUUCIGAGPA75RTQRGTVKGU, 5VCTVWR/GUUCIGAGP,
5VCTVWR/GUUCIGAGPRTQRGTVKGU, 5VCTVWR/GUUCIG, 5VCTVWR/GUUCIGRTQRGTVKGU.
Tworzenie zestawu zasobów najlepiej rozpoczynać zawsze od podstawowego. Dzięki
temu kod zawsze znajdzie przynajmniej podstawowy zasób w przypadku, gdy nie bę-
dzie dostępny zasób odpowiadający przekazanemu lub domyślnemu obiektowi klasy
.QECNG. Najpierw utworzymy więc podstawowy plik właściwości. Będzie on posiadać
nazwę 5VCTVWR/GUUCIG i następującą zawartość:
5VCTVWR5ETGGPOGUUCIG9GNEQOGVQ.1#2NGCUGRTGUU1E-VQKPUVCNNQWTUQHVYCTG
1VJGTYKUGRTGUU #0 .VQGZKV
Następnie utworzymy plik właściwości dla domyślnego obiektu klasy .QECNG o nazwie
5VCTVWR/GUUCIGAGPA75RTQRGTVKGU. Zawiera on takie same informacje jak podstawowy
plik właściwości. Skoro jednak informacja w obu plikach jest identyczna, to po co two-
rzyć plik podstawowy. Załóżmy, że obiekt klasy .QECNG przekazany metodzie IGV$WPFNG
dotyczy Chin, a obiekt domyślny Japonii. Ponieważ zestaw zasobów nie zawiera plików
właściwości dla języka chińskiego ani japońskiego, to posłuży się właśnie plikiem pod-
stawowym. Gdy w zestawie zasobów nie umieścimy pliku podstawowego, wówczas
w opisanym przypadku zostanie wyrzucony wyjątek /KUUKPI4GUQWTEG ZEGRVKQP.
Następnie utworzymy domyślny zasób opisujący teksty przycisków. Nazwiemy go
5VCTVWR$WVVQPRTQRGTVKGU. Zawiera on następujące informacje:
5VCTVWR$WVVQPQM1-
5VCTVWR$WVVQPECPEGN #0 .
Ponownie utworzymy też zasób dla domyślnego obiektu klasy PVKV[ o takiej samej za-
wartości. Nazwiemy go 5VCTVWR$WVVQPAGPA75RTQRGTVKGU.
Po oddzieleniu zasobów od kodu programu zobaczmy, w jaki sposób może korzystać
z nich program.
Poniższy fragment kodu wczytuje zasób 5VCTVWR/GUUCIG dla domyślnego obiektu kla-
sy .QECNG:
4GUQWTEG$WPFNGUVCTVWR/GUUCIG$WPFNG
UVCTVWR/GUUCIG$WPFNG4GUQWTEG$WPFNGIGV$WPFNG
5VCTEVWR/GUUCIG
5VTKPIOGUUCIGUVCTVWR/GUUCIG$WPFNGIGV5VTKPI
5VCETVWR5ETGGPOGUUCIG
Podobnie poniższy fragment kodu wczyta zasób 5VCTVWR$WVVQP dla domyślnego obiektu
klasy .QECNG:
112
Java. Potrzaski
4GUQWTEG$WPFNGUVCTVWR$WVVQP$WPFNG
UVCTVWR$WVVQP$WPFNG4GUQWTEG$WPFNGIGV$WPFNG
5VCTVEWR$WVVQP
5VTKPIQM$WVVQPUVCTVWR$WVVQP$WPFNGIGV5VTKPI
5VCTEVWR$WVVQPQM
Jeśli domyślny obiekt klasy .QECNG odpowiada językowi angielskiemu (GP) i USA (75),
to zostaną załadowane pliki 5VCTVWR/GUUCIGAGPA75RTQRGTVKGU oraz 5VCTVWR$WVVQPA
GPA75RTQRGTVKGU. Zaletą przedstawionego rozwiązania jest to, że kod programu nie
musi zmieniać się ze zmianą języka wyświetlanych komunikatów. Wystarczy, że tłu-
macz stworzy nowy plik właściwości i odpowiednio go nazwie. W ten sposób jeden
i ten sam fragment kodu może obsługiwać wiele języków.
Problematyka internacjonalizacji oprogramowania jest rozległa. W zagadnieniu tym skon-
centrowaliśmy się na omówieniu różnic pomiędzy klasami 2TQRGTVKGU i 4GUQWTEG$WPFNG
i przedstawieniu podstawowych sposobów posługiwania się klasą 4GUQWTEG$WPFNG. Moż-
na więc potraktować go jedynie jako wprowadzenie do tematu. Język Java dysponuje
jeszcze innymi klasami wspierającymi programistę podczas internacjonalizacji pro-
gramów, na przykład CVG(QTOCV, 0WODGT(QTOCV i /GUUCIG(QTOCV.
Zagadnienie 21.
Pułapki klasy Properties
Jeśli Czytelnik programuje długo w języku Java, to z pewnością używał już obiektów
klasy 2TQRGTVKGU. Mógł nawet przyjąć, że klasa ta stanowi cudowny środek, który raz
na zawsze uwalnia programistę od konieczności kodowania wartości bezpośrednio w ko-
dzie programu. Jeśli natomiast nie korzystał jeszcze z klasy 2TQRGTVKGU w swoich progra-
Pobierz darmowy fragment (pdf)