Jason. Cała informatyka w jednym miejscu!

Na dzisiaj mam dla Was coś specjalnego na temat języka Java. 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 znany pod hasłem "String" w języku Java 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!

TYP "STRING" W JĘZYKU JAVA SKRYWA PEWNĄ 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 obiekt typu "String":

String s = "Nowy łańcuch";

przypisując do niego wartość, tak jak ma to miejsce przy każdym obiekcie. Typ "String" w języku Java jest obiektem, stąd konieczna wielka litera. Dopiero w C# ten typ danych "doczekał się" aliasu pozwalającego na pisanie "string" małą literą. Przechodząc do sedna, możemy bezkarnie zmienić sobie łańcuch na inny przy użyciu operatora przypisania:

s = "Inny łańcuch";

Ci którzy korzystają z języka C wiedzą, że 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. "String" w języku Java to przepuści, lecz w języku C to się wywali 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" na stercie i już nigdy nie zostanie odnaleziona ani wykorzystana.

Schemat przypisywania nowego łańcucha znaków w języku 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. Proces odbywa się bez zwalniania poprzedniej pamięci!

JAKIEŚ OBEJŚCIE?

Rozwiązania są dwa: albo korzystać z obiektu "String" w języku Java 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 (w przeciwieństwie do "String"). Można do niego dodawać znaki, łańcuchy, można go wycinać i tak dalej. Co najważniejsze, obiekt korzysta wtedy 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 wielu megabajtów pamięci.

PODOBNE ARTYKUŁY