JavaRush /Blog Java /Random-PL /Wprowadzenie do String, StringBuffer i StringBuilder w Ja...

Wprowadzenie do String, StringBuffer i StringBuilder w Javie

Opublikowano w grupie Random-PL
W Javie istnieją trzy klasy do pracy z danymi tekstowymi: String , StringBuffer i StringBuilder . Z tym pierwszym każdy programista spotyka się na samym początku nauki języka. A co z pozostałą dwójką? Jakie są między nimi różnice i kiedy lepiej jest użyć tej czy innej klasy? Generalnie różnica między nimi jest niewielka, ale lepiej wszystko zrozumieć w praktyce :) Wprowadzenie do String, StringBuffer i StringBuilder w Javie - 1

Klasa string

Ta klasa reprezentuje sekwencję znaków. Wszystkie literały łańcuchowe zdefiniowane w programach, takie jak „This is String”, są instancjami klasy String. Ciąg ma dwie podstawowe cechy:
  • jest to klasa niezmienna
  • to są ostatnie zajęcia
Ogólnie rzecz biorąc, klasa String nie może mieć dzieci ( final), a instancje klasy nie mogą być modyfikowane po utworzeniu ( immutable). Daje to klasie String kilka ważnych zalet:
  1. Ze względu na niezmienność kod skrótu instancji klasy String jest buforowany. Nie trzeba go oceniać za każdym razem, ponieważ wartości pól obiektu nigdy nie ulegną zmianie po jego utworzeniu. Zapewnia to wysoką wydajność podczas używania tej klasy jako klucza dla HashMap.

  2. Klasy String można używać w środowisku wielowątkowym bez dodatkowej synchronizacji.

  3. Inną cechą klasy String jest to, że przeciąża ona +operator „ ” w Javie. Dlatego łączenie (dodawanie) ciągów jest dość proste:

public static void main(String[] args) {
    String command = "Follow" + " " + "the" + " " + "white" + " " + "rabbit";
    System.out.println(command); // Follow the white rabbit
}
W skrócie, łączenie ciągów znaków odbywa się za pomocą klasy StringBuilder lub StringBuffer (według uznania kompilatora) oraz metody append(o tych klasach porozmawiamy nieco później). Jeśli dodamy instancje klasy String do instancji innych klas, ta ostatnia zostanie zredukowana do reprezentacji łańcuchowej:
public static void main(String[] args) {
    Boolean b = Boolean.TRUE;
    String result = "b is " + b;
    System.out.println(result); //b is true
}
To kolejna interesująca właściwość klasy String: obiekty dowolnej klasy można rzutować na reprezentację w postaci ciągu znaków przy użyciu metody toString()zdefiniowanej w klasie Objecti dziedziczonej przez wszystkie inne klasy. Często metoda toString() na obiekcie jest wywoływana niejawnie. Na przykład, gdy wyświetlamy coś na ekranie lub dodajemy String do obiektu innej klasy. Klasa String ma jeszcze jedną funkcję. Wszystkie literały łańcuchowe zdefiniowane w kodzie Java, takie jak „asdf”, są buforowane w czasie kompilacji i dodawane do tak zwanej puli ciągów. Jeśli uruchomimy następujący kod:
String a = "Wake up, Neo";
String b = "Wake up, Neo";

System.out.println(a == b);
W konsoli zobaczymy wartość true , ponieważ zmienne będą aw rzeczywistości bodnosić się do tej samej instancji klasy String, która została dodana do puli ciągów w czasie kompilacji. Oznacza to, że nie są tworzone różne instancje klasy o tej samej wartości, a pamięć jest zapisywana.

Wady:

Nietrudno się domyślić, że klasa String jest potrzebna przede wszystkim do pracy z ciągami znaków. Jednak w niektórych przypadkach powyższe cechy klasy String mogą zamienić zalety w wady. Po utworzeniu ciągów znaków w kodzie Java często wykonuje się na nich wiele operacji:
  • konwertowanie ciągów znaków do różnych rejestrów;
  • ekstrakcja podciągów;
  • powiązanie;
  • itp.
Spójrzmy na ten kod:
public static void main(String[] args) {

    String s = " Wake up, Neo! ";
    s = s.toUpperCase();
    s = s.trim();

    System.out.println("\"" + s + "\"");
}
Na pierwszy rzut oka wydaje się, że właśnie przetłumaczyliśmy wiersz „Obudź się, Neo!” na wielkie litery, usuń dodatkowe spacje z tego ciągu i owiń go w cudzysłów. Tak naprawdę, ze względu na niezmienność klasy String, w wyniku każdej operacji tworzone są nowe instancje stringów, a stare są odrzucane, generując dużą ilość śmieci. Jak uniknąć marnowania pamięci?

Klasa StringBuffer

Aby obsłużyć tworzenie tymczasowych śmieci w wyniku modyfikacji obiektu String, możesz użyć klasy StringBuffer. Jest to mutableklasa, tj. zmienny. Obiekt klasy StringBuffer może zawierać określony zestaw znaków, których długość i wartość można zmieniać wywołując określone metody. Zobaczmy, jak działa ta klasa. Aby utworzyć nowy obiekt, użyj jednego z jego konstruktorów, na przykład:
  • StringBuffer() - utworzy pusty obiekt (bez znaków).
  • StringBuffer(String str) - utworzy obiekt na podstawie zmiennej str (zawierającej wszystkie znaki str w tej samej kolejności)
Ćwiczyć:
StringBuffer sb = new StringBuffer();
StringBuffer sb2 = new StringBuffer("Not empty");
Łączenie ciągów za pomocą StringBuffer w Javie odbywa się za pomocą metody append. Generalnie metoda appendw klasie StringBuffer jest przeciążona w taki sposób, że może przyjąć niemal każdy typ danych:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2));
    sb.append("; ");
    sb.append(false);
    sb.append("; ");
    sb.append(Arrays.asList(1,2,3));
    sb.append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
Metoda appendzwraca obiekt, na którym została wywołana (jak wiele innych metod), co pozwala na wywołanie jej w „łańcuchu”. Powyższy przykład można zapisać w następujący sposób:
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer();

    sb.append(new Integer(2))
            .append("; ")
            .append(false)
            .append("; ")
            .append(Arrays.asList(1,2,3))
            .append("; ");

    System.out.println(sb); // 2; false; [1, 2, 3];
}
Klasa StringBuffer posiada wiele metod pracy z ciągami znaków. Wymieńmy główne:
  • delete(int start, int end)— usuwa podciąg znaków zaczynający się od pozycji starti kończącyend
  • deleteCharAt(int index)— usuwa znak na pozycjiindex
  • insert(int offset, String str)— wstawia linię strw pozycji offset. Metoda insertjest również przeciążona i może przyjmować różne argumenty
  • replace(int start, int end, String str)- zastąpi wszystkie znaki od pozycji startdo pozycji endprzezstr
  • reverse()— odwraca kolejność wszystkich znaków
  • substring(int start)- zwróci podciąg zaczynający się od pozycji start
  • substring(int start, int end)- zwróci podciąg zaczynając od pozycji startdo pozycjiend
Pełna lista metod i konstruktorów znajduje się w oficjalnej dokumentacji . Jak działają powyższe metody? Zobaczmy w praktyce:
public static void main(String[] args) {
     String numbers = "0123456789";

     StringBuffer sb = new StringBuffer(numbers);

     System.out.println(sb.substring(3)); // 3456789
     System.out.println(sb.substring(4, 8)); // 4567
     System.out.println(sb.replace(3, 5, "ABCDE")); // 012ABCDE56789

     sb = new StringBuffer(numbers);
     System.out.println(sb.reverse()); // 9876543210
     sb.reverse(); // Zwróć oryginalne zamówienie

     sb = new StringBuffer(numbers);
     System.out.println(sb.delete(5, 9)); // 012349
     System.out.println(sb.deleteCharAt(1)); // 02349
     System.out.println(sb.insert(1, "One")); // 0One2349
    }

Zalety:

  1. Jak już wspomniano, StringBuffer jest klasą zmienną, więc praca z nią nie powoduje powstania takiej samej ilości śmieci w pamięci, jak w przypadku String. Dlatego też, jeśli w łańcuchach wprowadza się wiele modyfikacji, lepiej jest użyć StringBuffer.

  2. StringBuffer jest klasą bezpieczną dla wątków. Jego metody są zsynchronizowane, a instancje mogą być używane przez wiele wątków jednocześnie.

Wady:

Z jednej strony bezpieczeństwo gwintu jest zaletą tej klasy, z drugiej jest wadą. Metody zsynchronizowane są wolniejsze niż metody niezsynchronizowane. Tutaj w grę wchodzi StringBuilder. Zastanówmy się, jaki to rodzaj klasy Java - StringBuilder, jakie ma metody i jakie są jej funkcje.

Klasa StringBuilder

StringBuilder w Javie to klasa reprezentująca sekwencję znaków. Jest bardzo podobny do StringBuffer pod każdym względem, z wyjątkiem bezpieczeństwa wątków. StringBuilder zapewnia interfejs API podobny do StringBuffer. Zademonstrujmy to na znanym już przykładzie, zastępując deklarację zmiennych z StringBufer na StringBuilder:
public static void main(String[] args) {
    String numbers = "0123456789";

    StringBuilder sb = new StringBuilder(numbers);

    System.out.println(sb.substring(3)); //3456789
    System.out.println(sb.substring(4, 8)); //4567
    System.out.println(sb.replace(3, 5, "ABCDE")); //012ABCDE56789

    sb = new StringBuilder(numbers);
    System.out.println(sb.reverse()); //9876543210
    sb.reverse(); // Zwróć oryginalne zamówienie

    sb = new StringBuilder(numbers);
    System.out.println(sb.delete(5, 9)); //012349
    System.out.println(sb.deleteCharAt(1)); //02349
    System.out.println(sb.insert(1, "One")); //0One2349
}
Jedyna różnica polega na tym, że StringBuffer jest bezpieczny dla wątków i wszystkie jego metody są zsynchronizowane, podczas gdy StringBuilder nie. To jedyna funkcja. StringBuilder w Javie jest szybszy niż StringBuffer ze względu na brak synchronizacji metod. Dlatego w większości przypadków, z wyjątkiem środowiska wielowątkowego, lepiej jest używać StringBuilder dla programu Java. Podsumowujemy wszystko w tabeli porównawczej trzech klas:

String vs StringBuffer vs StringBuilder

Strunowy Bufor ciągów Konstruktor ciągów
Zmienność Immutable(NIE) mutable(Tak) mutable(Tak)
Rozciągliwość final(NIE) final(NIE) final(NIE)
Bezpieczeństwo nici Tak, ze względu na niezmienność Tak, ze względu na synchronizację NIE
Kiedy użyć Podczas pracy z ciągami znaków, które rzadko będą modyfikowane Podczas pracy z ciągami znaków, które będą często modyfikowane w środowisku wielowątkowym Podczas pracy z ciągami, które będą często modyfikowane w środowisku jednowątkowym
Temat ten możesz przestudiować bardziej szczegółowo na drugim poziomie zadania Java Multithreading w kursie JavaRush:
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION