Pierwszą rzecz, którą musisz wiedzieć o łańcuchach znaków to to, że nie istnieje typ prosty je obsługujący. String w Javie jest klasą, której implementacja jest oparta na typie znakowym (char) i tablicach. Obie te kwestie omawiałem już wcześnie, także powinieneś rozumieć, że String to nic innego jak zlepek zmiennych typu char. Teoretycznie moglibyśmy stworzyć sami tablicę tego rodzaju i wypełniać je pojedynczymi znakami, ale byłoby to niemiłosiernie uciążliwe.
String jest literałem
String podobnie jak każda klasa opakowująca (Integer, Double, itp.) jest literałem i można przypisywać do niego wartości w dwojaki sposób: przez new i znak równości.
String someStringObject = new String(„Ala ma kota”); String quickString = “Ala ma kota”;
Teraz spróbujmy porównać czy dwa łańcuchy zawierają tą samą zawartość. W przypadku liczb można to zrobić bardzo łatwo używając operatora porównania (==) oraz instrukcji warunkowej if. Ogólny zarys jej działania jest bardzo prosty: jeśli coś spełnia warunek to jest wykonywane, w przeciwnym razie wykonywany jest kod, który został napisany po instrukcji else.
Na przykład:
int firstNumberToCheck = 1; int secondNumberToCheck = 2; if (firstNumberToCheck == secondNumberToCheck) { System.out.println(“Są rownie”); } else { System.out.println(„Nie są sobie równe); }
Rezultat: nie są sobie równe (łatwe do przewidzenia). Teraz spróbuję zrobić coś podobnego z instrukcjami
Instrukcje warunkowe mogą mieć więcej niż dwa warunki.
String checkValue = "1"; if (checkValue == 1) { System.out.println("1"); } else if (checkValue == 2) { System.out.println("2"); } else { System.out.println("coś innego"); }
Teraz spróbuję porównać dwa Stringi. Wynik: „1” oznacza, że udało mi się sprawdzić czy String jest taki sam jak „1”. Ale co się stanie, gdy stworzę łańcuch poprzez słowo kluczowe ‘new’?
String stringMyObject = new String("1"); if (stringMyObject == "1") { System.out.println("1"); } else { System.out.println("coś innego"); }
Używanie equals przy Stringach
Program nie zadziałał poprawnie. Dzieje się tak, dlatego że dla porównywania Stringów utworzonych jako obiekty należy używać specjalnej metody porównującej o nazwie ‘equals’. Sprawdźmy zatem.
String stringTwo = new String("2"); if (stringTwo.equals("2")) { System.out.println("2"); } else { System.out.println("coś innego"); }
Teraz udało się porównać dwa łancuchy znaków.
Zobaczmy co jeszcze oferuje klasa String.
- charAt(indexNumber) – zwraca znak po indeksie z łańcucha
- indexOf(charValue) – odwrotna metoda do poprzedniej, zwraca numer indeksu pierwszego wystąpienia danego znaku
- length() – zwraca długość łańcucha znaków
- contains(charValue) – zwraca ‘true’, jeśli w łańcuchu znajdował się szukany znak.
- matches(stringValue) – podobna metoda to tej wyżej, tylko wyszukuje w łańcuchu inny tekst po wyrażeniu regularnym*.
- contact(stringValue) – łączy ze sobą dwa łańcuchy. Alternatywnie możesz też używać operatora dodawania (+), aby osiągnąć ten sam efekt.
- isEmpty() – zwraca ‘true’, gdy łańcuch jest pusty (ale nie może być nullem!)
- replaceAll(originalStringToReplace, newVersionOfString) – szuka wyrażeniem regularnym określonego fragmentu tekstu i podmienia go na nowy we wszystkich miejscach.
- split(delimiter) – dzieli tekst na części, jeśli oddziela je konkretny delimiter (np. spacja, przecinek, dwukropek, itp.)
- substring(beginIndex, endIndex) – wydziela fragment tekstu zawartego między indeksami
- toLowerCase() – zmienia wszystkie znaki z liter wielkich na małe
- toUpperCase() – to samo, co wyżej tylko zamienia na wielkie
- trim() – usuwa spacje wiodące (na początku tekstu) oraz te na końcu.
Jest oczywiście jeszcze wiele innych metod. Wymieniłem jedynie te najciekawsze.
StringBuilder i StringBuffer
Klasa String ma jeszcze jedną ważną właściwość, którą warto poznać, jest klasą typu „immutable” (niezmienna). Nigdy nie używam w języku potocznym określenia polskiego, więc pozwolisz, że będę w tym i następnych postach używał tylko wersji angielskiej. Idea takiej klasy jest taka, że zawartość jej raz stworzonego obiektu pozostaje cały czas taka sama.
O klasach immutable jeszcze napiszę, natomiast na ten moment ważne jest zrozumienie, że stworzenie raz jakiegoś łańcucha znaków, powoduje że, gdy chcemy do niego dodać kolejny to Java może stworzyć w pamięci nowy łańcuch zamiast (co wydawałoby się logiczne) dodać do obecnego kolejny fragment. W takim wypadku, aby oszczędzać wydajniej jest używać klasy StringBuilder lub synchronizowanej wersji tej klasy o nazwie StringBuffer. Oto przykład jak można efektywnie dodawać kolejne fragmenty tekstu do siebie w pętli.
String immutableString = "Sample text."; StringBuilder builder = new StringBuilder(immutableString); for (int i =0; i <10; i++) { builder.append("\nLoop counter: " + i); } System.out.println(builder.toString());
Analogicznie możesz tak samo używać klasy StringBuffer. Jest to synchronizowana wersja StringBuildera przeznaczona do pracy w środowisku wielowątkowym.
*Wyrażenie regularne(regex) – jest to specjalny zapis w informatyce, który używając pewnych symboli, pozwala komputerowi wyszukać tekst zgodny z podanym wzorcem (więcej poszukaj na tej stronie: https://regexr.com).
Link do lekcji: https://github.com/developeronthego/java-basics/tree/main/src/main/java/basics/lesson8
Jeśli chcesz dowiedzieć się czegoś więcej o klasach immutable: Java zaawansowane #12: obiekty niezmienne (immutable)