Tak oto dochodzimy do ostatniego artykułu z długiego cyklu na temat języka Java. W przyszłości mogą pojawić się jeszcze jakieś, ale będą to pojedyncze wpisy. Na dzisiaj mam dla Was coś specjalnego na odejście od tematu. Czy zdajecie sobie sprawę, że mogliście wielokrotnie źle korzystać z łańcucha znaków od czasu utworzenia instancji? Dowiedzieliśmy się już znacznie wcześniej, że łańcuch znaków sprawia trudności w języku C, aczkolwiek w Javie też jest pewna pułapka i to o wiele bardziej perfidna, bo niedająca po sobie niczego poznać. Zapraszam serdecznie, to jest bardzo ważny wątek!

ŁAŃCUCH ZNAKÓW MA JESZCZE JEDNĄ TAJEMNICĘ

Sytuacja o której będę pisać stanowi regularny manewr u wielu początkujących. ZŁY manewr, jeśli chodzi o ścisłość. Zacznijmy od początku. Tworzymy sobie nowy "String":

String s = "Nowy łańcuch";

przypisując do niego wartość, tak jak ma to miejsce przy każdym obiekcie. W Javie, łańcuch znaków jest obiektem, stąd konieczna wielka litera. Dopiero w C# ten typ danych "doczekał się" aliasu pozwalającego na pisanie "string" z małej litery. Przechodzimy do sedna. Możemy bezkarnie zmienić sobie łańcuch na inny przy użyciu operatora przypisania:

s = "Inny łańcuch";

Wiemy już dobrze, że w C ten numer nie przejdzie i program się wysypie z powodu doprowadzenia do naruszenia ochrony pamięci. Nie dziwi Was, że w tym przypadku jest to dozwolone? A może...to "tylko" pociąga za sobą inne konsekwencje których nie będzie widać na pierwszy rzut oka? Warto się zastanowić co się dzieje oraz co się NIE dzieje.

PRAWIDŁOWE DZIAŁANIE TEŻ POWINNO DAĆ DO MYŚLENIA

Po kolei. Tworzymy nową instancję typu "łańcuch znaków" i przypisujemy dowolny łańcuch. Chwilę później już za pomocą osobnej instrukcji przypisania zmieniamy bezkarnie łańcuch i program idzie dalej. W języku C to się wywali, ale tutaj nie i to wcale nie jest "zasługa" wyższego poziomu abstrakcji języka ani magicznych sztuczek. TO JEST BŁĄD! Nic się złego nie stanie z programem, ale od tego momentu kaleczymy pamięć RAM. Dlaczego?

"String" jest obiektem niemodyfikowalnym (ang. "immutable") co oznacza, że raz przypisanej wartości do zaalokowanej pamięci nie możemy zmienić z formalnego punktu widzenia. Możecie wytrzeszczać oczy i się dziwić. "Jak nie można zmienić jak przypisuję nowy łańcuch znaków linijkę niżej i działa?". To, że działa to wcale nie znaczy, że zmieniana jest wartość! W rzeczywistości, adres zmiennej do starego łańcucha jest "odpinany", przydzielana jest zupełnie odrębna pamięć dla drugiego łańcucha, a na samym końcu adres zmiennej zostaje ponownie "podpięty" i wskazuje na ten drugi łańcuch.

W wyniku takiego manewru dochodzi do wycieku pamięci, gdyż poprzednia pamięć nie zostaje zwolniona! Ona sobie gdzieś "lata" i już nigdy nie zostanie odnaleziona ani wykorzystana.

Niemodyfikowalny łańcuch znaków w Java

Za każdym razem, gdy występuje przypisanie nowego łańcucha, bądź konkatenacja, wbrew intuicyjnemu wnioskowaniu, następuje "odrzucenie" starego łańcucha i wskazywanie przez adres tej samej zmiennej na nowy łańcuch wymagający przydzielenia osobnej pamięci bez zwalniania poprzedniej.

ŁAŃCUCH ZNAKÓW JAKO "BUDOWNICZY"

Rozwiązania są dwa: albo korzystać z obiektu "String" przypisując do niego jakiś łańcuch tylko jeden raz i traktować jak zmienną lokalną, albo skorzystać z obiektu "StringBuilder", który sprawia, że łańcuch znaków jest modyfikowalny. Można do niego dodawać znaki, łańcuchy, można go wycinać i tak dalej. Co najważniejsze, korzysta z tej samej pamięci i nie dochodzi do żadnych wycieków.

StringBuilder sb = new StringBuilder("Nowy łańcuch");

Zainteresowanych metodami jakie oferuje "StringBuilder" odsyłam do dokumentacji Javy.


Wszystko. Więcej tłumaczeń nie trzeba poświęcać na to zagadnienie. Lekcja na przyszłość brzmi tak: nie myśl, że modyfikując łańcuch znaków ominiesz wszystkie nieprzyjemności, które pojawiały się w języku C. Od tej chwili, gdy macie pewność, że jeden "String" będzie musiał być edytowany, sięgnijcie po "StringBuilder" i śpijcie spokojnie ze świadomością, że Wasz program nie wyżre systemowi megabajtów pamięci.

PODOBNE ARTYKUŁY