17 KiB
17 KiB
Řetězce a práce s nimi
- Třída
String
- Jedna z nejpoužívanějších tříd z Java Core API
- Řetězcové konstanty (literály – texty uzavřené do uvozovek, např. "Ahoj") používáme od začátku předmětu KIV/PPA1
Specifické vlastnosti třídy String
String
je třída, jednotlivé řetězce (tj. texty) jsou její instance uložené na haldě (na heapu)- Z praktických důvodů má však některé vlastnosti, které u jiných tříd nejsou
Vytvoření řetězce bez operátoru new
- Jak bylo vidět ve všech příkladech, které dosud vypisovaly text, instance třídy
String
může vzniknout i bez operátorunew
- Vznikne zápisem literálu (nepojmenované konstanty)
- Např.
String pozdrav = "Ahoj!";
- Např.
System.out.println("Nazdar!");
- Např.
- Tento postup jsme používali dosud (aniž jsme věděli o tom, že vznikají instance třídy
String
) - Tento postup se používá běžně
- Vznikne zápisem literálu (nepojmenované konstanty)
- Je možné i přímo vytvořit novou instanci třídy String operátorem
new
- Třída
String
obsahuje několik konstruktorů umožňující vytvořit řetězec z pole znaků, pole bytů, atd. - Je možné i vytvořit nový řetězec z jiného řetězce
- Např.
String pozdrav = new String("Ahoj!");
- Tento zápis NEPOUŽÍVAT
- Protože samotný zápis literálu "
Ahoj
" způsobí vytvoření nové instance třídyString
, volání newString()
zbytečně vytvoří další instanci
- Např.
- Třída
Konstantnost řetězce
- Řetězce v Javě (tj. instance třídy
String
) jsou konstantní, neměnné (immutable)- Nelze do nich přidávat text, mazat, nebo měnit jednotlivé znaky
- Veškeré metody zdánlivě upravující řetězec ve skutečnosti vytvoří novou instanci třídy
String
a text v původní instanci zůstane nedotčen
- Existují třídy pro práci s měnitelným řetězcem
- Třída StringBuilder
- Třída StringBuffer
- Přesto si ve většině případů vystačíme s třídou
String
- To, že při změně obsahu řetězce dojde k vytvoření nové instance a původní zůstane nezměněná, nám nevadí (v podstatě si toho nevšimneme)
Spojení řetězců pomocí operátoru „+“ (zřetězení)
- Od začátku jsme běžně používali
- Především v metodě
System.out.println()
- Především v metodě
- Operátor „+“ spojí dva řetězce (operandy) a vytvoří novou instanci obsahující texty obou řetězců (operandů)
- Operátor „+“ také umožňuje připojit k řetězci libovolný datový typ
- Hodnota daného typu se převede na řetězec
- Alespoň jeden operand musí být řetězec, pokud ne, má operátor „+“ význam sčítání
- Pro přehlednost je lepší začínat řetězcem, pokud nechceme začínat uvozujícím textem, lze použít prázdný řetězec
- Časté je použití přímo v metodě
System.out.println()
Práce s řetězci
- Metody pro práci s řetězci jsou převážně metody instance třídy String
- Proto se volají nad referenční proměnnou ukazující na instanci řetězce
referenčníProměnná.názevMetody(parametry);
- Např.
pozdrav.charAt(0);
- Stejné jako u jiných objektů
- Protože instance řetězce vznikne pouhým zapsáním literálu, lze nad ním rovnou volat metody bez nutnosti použití referenční proměnné
- Např.
"Ahoj".charAt(0); //Funkcni ale nepouzivat
- NEPOUŽÍVAT!
- Např.
Práce s jednotlivými znaky a délka řetězce
- Řetězec si lze představit jako speciální konstantní pole znaků
- Ale jedná se o instanci třídy, nelze s ní pracovat jako s polem – tj. přistupovat k jednotlivým znakům pomocí hranatých závorek „[“ a „]“
- Pole znaků (tj.
char[]
) je uvnitř řetězce skutečně obsaženo
- Pro následující příklady předpokládejte deklaraci
String pozdrav = "Nazdar";
- Délka řetězce
- Metoda
length()
- POZOR! – Je to metoda, nikoliv proměnná, jako u polí (tj. musí se uvést závorky)
- Vrací počet znaků řetězce (včetně bílých znaků)
int delka = pozdrav.length(); //delka bude 6
- Metoda
- Znak na zadané pozici
- Metoda
charAt(indexZnaku)
- Znaky mají index podobně jako prvky pole číslované od 0 do délka řetězce - 1
char znak = pozdrav.charAt(0); //znak bude 'N'
- Metoda
- Index prvního výskytu znaku/podřetězce
- Metoda
indexOf(znak/podřetězec)
- Vrátí index prvního výskytu znaku (podřetězce) v řetězci, nebo -1, pokud znak (podřetězec) není nalezen
int index1 = pozdrav.indexOf('a'); //index1 bude 1
int index2 = pozdrav.indexOf("zd"); //index2 bude 2
int index3 = pozdrav.indexOf("j"); //index3 bude -1
- Metoda
- Index posledního výskytu znaku/podřetězce
- Metoda
lastIndexOf
(znak/podřetězec
) - Vrátí index posledního výskytu znaku (podřetězce) v řetězci, nebo -1, pokud znak (podřetězec) není nalezen
int li1 = pozdrav.lastIndexOf('a'); //li1 bude 4
int li2 = pozdrav.lastIndexOf("Na "); //li2 bude 0
- Metoda
- Náhrada všech výskytů znaku v řetězci
- Metoda
replace(puvodníZnak, novýZnak)
String s2 = pozdrav.replace('a', 'e'); //"Nezder"
- Metoda
Porovnání řetězců
- Řetězce jsou instance třídy
String
- Porovnání pomocí operátoru „
==
“, pouze zjistí, zda se jedná o stejné instance nepoužívat - Porovnání podle obsahů (důsledně včetně velikosti písmen) – shodné/rozdílné
- Metoda
equals
(jinýŘetězec
) - Výsledek
true
(řetězce jsou shodné) nebofalse
(řetězce jsou rozdílné)
- Metoda
- Porovnání podle obsahů bez ohledu na velikost písmen – shodné/rozdílné
- Metoda
equalsIgnoreCase
(jinýŘetězec
) - Výsledek
true
(řetězce jsou shodné bez ohledu na velikost písmen) nebofalse
(řetězce jsou rozdílné bez ohledu na velikost písmen)
- Metoda
- Porovnání podle obsahů (důsledně včetně velikosti písmen) – větší/menší/stejný
- Metoda
compareTo
(jinýŘetězec
) - Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je dále od začátku abecedy)
- Výsledek 0 (řetězce jsou shodné), nebo záporné číslo (první řetězec je „menší“ než druhý – tj. je blíže začátku abecedy), nebo kladné číslo (první řetězec je „větší“ než druhý – tj. je blíže konci abecedy)
- Metoda
- POZOR! – Návratové hodnoty metod
compareTo…()
- Vrácené záporné a kladné číslo (když řetězce nejsou shodné) nemusí být (a není) jen -1 nebo 1
- Návratovou hodnotu metody je třeba porovnávat pomocí operátorů „>“ a „<“, nikoliv porovnáním operátorem „==“ s -1 či 1
- Test začátku a konce řetězce
- Výsledek
true
, pokud řetězec začíná/končí zadaným podřetězcem, jinak vracífalse
- Metoda
startsWith(prefix)
- Metoda
endsWith(postFix)
- Metoda
startsWithIgnoreCase(prefix)
- Metoda
endsWithIgnoreCase(postFix)
- Výsledek
Získání podřetězce z řetězce
- Stále předpokládáme deklaraci
String pozdrav = "Nazdar";
- Získání podřetězce od zadaného indexu (včetně) do konce
- Metoda
substring(indexOd)
String p1 = pozdrav.substring(2); //p1 bude "zdar"
- Metoda
- Získání podřetězce od zadaného indexu (včetně) do zadaného indexu (vyjma)
- Metoda
substring(indexOd, indexDo)
String p2 = pozdrav.substring(0, 2); //p2 bude "Na"
- Metoda
- Odstranění bílých znaků ze začátku a konce řetězce
- Metoda
trim()
- Uvažujme deklaraci
String bz = "\r\n \tahoj \t\n\r";
String oriznuty = bz.trim(); //oriznuty bude "ahoj"
- Metoda
Konverze řetězce na jiné datové typy a obráceně
- Relativně časté operace
- Převod řetězce na číselný datový typ
- Typicky při vstupu (když nepoužíváme Scanner, nebo je vstup komplikovanější, nebo v GUI)
- Číselný datový typ je potřeba, abychom mohli provádět aritmetické operace
Např. "1" + "2" je řetězec "12", ale 1 + 2 je 3
- Převod čísla na řetězec
- Implicitně se provádí při každém výstupu
- Explicitně, když chceme využít operace nad řetězci např. pro čísla (např. zjištění počtu znaků (tj. číslic), zřetězení s řetězcem)
- Převod instance (objektu) na řetězec
- Pokud chceme instanci vypsat
- Převod řetězce na číselný datový typ
Konverze řetězce na jiné datové typy
- Pro základní datové typy se používá metoda
Typ.parseTyp(řetězec)
z příslušné obalovací třídy základního datového typu- Jedná se o metody třídy, volá se s názvem třídy, není potřeba vytvářet instanci
- Např.
int i = Integer.parseInt("42");
- Např.
long l = Long.parseLong("2444111333");
- Např.
double d = Double.parseDouble("5.972E24");
- Např.
boolean b = Boolean.parseBoolean("false");
- Např.
- Pro objekty
- Není žádný standardní a obecný postup pro převod řetězce na instanci jiné třídy
- Jedná se o metody třídy, volá se s názvem třídy, není potřeba vytvářet instanci
Konverze jiných datových typů na řetězec
- Běžně se využívá schopnost operátoru zřetězení „+“ převádět jiné datové typy (základní datové typy a instance tříd) na řetězec
- Pro základní datové typy funguje přímočaře
- Pro objekty také – objekt se převede na řetězec implicitním voláním metody
toString()
- Pokud je metoda
toString()
překryta, funguje dobře
- Pokud je metoda
- Pro pole je potřeba použít metodu třídy
Arrays.toString(pole)
- Pokud se použije pouze operátor „+“, použije se implicitní textová reprezentace pole (např.
[I@15db9742
)
- Pokud se použije pouze operátor „+“, použije se implicitní textová reprezentace pole (např.
- Pro základní datové typy existuje další možnost – metoda
Typ.toString (hodnota)
z příslušné obalovací třídy základního datového typu- Např.
String s = Integer.toString(42); //s bude "42"
- Např.
- Pro základní datové typy a pro instance tříd existuje další možnost – metoda třídy
valueOf(hodnota)
třídyString
- Metoda je překrytá pro všechny základní datové typy a objekty
- Např.
String s = String.valueOf(42) //s bude "42"
Rozdělení řetězce na podřetězce
- Často je potřeba rozdělit řetězec na několik podřetězců podle oddělovače (mezer, bílých znaků, čárek, teček, pomlček či jiné interpunkce či jiného znaku)
- Metoda instance
split(regulárníVýraz)
ve tříděString
- Metoda má jako parametr regulární výraz
- Regulární výraz
- Řetězec popisující celou množinu řetězců => mnohé znaky tak mají speciální význam
- Parametrem tedy není jen znak, podle kterého se má řetězec rozdělit
- Některé znaky (např. mezera) nemají speciální význam a lze je tak použít bez problémů (tj.
split(" ")
) - Některé znaky mají speciální význam a je třeba použít tzv. „escape“ sekvenci
- Zpětné lomítko „\“ před znak, který chceme použít => zruší se tím speciální význam znaku
- Protože však zpětné lomítko má speciální význam i v řetězcových a znakových literálech (umožňuje napsat speciální znaky, např. konec řádky „\n“), je třeba napsat zpětná lomítka
- Regulární výraz
- Metoda vrací pole řetězců, délka pole záleží na počtu podřetězců dvě „\“
- Metoda instance
Proměnný řetězec
- V některých případech (ač jich není mnoho) opravdu potřebujeme, aby se při každé změně textu řetězce nevytvářela nová instance => je potřeba měnitelný (mutable) řetězec
- Pokud provádíme v řetězci mnoho změn a použili bychom třídu
String
, vytvářelo by se mnoho instancí – pro každou změnu se vytvoří nová, což zbytečně zabírá paměť a zpomaluje program (vytvoření instance nějakou dobu trvá) - Pokud by šel řetězec měnit, vystačíme si s jednou instancí
- Pokud provádíme v řetězci mnoho změn a použili bychom třídu
Třída StringBuilder
- Proměnný/měnitelný řetězec (sekvence znaků)
- Vytvoření instance třídy
StringBuilder
- Lze zadat řetězec, nebo kapacitu
- Kapacita se udává kvůli efektivitě – pokud je dostatečná, nemusí se během práce s řetězcem (při jeho prodloužení) kapacita navyšovat
- Je však možné do instance třídy
StringBuilder
vložit/přidat řetězec nebo jiný datový typ (viz níže) a překročit aktuální kapacitu kapacita se automaticky navýší
- Např.
StringBuilder sb1 = new StringBuilder("Ahoj");
- Např.
StringBuilder sb2 = new StringBuilder(100);
- Lze zadat řetězec, nebo kapacitu
- Práce se znaky
- Zjištění konkrétního znaku
- Metoda
charAt(index)
- Vrátí znak na zadaném indexu
- Např.
int i = sb1.charAt(3); //'o'
- Metoda
- Nastavení konkrétného znaku
- Metoda
setCharAt(index, znak)
- Nastaví znak na zadaném indexu na zadaný znak
- Např.
sb1.setCharAt(0, 'E'); //"Ehoj"
- Metoda
- Zjištění konkrétního znaku
- Délka řetězce
- Zjištění délky uloženého řetězce
- Metoda
getLength()
- Vrátí délku řetězce
- Např.
int d1 = sb1.getLength(); //4
- Např.
int d2 = sb2.getLength(); //0
- Metoda
- Zjištění délky uloženého řetězce
- Nastavení délky řetězce
- Metoda
setLength(délka)
- Nastaví délku řetězce
- Pokud se řetězec prodlužuje, přidané znaky budou mít hodnotu 0
- Pokud se řetězec zkracuje, znaky nad zadanou délku se oříznou
- Např.
sb2.setLength(10); //10 znaků hodnoty 0
- Např.
sb2.setLength(0); //Prazdny retezec
- Metoda
- Převrácení řetězce
- Metoda
reverse()
- Převrátí pořadí znaků
- Např.
sb1.reverse(); //"johE"
- Metoda
- Přidání/vložení libovolného datového typu
- Přidání libovolného datového typu
- Metoda
append(hodnota)
- Metoda překryta pro všechny základní datové typy,
Object
,String
aStringBuilder
- Např.
sb2.append(true); //"true"
- Např.
sb1.append(sb2); //"johEtrue"
- Metoda
- Vložení libovolného datového typu
- Metoda
insert(index, hodnota)
- Metoda překryta pro všechny základní datové typy,
Object
aString
- Znaky na pozici
index
a dále se odsunou o počet vložených znaků - Např.
sb1.insert(3, 42); //"joh42Etrue"
- Metoda
- Smazání podřetězce či znaku
- Smazání podřetězce
- Metoda
delete(začátek, konec);
- Smaže podřetězec začínající na pozici začátek a končící před pozicí
konec
- Např.
sb1.delete(2, 5); //"joEtrue"
- Metoda
- Smazání znaku
- Metoda
deleteCharAt(index)
- Smaže znak na zadaném indexu
- Např.
sb1.deleteCharAt(2); //"jotrue"
- Metoda
- Smazání podřetězce
- Přidání libovolného datového typu
Třída StringBuffer
- Proměnný/měnitelný řetězec (sekvence znaků), která má téměř stejné metody a téměř stejné použití jako třída
StringBuilder
- Starší a pomalejší
- Vhodný, pokud má s proměnným řetězcem pracovat více vláken (viz předmět KIV/PGS)
Třída Character
- Obalovací třída pro základní datový typ
char
- Obsahuje mnoho konstant důležitých pro práci s různými speciálními znaky (např. z jiných abeced než latinky)
- Obsahuje mj. metody pro určení typu znaku
Určení typu znaku
- Metody pro určení typu znaku třídy
Character
- Jedná se o metody třídy, volají se nad názvem třídy, vrací
true
, pokud znak je daného typu (podle názvu metody), jinak vracífalse
- Metody pracují správně i pro speciální znaky (které např. nejsou z latinky)
- Metoda
isDigit(znak)
- Zjistí, jestli je zadaný znak číslice
- Např.
Character.isDigit('3'); //true
- Např.
Characet.isDigit('A'); //false
- Metoda
isLetter(znak)
- Zjistí, jestli je zadaný znak písmeno
- Např.
Character.isLetter('3'); //false
- Např.
Character.isLetter('A'); //true
- Metoda
isLetterOrDigit(znak)
- Zjistí, jestli je zadaný znak písmeno nebo číslice
- Např.
Character.isLetterOrDigit('3'); //true
- Např.
Character.isLetterOrDigit('A'); //true
- Metoda
isWhitespace(znak)
- Zjistí, jestli je zadaný znak bílý znak
- POZOR! – druhé „
s
“ v názvu metody je také malé - Např.
Character.isWhitespace(' '); //true
- Např.
Character.isWhitespace('\n'); //true
- Metoda
isLowerCase(znak)
- Zjistí, jestli je zadaný znak malé písmeno
- Např.
Character.isLowerCase('a'); //true
- Např.
Character.isLowerCase('A'); //false
- Např.
Character.isLowerCase('3'); //false
- Metoda
isUpperCase(znak)
- Zjistí, jestli je zadaný znak velké písmeno
- Např.
Character.isUpperCase('a'); //false
- Např.
Character.isUpperCase('A'); //true
- Např.
Character.isUpperCase('3'); //false
- Jedná se o metody třídy, volají se nad názvem třídy, vrací