Java. Potrzaski

33
Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: [email protected] PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ IDZ DO IDZ DO ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG KATALOG KSI¥¯EK KATALOG KSI¥¯EK TWÓJ KOSZYK TWÓJ KOSZYK CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE O NOWOCIACH ZAMÓW INFORMACJE O NOWOCIACH ZAMÓW CENNIK ZAMÓW CENNI K CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE SPIS TRECI SPIS TRECI DODAJ DO KOSZYKA DODAJ DO KOSZYKA KATALOG ONLINE KATALOG ONLINE Java. Potrzaski 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ê wydajnoci 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 • Wejcie i wyjcie, w tym subtelnoci 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

description

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

Transcript of Java. Potrzaski

Page 1: Java. Potrzaski

Wydawnictwo Helion

ul. Chopina 6

44-100 Gliwice

tel. (32)230-98-63

e-mail: [email protected]

PRZYK£ADOWY ROZDZIA£PRZYK£ADOWY ROZDZIA£

IDZ DOIDZ DO

ZAMÓW DRUKOWANY KATALOGZAMÓW DRUKOWANY KATALOG

KATALOG KSI¥¯EKKATALOG KSI¥¯EK

TWÓJ KOSZYKTWÓJ KOSZYK

CENNIK I INFORMACJECENNIK I INFORMACJE

ZAMÓW INFORMACJEO NOWO�CIACH

ZAMÓW INFORMACJEO NOWO�CIACH

ZAMÓW CENNIKZAMÓW CENNIK

CZYTELNIACZYTELNIA

FRAGMENTY KSI¥¯EK ONLINEFRAGMENTY KSI¥¯EK ONLINE

SPIS TRE�CISPIS TRE�CI

DODAJ DO KOSZYKADODAJ DO KOSZYKA

KATALOG ONLINEKATALOG ONLINE

Java. Potrzaski

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

Page 2: Java. Potrzaski

Spis treści

Wstęp ............................................................................................... 9

Rozdział 1. Składnia języka................................................................................ 13Zagadnienie 1. Przesłanianie metod statycznych........................................................14Zagadnienie 2. Zastosowanie metody equals() i operatora ==dla obiektów klasy String ......................................................................................16

Zagadnienie 3. Kontrola zgodności typów w języku Java ...........................................19Konwersja typów..............................................................................................20Rozszerzanie ....................................................................................................21Zawężanie ........................................................................................................22Niejawne konwersje typów................................................................................22

Zagadnienie 4. Czy to jest konstruktor? ....................................................................23Zagadnienie 5. Brak dostępu do przesłoniętej metody ................................................25Zagadnienie 6. Pułapka ukrytego pola.......................................................................27

Rodzaje zmiennych w języku Java .....................................................................29Zakres deklaracji zmiennej.................................................................................29Które zmienne mogą być ukrywane? ..................................................................30Ukrywanie zmiennych instancji i zmiennych klas.................................................30Dostęp do ukrytych pól......................................................................................32Różnice pomiędzy ukrywaniem pól i przesłanianiem metod..................................33

Zagadnienie 7. Referencje wyprzedzające.................................................................34Zagadnienie 8. Konstruktory i projektowanie klas......................................................35Zagadnienie 9. Przekazywanie typów prostych przez referencję..................................42Zagadnienie 10. Wyrażenia i operatory logiczne ........................................................45

Rozdział 2. Funkcjonalność wbudowana w język Java ......................................... 47Zagadnienie 11. Odzyskiwanie pamięci za pomocą obiektów SoftReference ................48

Odzyskiwanie pamięci.......................................................................................48Klasa SoftReference..........................................................................................50Kolejki referencji ..............................................................................................55

Zagadnienie 12. Zakleszczenie na skutek wywołania metody synchronizowanejprzez metodę synchronizowaną .............................................................................57Wątki, monitory i słowo kluczowe synchronized..................................................57Przykładowy scenariusz zakleszczenia ................................................................61

Zagadnienie 13. Klonowanie obiektów .....................................................................65Zagadnienie 14. Przesłanianie metody equals ............................................................71

Zastosowanie obiektów klasy StringBuffer jako kluczy kodowania mieszającego ...73Zagadnienie 15. Unikajmy konstruktorów w implementacji metody clone() .................74

Page 3: Java. Potrzaski

6 Java. Potrzaski

Zagadnienie 16. Rozdział metod a mechanizm refleksji, interfejsyi klasy anonimowe................................................................................................79

Zagadnienie 17. Obsługa wyjątków i błąd OutOfMemoryError ...................................88Składnia wyjątków............................................................................................89Hierarchia wyjątków .........................................................................................89Obsługa wyjątków ............................................................................................90Błąd braku pamięci ...........................................................................................90

Rozdział 3. Użyteczne klasy i kolekcje ............................................................... 93Zagadnienie 18. Uporządkowane klucze właściwości? ...............................................94Zagadnienie 19. Obsługa kolekcji o znacznych rozmiarachza pomocą mechanizmów buforowania i trwałości...................................................97

Zagadnienie 20. Plik właściwości czy zestaw zasobów?...........................................109Zagadnienie 21. Pułapki klasy Properties ................................................................112Zagadnienie 22. Klasa Vector i nowe kolekcje.........................................................117

Rozdział 4. Wejście i wyjście ........................................................................... 121Zagadnienie 23. Serializacja...................................................................................122

Jak działa serializacja?.....................................................................................123Interfejs Externalizable ....................................................................................124

Zagadnienie 24. Unicode, UTF i strumienie.............................................................125Unicode .........................................................................................................126UTF ..............................................................................................................126Strumienie......................................................................................................128Konfigurowanie kodowania .............................................................................131

Zagadnienie 25. Przesyłanie serializowanych obiektówza pomocą gniazd sieciowych..............................................................................131

Zagadnienie 26. Try, catch … finally? ....................................................................135Zagadnienie 27. Opróżnianie zasobów związanych z obrazami .................................138

Rozdział 5. Graficzny interfejs użytkownika — prezentacja................................ 143Zagadnienie 28. Informowanie o postępach.............................................................144

Kursor zajętości ..............................................................................................145Monitor 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...........................153Menedżery układu...........................................................................................154JLayeredPane.................................................................................................158

Zagadnienie 31. Zagadka metod validate(), revalidate() i invalidate().........................160Zagadnienie 32. Pionowy układ komponentów........................................................164Zagadnienie 33. Właściwe sposoby użycia menedżera GridBagLayout ......................172Zagadnienie 34. Zapobieganie migotaniu obrazu .....................................................179

Rysowanie w AWT.........................................................................................180Rysowanie i Swing..........................................................................................183

Zagadnienie 35. Komponenty z zagnieżdżonymi etykietami HTML..........................184

Rozdział 6. Graficzny interfejs użytkownika — sterowanie ................................ 189Zagadnienie 36. Kontrola danych wprowadzanych przez użytkownika ......................190

Komponenty tworzone na miarę .......................................................................191Filtrowanie .....................................................................................................191Konsumowanie zdarzeń...................................................................................192Kontrola po wprowadzeniu danych...................................................................194Problemy projektowania ..................................................................................194

Page 4: Java. Potrzaski

Spis treści 7

Asynchroniczna kontrola poprawności ..............................................................195Adapter kontroli danych ..................................................................................196Techniki kontroli poprawności danych..............................................................198Kontrola poprawności danych z wykorzystaniem wyjątków................................198Łańcuchy kontroli poprawności danych ............................................................200Uwagi końcowe..............................................................................................201

Zagadnienie 37. Uaktywnianie komponentów interfejsu użytkownikaw zależności od stanu aplikacji ............................................................................201Pierwsze rozwiązanie ......................................................................................202Rozwiązanie siłowe.........................................................................................202Rozwiązanie przez abstrakcję — klasa StateMonitor ..........................................203ListViewer .....................................................................................................205Adaptacyjna deaktywacja komponentów...........................................................208

Zagadnienie 38. Wielowątkowa obsługa zdarzeń .....................................................208Skuteczna implementacja obsługi przycisku Cancelz wykorzystaniem wątków.............................................................................210

Skuteczna implementacja obsługi przycisku Cancelwykorzystująca klasę SwingWorker ...............................................................212

Zagadnienie 39. Wzorzec „model widok kontroler” i komponent JTree .....................214Zagadnienie 40. Przekazywanie danych innych niż tekst ..........................................217

Pakiet java.awt.datatransfer .............................................................................218Trzy scenariusze przekazywania danych ...........................................................219Przykład przekazywania danych w obrębie jednej maszyny wirtualnej .................219Określanie sposobu przekazywania danych .......................................................223Przekazywanie danych poza maszynę wirtualną.................................................224

Zagadnienie 41. KeyListener, który nie słucha? .......................................................238Zagadnienie 42. Drukowanie tekstu, dokumentów HTML i obrazówza pomocą komponentu JEditorPane....................................................................241

Rozdział 7. Efektywność.................................................................................. 251Zagadnienie 43. Odroczone ładowanie sposobem na poprawę efektywności...............252Zagadnienie 44. Zastosowania puli obiektów...........................................................254

Odzyskiwanie obiektów...................................................................................255Porównanie puli obiektów i buforowania...........................................................255Implementacja ................................................................................................256Zalety ............................................................................................................257Wady.............................................................................................................258Kłopoty..........................................................................................................258

Zagadnienie 45. Efektywność tablic i klasy Vector...................................................260Dlaczego klasa Vector jest wolniejsza od zwykłych tablic? .................................262Kiedy używać klasy Vector? ............................................................................263Klasa ArrayList...............................................................................................264

Zagadnienie 46. Zagadnienie dynamicznego wzrostu tablic ......................................265Zagadnienie 47. Konkatenacja łańcuchów znakowych w pętli— porównanie klas String i StringBuffer ..............................................................270

Rozdział 8. Rozmaitości................................................................................... 273Zagadnienie 48. Czy istnieje lepszy sposób uruchamiania? .......................................273Zagadnienie 49. Hermetyzacja wywołań JNI za pomocą interfejsów .........................275

Koncepcja ......................................................................................................276Przykład interfejsu ..........................................................................................277Implementacja w języku Java...........................................................................279Implementacja w kodzie macierzystym .............................................................281Kod specyficzny dla platformy Windows ..........................................................285

Page 5: Java. Potrzaski

8 Java. Potrzaski

Zagadnienie 50. Asercje ........................................................................................289Asercje w języku Java .....................................................................................290Stosowanie asercji...........................................................................................290Jak nie należy stosować asercji.........................................................................290Przykładowa implementacja.............................................................................291

Skorowidz .......................................................................................... 295

Page 6: Java. Potrzaski

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łasnedoświadczenia — niektóre klasy pakietu ��������� ujęte w pięć następujących zagadnień:

Zagadnienie 18. Uporządkowane klucze właściwości? — opisuje sposób udoskona-lenia klasy �� �� � 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ązanierzeczywistego 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 informacjio 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 modyfikacjeklasy � ��� na skutek włączenia jej do szkieletu kolekcji udostępnionego w nowszychwersjach języka Java. Zagadnienie ma zachęcić Czytelnika do korzystania z nowegoszkieletu kolekcji.

Page 7: Java. Potrzaski

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ędziezarzą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 Bobi 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 obrazujemoment, gdy z Patty wsiadamy do samolotu”. Jednak po naciśnięciu klawisza, któreto wyświetli, pojawia się zdjęcie twoich przyjaciół, Drew i Suzy, w hotelu. Okazujesię, że zdjęcia zupełnie się pomieszały. Gdy wujek Bob zaczyna rzucać pomidoramiw ekran monitora, łatwo się domyśleć, że pokaz nie udał się. Jednak zostaje złożonepostanowienie 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 wielelepsze niż konieczność modyfikowania kodu źródłowego za każdym razem, gdy chcesię stworzyć nową prezentację. Ponieważ w pliku właściwości oprócz ścieżek dostępudo 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 tymcelu wszystkie właściwości zdjęć poprzedzimy przedrostkiem ���� �. Wydaje się todobrym 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:

����������������� �������������������������������������������������������� �������������������������������� !������������������ !�������������� ���"� �#$ !��������%���%��� !������������������$�&�� ����&���� !��

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 ���� ���� na podstawiewłaściwości zdjęć zapisanych w pliku:

Page 8: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 95

'(������%�����������)*��������� +,'-����.'/�����������������)*������ ������0'1���������2���$3� ��������"�2���$3� �+,0'4������������������������������������ ����������$+5���������5,0'6��������������������� ��������������� ����'7���������8����+&�$ �� 9���:������ +,,';���������.'<���������������������&�$��+������,&�$ ��=�:������+,0('������������������� ������������������((��������������.(-��������������������������������������������������������� !����������(/�������������������������������"����� ��� ���(1������������������!��##������(4��������������>(6���������>(7������������� �#����� �#�+,0(;������������+ �#��?�',(<���������.-'������������������� ����"���������) �#�*0-(���������������� ��2���$+����� ,0--���������>-/��������������������� 0-1����>

Metoda � ����� ��� zwraca tablicę obiektów ���� ����. Tablica ta jest wypełnianaw miarę przeglądania kluczy właściwości i sprawdzania, czy rozpoczynają się one odprzedrostka ���� � (wiersz 10.). Jeśli klucz zawiera taki przedrostek, to tworzony jestobiekt klasy ���� ���� i wstawiany do tablicy klasy ������� (wiersze 12. – 14.). Pozakończeniu analizy pliku właściwości tablica ������� jest konwertowana do zwykłejtablicy obiektów klasy ���� ���� i zwraca jako wynik wykonania metody.

Wydaje się więc, że kod programu jest napisany prawidłowo. Jednak skoro także plikwłaściwości jest prawidłowy, to program powinien wyświetlać zdjęcia w odpowiedniejkolejnoś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&�$�����@5�A�&�$�A�5@5,0

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ę:

&�$��@�����������@&�$��@������������ @&�$��@���������������@&�$��@������������@&�$��@������%���@

Widzimy więc, że kolejność uzyskiwania zdjęć różni się od kolejności ich występowa-nia w pliku. Czy to oznacza, że metoda � ���� klasy �� �� � posiada błędy? Od-powiedź na to pytanie jest krótka: nie. Źródłem problemu jest przyjęte założenie, żeklucze obiektu �� �� � są widziane w tej samej kolejności, w której występują w pli-ku. Założenie to nie jest prawdziwe. Ponieważ klasa �� �� � stanowi klasę pochodną

Page 9: Java. Potrzaski

96 Java. Potrzaski

klasy �������� , to klucze właściwości przechowywane są w tablicy mieszającej, a niena uporządkowanej liście. Klasa �������� przyznaje każdemu kluczowi indeks zależnyod 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. Natomiastmetoda � ���� 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, abyuzyskać 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 dozdjęć 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 �� �� � w kolejności, w której występują one w plikuwłaściwości, może okazać się przydatna w wielu innych zastosowaniach.

W jaki sposób zatem uzyskać uporządkowaną listę kluczy z obiektu �� �� �? Niejest to możliwe. Możemy jednak stworzyć własną klasę pochodną klasy �� �� �,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ądkowanejlisty, musimy także przesłonić metody ����� i ��� �� własną implementacją oraz do-dać metodę, za pomocą której będzie można uzyskać uporządkowaną listę kluczy.

Nową klasę nazwiemy ������ �� �� � (w zagadnieniu 21. przedstawiono szeregprzydatnych metod tej klasy). Definicja klasy ������ �� �� � może wyglądać na-stępująco:

'(������%����� �:��������������� ��=���� ���������� '-����.'/���������BB�&�� ���&���$'1�'4���������2���$3� ���������C�$ ����"�2���$3� �+,0'4�'6�����������%��� $������#����%!������+�%!���&�$���%!���D����,'7���������.';���������������%!����%!���� ���� ���+&�$��D����,0'<���������������������C�$ ���+&�$,0('����������������������%!��0((���������>(-�(/�����������%��� $������#����%!�������D��+�%!���&�$,(1���������.(4���������������%!����%!���� ���� ����D�+&�$,0(6���������������������C�$ ����D�+&�$,0(7����������������������%!��0(;���������>(<�-'�����������%��� $������#����������������������C�$ +,-(���������.--����������������������������C�$ ��������+,0-/���������>-1����>

Page 10: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 97

Zmienna instancji � ! �� w wierszu 5. jest kontenerem, w którym przechowuje sięuporządkowaną listę kluczy. Metoda �����, której definicja rozpoczyna się w wierszu 8.,wywołuje najpierw metodę ��� ������, która umieszcza klucz w tablicy mieszającejw sposób właściwy klasie �� �� �. Natomiast wywołanie � ! ���� �� ��w wierszu 9. wstawia ten klucz na uporządkowaną listę kluczy. Wywołanie metody �����spowoduje za każdym razem dodanie klucza do tablicy mieszającej �������� i wsta-wienie go do uporządkowanej listy kluczy. Metoda ��� ��, której definicja rozpoczy-na się w wierszu 13., działa w podobny sposób do metody �����. Za każdym razem,gdy wywołana jest metoda ��� ��, 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� �" ! ����, 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 � ����� ��� tworząca tablicę obiektów klasy ���� ���� na podstawie właści-wości, których klucz rozpoczyna się od przedrostka ���� �, musi zostać zmodyfikowanaw niewielkim stopniu. Wiersze 6. – 9. trzeba zatem zastąpić następującymi wierszami:

'6�����������������������C�$ ����������� ����������C�$ +,0'7�������8����+&�$ �� E�=�+,,';�������.'<��������������������&�$��+������,&�$ ��=�+,0

Jedyną zmianą, której będziemy musieli wykonać w pozostałej części programu, bę-dzie zastąpienie instancji klasy �� �� � tworzonej podczas wczytywania zawartościpliku właściwości za pomocą instancji nowej klasy ������ �� �� �. Po wykona-niu tych zmian i uruchomieniu programu uzyskamy następującą informację o dodawa-nych kluczach:

&�$��@���������������@&�$��@�����������@&�$��@������������ @&�$��@������%���@&�$��@������������@

Ścieżki dostępu do plików są teraz uporządkowane w odpowiedni sposób. Wiadomo już,że klasa �� �� � jest pochodną klasy �������� , a sposób przyznawania indeksówkluczom 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 kolekcjio 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.

Page 11: Java. Potrzaski

98 Java. Potrzaski

W tym jednym nie wyświetla żadnych efektów zapytania, sygnalizując jednocześniewystąpienie błędu "��"#$ ���. Wyniki zapytań są umieszczane w klasie ����������� ���, która stanowi efektywną i wygodną metodę krótkotrwałego przechowywaniadanych. 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 danychstanowiąca kombinację bufora LRU (Least Recently Used) z trwałym składem obiek-tów. Jego implementację stanowić będzie klasa ���� ��%��� � ���, którą omówi-my w tym zagadnieniu.

Rysunek 3.1 przedstawia strukturę klasy ���� ��%��� � ��� z zaznaczeniem, żeskł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 "�� ��&�� umożliwiającego serializację obiektów.

Rysunek 3.1.

Architektura klasyPersistentCacheVector

Architektura przedstawiona na rysunku 3.1 posiada następujące zalety:

� Prostota użycia podobna do klasy ����������� ���.

� Możliwość osiągania znacznych rozmiarów przez kolekcję (na przykład ponad50 000 elementów) bez obawy wystąpienia błędu "��"#$ �����.

� Dostępność najczęściej wykorzystywanych elementów kolekcji w pamięci.

� Szczegóły implementacji związane z obsługą kolekcji znacznych rozmiarównie są widoczne dla użytkownika klasy.

Page 12: Java. Potrzaski

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. Zanimprzejdziemy do analizy kodu, przyjrzyjmy się zaproponowanemu interfejsowi klasy ���� ��%��� � ���. Posiada on następujące metody o dostępie publicznym:

��%������ � ����F��������+�����F�����#�,0��%���������D�������+�������#�%����,�����" ���:=������0��%����������%!������+������=,�����" �����=�����G���� :=�������������������������������������������������:=������0��%����������%!�������D�+��������=,�����" �����=�����G���� :=������������������������������������������������������:=������0��%���������D������$��+�%!����2���$�)*,�����" ���:=������0��%���������D������ �+,0��%���������D����������#�+,0��%������������� �#�+,0

Pomiędzy interfejsem klasy ���� ��%��� � ��� i metodami klasy � ��� wystę-pują cztery istotne różnice:

Konstruktor klasy ���������������� � wymaga określenia maksymalnego

rozmiaru bufora. Inaczej niż w przypadku klasy � ���, konstruktorowiktórej przekazujemy początkowy rozmiar wektora, dla klasy ���� ��%��� � ��� parametr konstruktora oznacza maksymalną liczbę obiektów, któremogą być przechowywane w pamięci. Obiekty nadmiarowe będą przechowanena dysku.

Niektóre z metod wyrzucają wyjątek �������� � ze względu

na przechowywanie obiektów w plikach. Z punktu widzenia zgodnościz klasą � ��� najlepiej obsługiwać ten wyjątek wewnątrz metod, zamiastprzekazywać go do kodu wywołującego metody. Jednak wystąpienie błędudysku spowodowałoby wtedy nieprzewidziane zachowanie klasy � ���. Drugamożliwość polega na przechwyceniu wyjątku �"�'� ����� i wyrzuceniu wyjątku(����� �'� �����, który nie musi być obsługiwany. W ten sposób równieżuzyskalibyśmy przezroczystość fasady klasy � ���, gdyż kod wywołującymetody nie musiałby obsługiwać żadnych wyjątków.

Pominięte zostały niektóre metody dostępne w klasie ��� �. Ich implementacjępozostawiono Czytelnikowi jako ćwiczenie do wykonania. Inna możliwośćudawania klasy � ��� polega na utworzeniu jej klasy pochodnej i przesłonięciuwszystkich metod klasy bazowej. Dzięki temu będziemy mogli używać obiektówklasy ���� ��%��� � ��� zamiast obiektów klasy � ���, jednak w istotnysposób zwiększy to rozmiary implementacji klasy ���� ��%��� � ���.

Parametrem metody ���� mogą być tylko obiekty implementujące

interfejs ����������. Ograniczenie to wynika z konieczności zapewnieniatrwałości buforowanych obiektów i oczywiście nie występuje ono w klasie� ���. Dla zapewnienia zgodności z klasą � ��� metoda � �� mogłabyprzyjmować 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ą � ���.

Page 13: Java. Potrzaski

100 Java. Potrzaski

Implementacja interfejsu klasy ���� ��%��� � ��� wymaga zarządzania struktura-mi przedstawionymi na rysunku 3.1: wektorem proxy zawierającym obiekty namiastek)�������, tablicą mieszającą obiektów %��� ����, listą LRU i obiektem "�� ��&�� .Zagadnienia te omówimy szczegółowo.

Klasa wewnętrzna )������� stwarza iluzję korzystania z obiektów klasy � ���. Użyt-kownik spodziewa się zwykłego obiektu klasy � ���, w którym będzie umieszczać swojeobiekty. Jednak w rzeczywistości będą umieszczane tam instancje klasy )������� 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 "�� ��&�� ). Klasa )������� posiada tylkodwie 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:

1'������� ����%:���$1(�����.1-��������BHH�I��#��&��������!J$�#$���������#��!��!�� �K�"�%����#��#$�����$ &� HB1/��������%���������F���011��������BHH�8 &�L��&���#$!�����&�����$���������#��!��!�� �K�����$ &� �HB14��������������������������M(016�����>

Klasa wewnętrzna %��� ���� 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żdyobiekt klasy %��� ���� jest umieszczany w tablicy mieszającej �������� przy zastoso-waniu klucza, który przechowywany jest także wewnątrz danego obiektu klasy %��� *����. 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)������� 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 ��� � w obiek-tach klasy )�������. W ten sposób zostałaby ograniczona liczba generowanych kluczy.Umieszczenie w obiektach klasy %��� ���� 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.

4(������� �F���:���$4-�����.4/��������BHH�C��#����������%����� ���� �!��$��%��&���������41����������������"����!J$�����& �"�����������"�&���� �HB44����������������&�$046��������BHH��%��&����#���"$"��$�"�%����#� �HB47���������%!����04;��������BHH��������!������#������������ �K����������������� �$ �HB4<��������F���:���$����D����=�06'�����>

Dostęp do dwukierunkowej listy LRU jest możliwy dzięki referencjom znajdującymsię w klasie ���� ��%��� � ���. Jedna z nich wskazuje początek listy (#���%��� *����), a druga jej koniec (����%��� ����). 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

Page 14: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 101

ostatni element listy reprezentuje najrzadziej używany element. Większość kodu klasy ���� ��%��� � ��� właśnie zarządza listą dwukierunkową. Poniżej zaprezentowanofragment umieszczający instancję klasy %��� ���� (o nazwie � ) na liście LRU. Działaon 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 � umieszcza w obiekcie, którydotychczas stanowił czoło listy jako referencję poprzedniego elementu listy. Na koniecnadaje 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.

(';�����������BB�" ��"���������������� �$('<��������������+�� �F���:���$�N�����,(('�����������.(((��������������BB����� ##����������#J�&���� �$((-��������������� ��=������ �F���:���$0((/����������������� �F���:���$ ���D���0((1����������������� �F���:���$���0((4�����������>((6������������� �((7�����������.((;��������������BB��� ���!� ���� ��((<����������������� �F���:���$���� �F���:���$���0(-'�����������>

Klasa "�� ��&�� przechowuje serializowane obiekty w pliku o dostępie swobodnym,reprezentowanym przez klasę (�� ����� ��&�� . Serializowany obiekt jest przechowy-wany w postaci tablicy bajtów. Aby zapisać tablicę bajtów za pomocą obiektu klasy(�� ����� ��&�� 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ówtablicy. Klasa "�� ��&�� zawiera instancję klasy (�� ����� ��&�� i implementujemetody zapisu i odczytu obiektów w omówionej postaci.

'7����%����� ��%!��O���';��.'<�����������2� O��������O���0('������������ O���E���0((�(-�������%����%!��O���+������� E���,�����" ���:=������(/�����.(1�������� O���E����� E���0(4������������O�������"�������2� O���+ E�����5�"5,0(6�����>

Dla potrzeb naszego przykładu klasa ���� ��%��� ��� posiada dodatkowo metodę������ umożliwiającą jej przetestowanie. Poniżej przedstawiamy efekt wykonania te-stów umieszczonych w tej metodzie:

�������/''��%!�� ��#���/''�� �������� '�(�-�/�1�4�E�"��������������������=�4�� ���6

Page 15: Java. Potrzaski

102 Java. Potrzaski

��#��� ��-<<-<6�-<7�-<;�-<<�(�-�/�1�4��� ���������D� ��#���-<<����D����('��#���-;<O�� ��(' -�1�6�;�('�(-�(1�(6�(;�-'�

Oto pełny kod źródłowy klasy ���� ��%��� � ���:

''(��BH���� � ����F�������� !�D��HB''-����&����!"���$ ������D�0''/�''1���������!�D� �� H0''4���������!�D� ���� H0''6�''7��BHH'';���H������"�����&�&�� $��������P$"�!J$�%������3�Q������� ##�!J$''<���H������$ &����������"���%��&�$ '('���HB'((����%����� ���� � ����F������������������ �F�����%�����������#�%��'(-��.'(/�����BHH�3�#��&���"��#��$���%��&�R" �HB'(1����� �����������F����0'(4�����BHH�9�& $����$���#�����%����� �HB'(6����������9�=F�����#�0'(7�����BHH�G��PJ$���#�����%����� �HB'(;����������F�����#�0'(<�����BHH�G���� �HB'-'�����S� ���%����������"�S� ���%��+,0'-(�����BHH���%����&�� $������ ���#���"�!��!��$���'--����������%��&��&�� $������:���$�����&�P�����" ��"��������%��&�� �HB'-/�������������" ����"������+,0'-1�����BHH��%!��O������#���"�!���%��&�$�����$ &� '-4���������T ����%!��O���'-6�����HB'-7������%!��O������0'-;�����BHH�E�#"�����&���"�&�R�$����#���"$"���� J��%��&�$ �HB'-<������������ ���E���0'/'�����BHH���#J��&��� �$�3�Q ������" #$��������������#����!�'/(��������!#KU��!�+� ������,��P$"��$���������%����� �HB'/-�����F���:���$���� �F���:���$0'//�����BHH�C������� �$�3�Q ��� �������������������#����!� '/1��������!�#��#��!�+� ������,��P$"��$���������%����� �HB'/4�����F���:���$��� �F���:���$0'/6�'/7�����BHH'/;������H�C�� ��"�"�K��#�������� �&� '/<������HB'1'������� ����%:���$'1(�����.'1-��������BHH�I��#��&��������!J$��#$���������#��!��!�� �K�"�%����#��#$����$ &� �HB'1/��������%���������F���0'11��������BHH�8 &�L��&���#$!�����&�����$���������#��!��!�� �K�����$ &� �HB

Page 16: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 103

'14��������������������������M(0'16�����>'17�'1;�����BHH'1<������H�C�� ��"�"�K��#��������#����!J����������%����� '4'������HB'4(������� �F���:���$'4-�����.'4/��������BHH�C��#����������%����� ���� �!��$��%��&���������'41����������������"����!J$�����& �"�����������"�&���� �HB'44����������������&�$0'46��������BHH��%��&����#���"$"��$�"�%����#� �HB'47���������%!����0'4;��������BHH��������!������#������������ �K����������������� �$ �HB'4<��������F���:���$����D����=�0'6'�����>'6(�'6-�����BHH'6/������H�C�� ���&�����&��U��!J$���#�����%����� ����&�����!� ����"�����$�'61������H����R&������#� ��������#�&��#��$���#�����%����� '64������H�T�������F�����#��9�& $����$���#�����%����� '66������HB'67�������%������ � ����F��������+�����F�����#�,'6;�����.'6<����������� �9�=F�����#����F�����#�0'7'�����>'7(�'7-��������D����������D������������O���+,�����" ���:=������'7/�����.'71��������%�������%�������������0'74�'76��������"�����+%�������,'77��������.'7;����������� ���E�����5���5�A�+�$ ��� ����������9���� +,,'7<����������������������������A�+AA�F����,�A�5 �%�50';'�����������O���������"�O���+ ���E���,0';(��������������+N� �=� � +,,';-��������������%������������ �0';/��������>';1�';4��������������"��%!��O���+ ���E���,0';6�����>';7�';;�����BHH';<������H�9������" ��"������������������"�&���� �:�������#� ��!�'<'������H����� ##��$�"�%����#����%�����$ &� '<(������H�T���������%��&������"��$����"�&���� '<-������HB'</�������%���������D�������+�������#�%����,�����" ���:=������'<1�����.'<4�����������%:���$������"����%:���$+,0'<6�'<7����������" ���+�,0'<;�'<<�����������+�F�����#��V��9�=F�����#�,(''��������.('(������������ ��F���������0

Page 17: Java. Potrzaski

104 Java. Potrzaski

('-�����������F���:���$������"�F���:���$+,0('/������������ ����0('1������������ &�$����"��������+��" �#�+,�M�(,0('4�������������� ���+� &�$���,0('6������������F�����#�AA0('7�(';�����������BB�" ��"���������������� �$('<��������������+�� �F���:���$�N�����,(('�����������.(((��������������BB����� ##����������#J�&���� �$((-��������������� ��=������ �F���:���$0((/����������������� �F���:���$ ���D���0((1����������������� �F���:���$���0((4�����������>((6������������� �((7�����������.((;��������������BB��� ���!� ���� ��((<����������������� �F���:���$���� �F���:���$���0(-'�����������>(-(��������>(--���������� �(-/��������.(-1�������������+��������,(-4����������������������O���+,0(-6�(-7����������� ��������������� "�����%!��+�,0(-;��������>(-<�����>(/'�(/(�����BHH(/-������H�9�������� �K���������������"�&������������$������& �� (//������H��%��&����%�����$�!� ��#�%��������%����&� (/1������H�T��������=�����& ���%����������������� (/4������H�T������ ��%��&������ ##��$�"�"�&���#� (/6������HB(/7�������%����������%!������+������=,�����" �����=�����G���� :=�������(/;�����������������������������������������������:=������(/<�����.(1'�����������+��=�V�'�WW���=�?���" �#�+,,(1(���������������"���"�����=�����G���� :=������+5����=��5�A���=(1-�������������������������������������������A�5��������%���� 5,0(1/�(11�����������%:���$����+���%:���$,���" ���+��=,0(14�(16���������%!��������0(17�(1;�����������+� ��F���,(1<��������.(4'�����������BB���%������������(4(�����������F���:���$��������0(4-��������������+F���:���$,���� ���+��"��������+��=,,0(4/�(41��������������+�������,(44������������������"���"���:=������+5:������������=�5�A���=�A�5�� �EQ33N5,0(46�(47��������������++��N������XX�� �������,,

Page 18: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 105

(4;������������������"���"���:=������+5F����:������@ ��%!��������=�5(4<������������������������������������A���=�A�5�E���������N5,0(6'�(6(��������������� �0(6-�(6/��������������+��N���� �F���:���$,(61�����������.(64��������������BB�� �"�����#��� �$(66�����������������+� ��=��N�����,(67������������������ ��=� ���D��� ���D0(6;���������������� ��BB�� ���������������� �$(6<�������������������� �F���:���$��� ���D0(7'�(7(��������������� ���D ��=���� ��=�0(7-�(7/��������������BB���" ��"��������#J��&��� �$(71��������������� ��=������ �F���:���$0(74��������������� ���D������0(76����������������� �F���:���$ ���D���0(77����������������� �F���:���$���0(7;�����������>(7<��������>(;'���������� �(;(��������.(;-�����������BB��%��&��"�%����#�(;/������������ ��F���������0(;1�(;4�����������BB���%����������" ��"���������%�����(;6�������������$(;7�����������.(;;������������������� �����%!��+� �����������,0(;<�����������>�����+F�� E��O����:=����������,(<'�������������.�����"���"���:=������+��� ���9� ���+,,0�>(<(�(<-�����������BBHHH�����"�#���#$�%���������!� ����Y�$N(</��������������+�F�����#����9�=F�����#�,(<1�����������.(<4��������������BB�� �"����������#��!��!J$� �K����&�Z���� �$ (<6��������������F���:���$���� �Q ������ �F���:���$0(<7�����������������+��� �Q �� ���D�N�����,(<;��������������.(<<�������������������� �Q �� ���D ��=�������0-''������������������� �F���:���$����� �Q �� ���D0-'(������������������� �F���:���$ ��=�������0-'-��������������>-'/���������������� �-'1��������������.-'4�����������������BB�� �"��!��$�$����������� �$-'6�������������������� �F���:���$���� �F���:���$������0-'7��������������>-';�-'<��������������BB�" ��"�����%���$������������%�����-('��������������F���:���$������"�F���:���$+,0-((��������������� ����0-(-��������������� &�$����"��������+��=,0-(/����������������� ���+� &�$���,0-(1�

Page 19: Java. Potrzaski

106 Java. Potrzaski

-(4��������������BB����� ##����������U���3�Q-(6�����������������+�� �F���:���$�N�����,-(7��������������.-(;�����������������BB�" ��"��������#J��&��� �$-(<������������������ ��=������ �F���:���$0--'�������������������� �F���:���$ ���D���0--(�������������������� �F���:���$���0---��������������>--/���������������� �--1��������������.--4�����������������BB��� ���!� ���� ��--6�������������������� �F���:���$���� �F���:���$���0--7��������������>--;�--<��������������BB���%��������%:���$�� �"�������%��&��-/'�����������������%:���$�������%:���$��+���%:���$,-/(��������������������" ���+��� �Q �� &�$ ��������+,,0-/-�-//��������������BB�� �"���%��&��#�%�����-/1��������������F���:���$����F���:���$��+F���:���$,-/4��������������������� ����D�+��� �Q �� &�$,0-/6�����������������+���F���:���$������,-/7���������������������"���"��������:=������+5F����:���$����5-/;��������������������������������A���� �Q �� &�$�A�5�� �E���N5,0-/<�-1'�����������������+���F���:���$�N������XX����F���:���$ �������,-1(���������������������"���"��������:=������+5F�����%!������5-1-���������������������������������A���� �Q �� &�$�A�5�� �E���N5,0-1/�-11���������������%!�������%!�������F���:���$ �0-14�-16��������������������%:���$ ��F�������� �0-17�-1;�����������������+������%:���$ �������������M(,-1<��������������.-4'�����������������BB����� ##��$�"�%����#�-4(��������������������������%:���$ ������������-4-������������������������������� "�����%!��++�������#�%��,����%!��,0-4/��������������>-41���������������� �-44��������������.-46�����������������BB�#��!��!��!�P� �K�"����&��[�#��������#�����\-47�����������������������F��������#��-4;���������������������� ����%!��3�����+������%:���$ �����������,0-4<�-6'������������������G$��2���$�������������%�� ����"�G$��2���$������������+,0-6(�������������������%!����������������� ����"��%!��������������+%�� ,0-6-�������������������� "�����%!��++�������#�%��,�����%!��,0-6/�������������������� ��� �+,0-61�������������������������������%�� �#�+,0-64�-66���������������������+��������V��F��������#�,-67������������������������ ��"�����%!��+������%:���$ ������������-6;���������������������������������������%�� ��G$��2���$+,,0-6<�������������������� �-7'����������������������������%:���$ ������������

Page 20: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 107

-7(������������������������������������ "�����%!��++�������#�%��,����%!��,0-7-�-7/������������������%�� ������0-71�������������������� ������0-74����������������������%!��������0-76��������������>-77�����������>-7;������������� �-7<�����������.-;'��������������F���:���$������"�F���:���$+,0-;(��������������� ����0-;-��������������� &�$����"��������+��=,0-;/����������������� ���+� &�$���,0-;1���������������F�����#�AA0-;4�-;6��������������BB�" ��"�������� �K�3�Q-;7�����������������+�� �F���:���$�N�����,-;;��������������.-;<�����������������BB������#J��&��� �$-<'������������������ ��=������ �F���:���$0-<(�������������������� �F���:���$ ���D���0-<-�������������������� �F���:���$���0-</��������������>-<1���������������� �-<4��������������.-<6�����������������BB��� ���!� ���� ��-<7�������������������� �F���:���$���� �F���:���$���0-<;��������������>-<<�����������>/''�/'(��������>/'-�/'/����������������0/'1�����>/'4�����BB�HHH�9����$�������K���#��"#��K������%��&����! �/'6��>

Poniżej przedstawiamy kod źródłowy klasy "�� ��&�� :

'(��BH��%!��O��� !�D��HB'-����&����!"���$ ������D�0'/�'1���������!�D� �� H0'4���������!�D� ���� H0'6�'7����%����� ��%!��O���';��.'<�����������2� O��������O���0('������������ O���E���0((�(-�������%����%!��O���+������� E���,�����" ���:=������(/�����.(1�������� O���E����� E���0(4������������O�������"�������2� O���+ E�����5�"5,0(6�����>(7�(;�����BB�#"������#$!K����&������&�R��!�#��� �����%��&�

Page 21: Java. Potrzaski

108 Java. Potrzaski

(<�������%��� $������#��������"�����%!��+�������#�%����%!,�����" ���:=������-'�����.-(��������G$��2���$�������������%�� ����"�G$��2���$������������+,0--���������%!����������������� ����"��%!��������������+%�� ,0-/���������� "�����%!��+�%!,0-1���������� ��� �+,0-4�-6���������������������%�� �#�+,0-7�-;��������BB���YJ#����&���-<��������������� ������O��� ������+,0/'������������O��� ��&+�� ,0/(�/-��������BB�#��� �!����#��������$�//������������O��� "�������+�������,0/1������������O��� "����+%�� ��G$��2���$+,,0/4�/6��������%�� ������0��� ������0/7�/;����������������� 0/<�����>1'�1(�1-�����BB���%�����%��PJ$���#������%��&��1/�������%��� $������#�����������%!��3�����+�������� ,�����" ���:=������11�����.14������������O��� ��&+��� ,016�������������������O��� �������+,017�����>1;�1<�������%��� $������#����%!��������%!��+�������� ,4'����������������������" ���:=�������F�� E��O����:=������4(�����.4-������������O��� ��&+��� ,04/�������������������������O��� �������+,041�����������+��������?�����O��� ������+,,44���������������"���"���:=������+5]���������� ��������� ����������546����������������������������������A��������,047��������%$���)*���������"�%$��)�������*04;������������O��� ����O���$+����,04<�6'��������G$��2���$������������%�� ����"�G$��2���$�����������+����,06(���������%!���������������� ����"��%!�������������+%�� ,06-���������%!�������� �����%!��+,06/�61��������%�� ������0���������-'64���������� ������066������������������067�6;����������������06<�����>7'�7(�������%��������������+,�����" ���:=������7-�����.7/�������������������O��� ������+,071�����>74�76�������%���D������ �+,�����" ���:=������

Page 22: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 109

77�����.7;������������O��� �� �+,07<�����>;'�����BB�9����$�������K���#��"#��K������%��&����! �;(��>�BB�&�����&�� $��%!��O���

W zagadnieniu tym przedstawiono połączenie bufora �(+ i klasy umożliwiającej trwałeprzechowywanie obiektów ("�� ��&�� ), 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 niewieledanych oraz charakteryzuje się niezawodnością w momencie pojawienia się wyjątkowodużej ilości danych. Tworzenie takich niezawodnych, choć nie zawsze efektownych roz-wiązań cechuje najlepszych programistów.

Zagadnienie 20. Plik właściwościczy zestaw zasobów?

Proszę sobie wyobrazić, że ktoś rozpoczął właśnie pracę dla nowo powstałej firmyLOA, 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 napisanegow 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 czasdo 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, żejeden i ten sam moduł kodu powinien obsługiwać wszystkie języki. Dlatego kolejnympomysłem jest wczytywanie właściwości systemu zawierających informacje o wybranymję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ę zeswojego 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. Polecawięc zapoznanie się z klasą ( ���� ,�� � .

Klasa ( ���� ,�� � różni się od klasy �� �� � w wielu aspektach. Klasa ( ���� *,�� � i jej klasy pochodne ����( ���� ,�� � i �� ��( ���� ,�� � zaprojek-towano tak, by wykorzystywały klasę ����� do obsługi danych zależnych od kraju,w którym mieszka użytkownik programu. Natomiast klasa �� �� � nie używa klasy����� , ponieważ jej zadaniem jest jedynie przechowywanie par obiektów klasy )����reprezentujących klucz i odpowiadającą mu wartość. Dlatego też klasę �� �� �,w przeciwieństwie do klasy ( ���� ,�� � , stosujemy do przechowywania łańcuchów

Page 23: Java. Potrzaski

110 Java. Potrzaski

znaków )����, 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ęzykaaplikacji. Kolejna różnica pomiędzy klasami ( ���� ,�� � i klasą �� �� � polegana tym, że klasa ����( ���� ,�� � umożliwia przechowywanie klucza klasy )����i wartości klasy "�� ��. W praktyce oznacza to, że można przechowywać w niej war-tość będącą obiektem dowolnej klasy. Natomiast klasa �� �� � umożliwia przecho-wywanie jedynie łańcuchów znakowych klasy )����.

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 danychmoże to dotyczyć, przyjrzyjmy się bliżej klasie ����� . Klasa ta musi uwzględniać nietylko język, którym posługuje się użytkownik programu, ale także kraj, w którym onmieszka. W wielu krajach używa się bowiem tego samego języka, ale zapisuje liczbyi daty w różnych formatach. Trzecim parametrem klasy ����� jest wariant. Umożliwiaon programiście wyspecjalizowanie dodatkowych różnic w stosunku do podstawowychformató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( ���� ,�� � zawierający pliki właściwości. Przez zestaw zasobów rozumiemy w tymprzypadku grupę plików zawierających te same dane poddane procesowi lokalizacjidla różnych krajów i języków. Takich zestawów zasobów możemy opracować dowolniewiele. 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 klasyjęzyka Java). Zaletą takiego rozwiązania jest to, że, oddzielając w ten sposób kod oddanych, możemy przekazać tłumaczom tylko same pliki właściwości.

Zestaw zasobów uzyskujemy, wywołując metodę ( ���� ,�� � �� �,�� � ��. Prze-kazuje się jej jako parametr obiekt klasy ����� lub pozwala skorzystać z domyślnegoobiektu ����� . Aby klasa ( ���� ,�� � 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( ���� ,�� � , aby odnaleźć odpowiedni zasób:

%� ��� �A�5�5�A���������(�A�5�5�A������$(�A�5�5�A�D������(%� ��� �A�5�5�A���������(�A�5�5�A������$(�A�5�5�A�D������(�A�5 ��������� 5%� ��� �A�5�5�A���������(�A�5�5�A������$(%� ��� �A�5�5�A���������(�A�5�5�A������$(�A�5 ��������� 5%� ��� �A�5�5�A���������(%� ��� �A�5�5�A���������(�A�5 ��������� 5%� ��� �A�5�5�A���������-�A�5�5�A������$-�A�5�5�A�D������-%� ��� �A�5�5�A���������-�A�5�5�A������$-�A�5�5�A�D������-�A�5 ��������� 5%� ��� �A�5�5�A���������-�A�5�5�A������$-%� ��� �A�5�5�A���������-�A�5�5�A������$-�A�5 ��������� 5%� ��� �A�5�5�A���������-%� ��� �A�5�5�A���������-�A�5 ��������� 5%� ��� %� ��� �A�5 ��������� 5

Page 24: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 111

Załóżmy na przykład, że metodzie � �,�� � �� przekazaliśmy obiekt klasy ����� za-wierający kod języka niemieckiego ( ) i kod Szwajcarii (%�). Domyślny obiekt klasy����� zawiera natomiast kod języka angielskiego ( �) i Stanów Zjednoczonych (+)).Przypuśćmy, że klasę bazową tekstu powitania nazwaliśmy )�����$ ���� . Aby ustalić,jakich nazw zasobów będzie poszukiwać klasa ( ���� ,�� � , musimy zastąpić w po-wyższym schemacie parametr ��� ����� nazwą -)�����$ ���� -, parametr ������� .— łańcuchem - -, parametr ������. — łańcuchem -%�-, parametr ������� / — łań-cuchem - �- i parametr ������/ — łańcuchem -+)-. Ustalimy w ten sposób, że programbędzie próbować znaleźć kolejno następujące zasoby: )�����$ ���� � �%�, )�����*$ ���� � �%����� �� �, )�����$ ���� � , )�����$ ���� � ���� �� �,)�����$ ���� � ��+), )�����$ ���� � ��+)���� �� �, )�����$ ���� � �,)�����$ ���� � ����� �� �, )�����$ ���� , )�����$ ���� ���� �� �.

Tworzenie zestawu zasobów najlepiej rozpoczynać zawsze od podstawowego. Dziękitemu 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����� . Najpierw utworzymy więc podstawowy plik właściwości. Będzie on posiadaćnazwę )�����$ ���� i następującą zawartość:

������������ �� �����8���������3�2������ ����� ��C������ ��������� ���"��� �����"� ������ �F2EF:3�����=��

Następnie utworzymy plik właściwości dla domyślnego obiektu klasy ����� o nazwie)�����$ ���� � ��+)���� �� �. Zawiera on takie same informacje jak podstawowyplik właściwości. Skoro jednak informacja w obu plikach jest identyczna, to po co two-rzyć plik podstawowy. Załóżmy, że obiekt klasy ����� przekazany metodzie � �,�� � ��dotyczy Chin, a obiekt domyślny Japonii. Ponieważ zestaw zasobów nie zawiera plikówwł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ówczasw opisanym przypadku zostanie wyrzucony wyjątek $������( ���� �'� �����.

Następnie utworzymy domyślny zasób opisujący teksty przycisków. Nazwiemy go)�����,��������� �� �. Zawiera on następujące informacje:

�������G����� �&�C�������G����� ����F2EF:3

Ponownie utworzymy też zasób dla domyślnego obiektu klasy ������ o takiej samej za-wartości. Nazwiemy go )�����,������ ��+)���� �� �.

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 )�����$ ���� dla domyślnego obiektu kla-sy ����� :

'(���� ����G������ ������9� ���G�����0'-�� ������9� ���G��������� ����G����� ���G�����+5�������9� ���5,0'/����������� ����� ������9� ���G����� ���������+5������������ �� ���5,0

Podobnie poniższy fragment kodu wczyta zasób )�����,����� dla domyślnego obiektuklasy ����� :

Page 25: Java. Potrzaski

112 Java. Potrzaski

'(���� ����G������ ������G�����G�����0'-�� ������G�����G��������� ����G����� ���G�����+5�������G�����5,0'/����������&G������� ������G�����G����� ���������+5�������G����� �&5,0

Jeśli domyślny obiekt klasy ����� odpowiada językowi angielskiemu ( �) i USA (+)),to zostaną załadowane pliki )�����$ ���� � ��+)���� �� � oraz )�����,������ ��+)���� �� �. Zaletą przedstawionego rozwiązania jest to, że kod programu niemusi 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 jedeni 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 �� �� � i ( ���� ,�� � i przedstawieniu podstawowych sposobów posługiwania się klasą ( ���� ,�� � . Moż-na więc potraktować go jedynie jako wprowadzenie do tematu. Język Java dysponujejeszcze innymi klasami wspierającymi programistę podczas internacjonalizacji pro-gramów, na przykład 0�� &����, 1��� &���� i $ ���� &����.

Zagadnienie 21.Pułapki klasy Properties

Jeśli Czytelnik programuje długo w języku Java, to z pewnością używał już obiektówklasy �� �� �. Mógł nawet przyjąć, że klasa ta stanowi cudowny środek, który razna zawsze uwalnia programistę od konieczności kodowania wartości bezpośrednio w ko-dzie programu. Jeśli natomiast nie korzystał jeszcze z klasy �� �� � w swoich progra-mach, to może się dowiedzieć, że pozwala ona pobierać klucze i ich wartości zapisanew plikach właściwości. Pliki właściwości są plikami tekstowymi zawierającymi wierszepostaci ����234���56. Ich zadaniem jest umożliwienie modyfikacji wartości zmien-nych klasy )���� bez konieczności wprowadzania zmian w kodzie programu. Klasa�� �� � udostępnia programiście podstawowe narzędzia odczytujące zawartości pli-ku właściwości oraz pobierające lub nadające dane wartości. Pliki właściwości stanowiąwygodny sposób przechowywania informacji o konfiguracji aplikacji lub preferencjachużytkownika. Pliki właściwości wraz z klasą �� �� � stanowią próbę separacji in-formacji tekstowej i kodu programu. Takie rozwiązanie nie jest jednak pozbawione wła-snych problemów.

Załóżmy na przykład, że w pliku właściwości będziemy przechowywać dane o systemiebazy danych, z którym łączy się nasza aplikacja. Dzięki takiemu rozwiązaniu uzyskamymożliwość zmiany systemu bazy danych, z którym pracuje nasza aplikacja bez koniecz-ności wprowadzania zmian w kodzie aplikacji. Zawartość takiego pliku właściwości mo-że wyglądać następująco:

]������ ]%E����� ���� ]������ ���BB������ ��41/-B% ]������ Q ��E����� ���� ]������ �� "����� ����

Page 26: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 113

Jeśli plik ten umieścimy w katalogu c:\myApp\properties i nazwiemy System.properties,to jego zawartość można odczytać za pomocą przedstawionego niżej fragmentu kodu:

'(������$'-����.'/�������O����������������� ����"�O��������������+5����$2������������� ������������������������������������������������$ ��� ��������� 5,0'1���������������� ����� ����"���������� +,0'4����������� ����+�� ,0'6���������������%E��������� ����������$+5]������ ]%E���5,0'7����>';�������+O���E��O����:=�����������,.>�BB�% Y����"$!J�&�'<�������+��:=����������,�.>�BB��% Y����"$!J�&�

Powyższy kod tworzy obiekt klasy �� �� � zawierający pary kluczy i odpowiadają-cych im wartości zapisane w pliku System.properties. Zmieniając jego zawartość, może-my połączyć naszą aplikację z innym systemem bazy danych, nie zmieniając ani jednegowiersza jej kodu. Doskonałe rozwiązanie, ale gdzie jest problem? Zaletą tego rozwiąza-nia jest oddzielenie informacji o systemie bazie danych i kodu aplikacji. Jednak kod apli-kacji zawiera ścieżkę dostępu do pliku. Przypuśćmy, że użytkownik zainstalował nasząaplikację na dysku D zamiast C. Konstruktor &�� �����)� ���� wywołany w 3. wier-szu wyrzuci wtedy wyjątek &�� 1��&��� �'� �����, ponieważ plik System.propertiesnie zostanie znaleziony w katalogu c:\myApp\properties. W jaki zatem sposób możemyuniknąć kodowania w programie ścieżki dostępu do pliku właściwości?

Alternatywne rozwiązanie będzie wykorzystywać metodę � �( ���� ��)� ���� klasy%����. Metoda ta, poszukując zasobu, wykorzystuje ścieżki dostępu do klas. Dziękitemu możemy umieścić plik właściwości w dowolnym katalogu pod warunkiem, że ka-talog ten dodamy do ścieżki dostępu do klas. Domyślnie metoda � �( ���� ��)� ���)����7 ���� � przeszukuje ścieżki dostępu na dwa sposoby. Jeśli przekazany jejjako parametr łańcuch znaków opisujący zasób rozpoczyna się od znaku 8, to łańcuchten nie jest modyfikowany. W przeciwnym razie łańcuch jest dołączany na końcu na-zwy pakietu, w nazwie którego wszystkie znaki � zastępowane są znakiem 8. Przypu-śćmy, że klasa )���� �� � należy do pakietu �������������������. Klasa )���*� �� � może wtedy ładować obiekt klasy �� �� � w następujący sposób:

'(�����$'-���.'/���������������������� ���$ ��������� �� ����� ����2 ������'1���������+5B�$ ��� ��������� 5,0'4������������������ ���������"���������� +,0'6������������+� �N�����,'7���������.';������������������� ����+� ,0'<�����������������������%E��������� ����������$+5]������ ]%E���5,0('���������>((���>(-����������+��:=����������,�.>�BB��% Y����"$!J�&�

W tym przypadku metoda � �( ���� ��)� ����, poszukując pliku System.propertiessprawdza katalogi umieszczone w ścieżce dostępu do klas. Gdybyśmy jednak zmieniliw wierszu 4. parametr wywołania metody z -8)��� ����� �� �- na -)��� ����*� �� �-, to, sprawdzając katalogi umieszczone w ścieżce dostępu do klas, metoda

Page 27: Java. Potrzaski

114 Java. Potrzaski

� �( ���� ��)� ���� poszukiwałaby pliku com/mycompany/myapp/System.properties.Obie możliwości są równie dobre. Jeśli chcemy przechowywać razem wszystkie plikiwłaściwości, to wybierzemy pierwszą z nich. Jeśli natomiast preferujemy umieszcza-nie plików właściwości w tym samym katalogu, w którym korzystające z nich klasy,właściwe będzie drugie rozwiązanie. Najważniejsze jednak jest to, że w obu przypad-kach użytkownik nie musi już umieszczać pliku właściwości System.properties w ka-talogu c:\myApp\properties. Możemy także utworzyć plik typu jar, który będzie za-wierać klasy i pliki właściwości.

Spróbujmy teraz wykorzystać nasz plik właściwości do utworzenia paska narzędzi.Załóżmy, że pliki ikon każdego narzędzia będzie określany w pliku System.properties.Pozwoli to zmienić ikonę narzędzia bez konieczności wprowadzania zmian w kodzieprogramu. Informacje opisujące ikonę narzędzia w pliku właściwości będą miały na-stępującą postać:

��D� ���������$2��������� �� �D� ���E�" ���������$2��������� ����" ���

Właściwości )�� ����� i 1 4����� określają kompletne ścieżki dostępu do ikon na-rzędzi. Możliwość modyfikacji pliku właściwości jest z pewnością lepszym rozwią-zaniem niż modyfikacja kodu programu. Jednak także w tym przypadku natrafiamyna ten sam problem co w przypadku kodowania ścieżki dostępu do samego pliku wła-ściwości. Jeśli użytkownik nie zainstaluje naszej aplikacji w katalogu c:\myApp, toprogram nie odnajdzie plików ikon. Lepszym rozwiązaniem będzie więc umieszczeniew pliku właściwości tylko ścieżek dostępu określonych względem katalogu, w którymzostał zainstalowany program. Musimy wtedy dodatkowo utworzyć właściwość �����*����������, która będzie przechowywać informacje o katalogu, w którym został za-instalowany program. Wiele programów instalacyjnych, na przykład InstallShield, umoż-liwia uzyskanie informacji o katalogu, w którym użytkownik zainstalował aplikację.Dzięki temu można prawidłowo zainicjować właściwość ��������������� i przecho-wywać jedynie względne ścieżki dostępu do zasobów. Na przykład, gdy użytkownikzainstaluje aplikację myApp w katalogu d:\apps\myApp, to zawartość pliku właściwościbędzie wyglądać następująco:

2��������� ����������� ���$2����D� ������������ �� �D� ���E�" ������������ ����" ���

Oczywiście teraz kod programu po pobraniu ścieżki dostępu do zasobu musi dołączaćją do wartości ���������������. Oto fragment kodu pozwalający uzyskać pełną ścież-kę dostępu do zasobu )�� ����� :

'(����������G��������������"�������G�����+,0'-�������� ������+���� ����������$+52��������� ����5,0'/�������� ������+���� ����������$+5��D� �����5,0'1����������� �D���������������� ��������+,0'4����BB�&����"��#J$��%��&����������������� ��"��� �D����������

Użytkownik może teraz zainstalować aplikację w dowolnym katalogu i będzie ona zaw-sze mogła uzyskać dostęp do swoich zasobów.

Page 28: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 115

Z instalacją aplikacji mogą być związane jeszcze inne problemy. Na przykład użytkow-nik zainstalował ją w katalogu /pkgs/programs systemu Unix. Aplikacja nada więc wła-ściwości ��������������� wartość 8����8�����. Aby załadować ikonę przycisku Save,aplikacja dołączy do właściwości ��������������� łańcuch 99���� �99��� ���#. Pełnaścieżka dostępu będzie więc miała postać /pkgs/program\\images\\save.gif, stanowiącmieszankę sposobu zapisu ścieżek w systemach Unix i Windows. Aby rozwiązać tenproblem, napiszemy pomocniczą metodę, która będzie zmieniać format ścieżek w za-leżności od systemu operacyjnego. System operacyjny, w którym działa aplikacja, usta-limy, korzystając z właściwości systemowej ������ . Jeśli będzie nim Unix, to znaki 99zastąpimy w ścieżkach znakiem 8. W ten sposób na przykład ścieżka dostępu do iko-ny przycisku Save uzyska postać /pkgs/programs/images/save.gif.

Kolejny problem związany z naszym zastosowaniem obiektów klasy �� �� � po-lega na zapewnieniu, że wszyscy programiści pracujący nad aplikacją będą korzystaćz metody � �( ���� ��)� ����. Dotychczas omówiliśmy dwa sposoby ładowaniaobiektów �� �� �, ale istnieje ich znaczniej więcej. Jeśli więc kod aplikacji jesttworzony przez kilku programistów, to istnieje szansa, że przynajmniej jeden z nichbędzie ładował obiekty klasy �� �� � inaczej niż pozostali. Taka niespójność mo-że powodować niewłaściwe działanie aplikacji i utrudniać utrzymanie jej kodu. Moż-na jej uniknąć, tworząc na przykład specjalną klasę, która będzie zwracać obiekt klasy�� �� � na podstawie przekazanej jej nazwy pliku właściwości. Poniżej przedsta-wiono kod klasy �� ����� :

'(�����%����� ��������$3�����'-���.'/���������BB��@���� ������������ ������� ��� '1������������D�����������$3�����+,�.>'4�����������$!������"��������!��#�%��������&����'6���������.'7����������������$';��������������.'<��������������������������������� �('���������������������������$3����� �� ����� ����2 ������+����E���,0((�����������������������+� �N�����,(-��������������������.(/���������������������������������� ����� ����"���������� +,0(1����������������������������� ����+� ,0(4������������������������������������ 0(6��������������������>(7��������������>(;������������������+��:=����������,.>�BB���������=������(<�������������������������0-'���������>-(���>

Klasa �� ����� posiada metodę statyczna ��� ��. Może ona, tak jak w naszymprzykładzie, sama obsługiwać wyjątek �"�'� ����� lub tylko go wyrzucać, wymagającobsłużenia go przez kod wywołujący metodę. Niezależnie od wybranego sposobu ob-sługi wyjątku klasa �� ����� umożliwia załadowanie obiektu �� �� � przyskorzystaniu ze ścieżki dostępu do klas. Załadowanie obiektu �� �� � odbywa sięnastępująco:

��������� ����� ���������$3����� ����+5B�$2�� ��������� 5,0

Page 29: Java. Potrzaski

116 Java. Potrzaski

Wadą klasy �� ����� jest to, że ogranicza nas tylko do obiektów klasy �� �� �.Chociaż klasa �� �� � posiada szereg użytecznych metod, to czasami przydatne oka-zują się jeszcze inne. Na przykład, gdy zachodzi potrzeba zamiany wartości właściwo-ści klasy )���� na wartość typu ��� lub ���� ��. Klasy ��� � i ,��� �� dostarczająco prawda metody umożliwiającej przekształcenie wartości właściwości )��� �����na typ ��� lub ���� ��, ale nie jest możliwe jej zastosowanie do dowolnego pliku wła-ściwości. Kolejną przydatną metodą jest � ������ ����, która automatyzuje kon-wersję formatu ścieżek dostępu dla różnych systemów operacyjnych. Zamiast zmuszaćużytkownika klasy �� ����� do samodzielnej implementacji wspomnianych me-tod, możemy utworzyć klasę ������ �� �� � jako pochodną klasy �� �� � za-wierającą dodatkowe metody. Klasa ������ �� �� � może wyglądać następująco:

'(�����%����� �:��������������� ��=���� ���������� '-���.'/���������%���:��������������� +,'1�������.'4���������� ����+,0'6�������>'7���������%���:��������������� +��������� �������� ,';�������.'<���������� ����+������� ,0('�������>((���������%���:��������������� +������������� ,������" ���:=������(-�������.(/��������������+� ,0(1�������>(4���������%���%��������������$��G������+�������&�$,(6�������.(7����������BB����������D�������������D����������%�������D���� (;�������>(<���������%��������������$�����+�������&�$,-'�������.-(����������BB����������D�������������D���������������D���� --�������>-/���������%������������������������$+�������&�$,-1�������.-4����������BB����������D����������������������D�����������������������-6���������� $ ���������D���� -7�������>-;���>

Musimy jeszcze zmodyfikować klasę �� ����� tak, by zwracała obiekt klasy������ �� �� � zamiast �� �� �:

����������"�:��������������� +� ,0

Ponieważ w wierszu 11. klasy ������ �� �� � dodaliśmy konstruktor, którego pa-rametrem jest �����)� ��, to wiersze 12. – 14. klasy �� ����� możemy zastą-pić pojedynczym wierszem pokazanym wyżej. W klasie ������ �� �� � umie-ściliśmy tylko kilka propozycji dodatkowych metod, pozostawiając pozostałe inwencjiCzytelnika.

Page 30: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 117

Zagadnienie 22.Klasa Vector i nowe kolekcje

Stare przyzwyczajenia ciężko zmienić. Dlatego też wielu programistów, którzy inten-sywnie używali kolekcji w języku Java 1.0, niechętnie decyduje się porzucić swoje do-świadczenia i rozpocząć programowanie z wykorzystaniem nowych kolekcji zapropo-nowanych w następnych wersjach języka Java. Zadaniem tego zagadnienia jest pomócwykonać pierwszy krok w tym kierunku. Zamiast więc atakować Czytelnika ogromnąliczbą informacji o nowych kolekcjach i ich wspaniałych możliwościach, wybraliśmyzdecydowanie prostszy sposób. Pokażemy przykład zastosowania poprzedniej wersji kla-sy � ���, a następnie ten sam przykład wykorzystujący nowy interfejs klasy � ���.To najłatwiejszy sposób zapoznania się z podobieństwami i różnicami obu klas, któryumożliwi samodzielne poznanie pozostałych ponad 25 klas zawierających nowy zbiórkolekcji.

Zanim przejdziemy do omówienia przykładów, przedstawmy krótko nowy interfejskolekcji. Stanowi on szkielet umożliwiający tworzenie kolekcji i wykonywanie na nichoperacji. Przez kolekcję rozumiemy w tym przypadku grupę obiektów. Nowy interfejskolekcji definiuje kilka rodzajów takich grup — kolekcje, listy, mapy i zbiory. Każdaz tych kategorii jest reprezentowana przez interfejs, klasę abstrakcyjną i jedną klasękonkretną lub więcej. Uzupełnienie stanowią operacje oglądania kolekcji za pomocąiteratorów, porównań wewnątrz kolekcji, wyszukiwania elementów kolekcji oraz sor-towania kolekcji.

W pierwszym programie zademonstrowano najczęściej używane metody klasy � ���.Zawiera on przykłady dodawania i usuwania elementów wektora, wstawiania elemen-tów, pobierania elementów, kopiowania elementów wektora do tablicy obiektów, zasto-sowania obiektu ���� ����� do przeglądania wektora oraz wywołania metody usuwa-jącej wszystkie elementy wektora.

'(���������!�D� ���� H0'-�'/����%����� ���������2��'1��.'4��������%��� �����D���������+���������� )*,'6������.'7����������������D����"������+,0';����������D ���:������+59 �:�����5,0'<����������D ���:������+5] �2��� ��5,0���������--('����������D ���:������+5^ �:��5,0((����������D ���:������+52 �^�"���5,0(-����������D ���:������+5E �2��5,0(/�(1����������D ����D�:������2�+1,0(4����������D ����D�:������+5] �2��� ��5,0(6����������D �� ���:������2�+5F ������ 5��(,0(7�(;���������������+D,0(<���������������:������ +D ������� +,,0-'�

Page 31: Java. Potrzaski

118 Java. Potrzaski

-(�����������%!��)*�������E��� ����"��%!��)D �#�+,*0--����������D ��$����+������E��� ,0-/����������D ����D�2��:������ +,0-1������>-4�-6��������%��� �����D����������+������D,-7������.-;��������������������� ��D �#�+,0-<��������������+�������'0���V�������� 0��AA,/'���������������$ ��� ��� �������+D �������2�+�,,0/(������>/-�//��������%��� �����D���������:������ �+:������������,/1������./4����������"�����+� �� 9���:������ +,,/6���������������$ ��� ��� �������+� ��=�:������+,,0/7������>/;��>

Modyfikacja tego programu tak, aby wykorzystywał nowy interfejs wektorów, jest bar-dzo prosta. Odpowiedniki metod zawiera tabela 3.1.

Tabela 3.1. Porównanie poprzedniego i bieżącego interfejsu wektorów

Poprzedni interfejs Bieżący interfejs

D�����##�!����+�%!��, %������ �##+�%!��,

D������� ���+�%!��)*, �%!��)*��'��� +,

�%!����!����'+���, �%!�����+���,

:������������!�����+, ��������������+,

D���������!����'+�%!�������, D�����##+����=���%!��,

D��������(�'!!�!�����+, D�����!���+,

%�����������(��!����+�%!��, %�����������(�+�%!��,

D��������(��!����'+���, D��������(�+���,

�����)�+, �����)�+,

Klasa � ��� w nowym zestawie kolekcji implementuje interfejs ����. W następnej wer-sji programu można więc upewnić się, że korzystamy z nowych kolekcji, podstawia-jąc referencję nowo utworzonego wektora do zmiennej typu ����. Oczywiście, metodyspecyficzne dla klasy � ��� nie będą wtedy dostępne bez jawnego zastosowania rzu-towania. Oto wersja programu wykorzystująca nowe kolekcje:

'(���������!�D� ���� H0'-�'/����%����� �E�"�����2��'1��.'4��������%��� �����D���������+���������� )*,'6������.'7����������3� ��D����"������+,0';����������D ���+59 �:�����5,0'<����������D ���+5] �2��� ��5,0('����������D ���+5^ �:��5,0((����������D ���+52 �^�"���5,0

Page 32: Java. Potrzaski

Rozdział 3. ♦ Użyteczne klasy i kolekcje 119

(-����������D ���+5E �2��5,0(/�(1����������D ����D�+1,0(4����������D ����D�+5] �2��� ��5,0(6����������D ���+(��5F ������ 5,0(7�(;���������������+D,0(<���������������:������ +D ��������+,,0-'�-(�����������%!��)*�������E��� ��D ��2���$+,0--����������D ����+,0-/������>-1�-4��������%��� �����D����������+3� ��D,-6������.-7��������������������� ��D �#�+,0-;��������������+�������'0���V�������� 0��AA,-<���������������$ ��� ��� �������+D ���+�,,0/'������>/(�/-��������%��� �����D���������:������ �+�����������,//������./1����������"�����+�� �� E�=�+,,/4���������������$ ��� ��� �������+�� ��=�+,,0/6������>/7��>

Oprócz różnic interfejsu klasy � ��� podanych w tabeli 3.1 należy wskazać jeszczejedną. Nowe kolekcje bazują na koncepcji iteratora służącego do czytania ich zawar-tości. W zależności od typu kolekcji iteratory mogą posiadać różne poziomy funkcjo-nalności. Klasa � ��� implementuje interfejs ����, który specyfikuje dwa rodzaje ite-ratorów. Pierwszy z nich, klasy �� ���, musi być implementowany przez wszystkiekolekcje. Drugi, klasy ������ ���, posiada dodatkową funkcjonalność.

Porównując wiersze 35. i 36. pierwszej wersji programu z wierszami 34. i 35. drugiejwersji, zauważymy, że metody klas ���� ����� i �� ��� są bardzo zbliżone. Metoda���� ���������$� �� � ����� stanowi odpowiednik metody �� �������1 '���,a metoda ���� ������� '��� � ���� — odpowiednik metody �� ����� '���. Kla-sa �� ��� posiada dodatkowo metodę ��� ��, co daje jej pewną przewagę nadklasą ���� �����. Klasa �� ��� stanowi najmniejszy wspólny mianownik w dostę-pie do elementów różnych typów kolekcji.

Klasa ������ ��� udostępnia bardziej rozbudowaną funkcjonalność: pozwala mody-fikować listę (dodawać, modyfikować i usuwać elementy), a także przeglądać ją w obukierunkach. Programista ma więc do wyboru operacje na liście wykonywane za pomocąmetod iteratora ������ ��� lub metod interfejsu ����.

Stosowanie większości nowych kolekcji nie jest bezpieczne w programach wielowątko-wych. Dotyczy to na przykład klasy ������� będącej klasą siostrzaną klasy � ���(czyli klasą implementującą interfejs ����). Natomiast użycie klasy � ��� jest nadalbezpieczne z punktu widzenia wątków. Programista dokonuje więc wyboru, czy korzy-sta z klasy �������, której zastosowanie w programie wielowątkowym nie jest bez-pieczne, czy też klasy � ���, którą może bez obaw używać w wielu wątkach.

Page 33: Java. Potrzaski

120 Java. Potrzaski

Zastosowanie klasy � ��� pochodzącej z nowego zestawu kolekcji nie daje większejefektywności w porównaniu z poprzednią wersją, ale zapewnia większą modyfikowal-ność i uniwersalność kodu. Jeśli na przykład okaże się, że wydajność programu jest zamała, to (zamiast klasy � ���) możemy wykorzystać inną implementację ze zbioru no-wych kolekcji. W przypadku poprzedniej wersji klasy � ��� oznaczałoby to koniecz-ność modyfikacji programu. Warto więc przekonać się do stosowania nowych kolek-cji, ponieważ ułatwia to utrzymanie kodu i zwiększa możliwości jego modyfikacji.