StringBuilder i StringBuffer w Javie

Przetwarzanie danych tekstowych należy do jednych z ważniejszych elementów pracy przy komputerze. Na początku naszego szkolenia już wspominaliśmy o klasie String. Nadszedł czas na nieco szersze ujęcie problemu łańcuchów znakowych – bardziej od strony technicznej.

Budowa klasy String

Wśród typów prostych tylko char służy do przechowywania znaków. Jednakże dopiero tablica pozwala umieszczać całe ciągi znakowe. W Javie klasa String używa tablicę byte.

Pola

Klasa String składa się z wielu pól, ale nas interesuje najważniejsze.

Zwróćmy uwagę na to, że to pole jest finalne i tablicy nie można modyfikować po utworzeniu obiektu. Dzięki różnym konstruktorom obiekty klasy String można tworzyć na różne sposoby.

Łańcuchy w Javie zawsze są przechowywane w klasie String w związku z tym bez problemu można je przypisać do zmiennej.

Konstruktory

Konstruktor bezargumentowy wygląda następująco.

Jak widać do pola value przypisywany jest pusty łańcuch. Jest on obiektem typu String zatem przypisywana jest wartość jego pola value. Nie należy go mylić z wartością null.

Konkatenacja – łączenie Stringów

Skonfrontujmy teraz wiedzę z naszego szkolenia z klasy String. Pokazywaliśmy tam przecież możliwość łączenia łańcuchów przy pomocy przeciążonego operatora +. Istnieje również metoda o identycznym działaniu concat().

W obu przypadkach efektem będzie wyświetlenie komunikatu.

Witaj na szkoleniu na programistajava.pl

Jak widać powyżej połączyliśmy w jeden napis dwa obiekty typu String. Jak to się ma do finalnego pola value? Obiekty typu String zawsze są niemodyfikowalne. Natomiast zarówno użycie operatora + lub metody concat() powoduje zwrócenie nowego obiektu, który składa się z dwóch uprzednio osobnych łańcuchów.

Aby udowodnić powyższe stwierdzenia wykorzystamy metodę identityHashCode() z klasy System. Zaznaczamy, że ta metoda nie zwróci adresu obiektu, a jedynie unikalny kod obiektu. Klasa String posiada swoją implementację metody hashCode(), która porównuje także treść łańcucha. Z tego względu użyliśmy metody, która działa analogicznie do tej z klasy Object. Metoda identityHashCode() jest natywna, co oznacza, że jest napisana w innym języku niż Java. Jest to spowodowane sposobem implementacji, który może zwracać wartość int na podstawie adresu zmiennej. A z poziomu Javy nie ma do niego dostępu.

Spójrzmy zatem na poniższy program.

Poniżej pokazujemy wynik wywołania.

hashS: 2055281021

hashS2: 1554547125

Jak widać powyżej wyniki są różne mimo sprawdzenia dokładnie tej samej zmiennej. Z tego wynika, że obiekt s utworzony w miejscu pamięci nie został zmodyfikowany. Kompilator utworzył nowy obiekt złożony z dwóch zmiennych s i s2, a następnie przypisał referencję, do niego pod zmienną s.

StringBuilder, StringBuffer

Powyższy wstęp pokazuje istotną wadę korzystania z klasy String czyli modyfikowanie łańcucha. Jest ona bardzo kosztowna szczególnie przy wielu zmianach (np. pętla). Z pomocą przychodzą klasy StringBuilder oraz StringBuffer. Ich działanie jest identyczne. Posiadają dokładnie te same metody. Jedyną różnicą jest synchronizacja między wątkami. Klasa StringBuffer ją zapewnia, w związku z tym jeśli wiele wątków będzie modyfikować łańcuch należy z niej skorzystać. W przeciwnym wypadku ze względu na szybkość działania polecamy używać StringBuilder.

Konstruktory

Obie klasy posiadają ten sam zestaw konstruktorów.

  • StringBuilder() – tworzy obiekt o pojemności 16.
  • StringBuilder(int capacity) – konstruuje obiekt o pojemności capacity.
  • StringBuilder(String s) – tworzy obiekt zawierający łańcuch s o pojemności 16 + długość łańcucha.
  • StringBuilder(CharSequence cs) – tworzy obiekt zawierający takie same znaki jak cs o pojemności 16 + długość łańcucha.

Metody

  • StringBuilder append() – dodaje tekst do istniejącego obiektu. Przyjmuje różne argumenty w tym typy liczbowe, znakowe oraz String.
  • int capacity() – zwraca rozmiar tablicy wewnętrznej
  • String substring(int start, int end) – zwraca String, który zawiera sekwencję znaków od start do end.
  • StringBuilder delete(int start, int end) – usuwa sekwencję znaków w podanym przedziale.
  • String toString()– zwraca całą sekwencję znaków w postaci String.

Przykłady użycia

Poniżej pokażemy przykład łączenia Stringów w Javie korzystając z obiektu klasy StringBuilder. Służy do tego metoda append().

Wynik działania programu jest następujący.

Optymalizowanie pracy z tekstem przy pomocy obiektu StringBuilder jest szczególnie istotne przy używaniu pętli.

W następnej części przyjrzymy się plikom w Javie.