Lekce 4 - Typový systém podruhé: Datové typy
V předešlém cvičení, Řešené úlohy k 3. lekci Javy, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Nyní se na datové typy podíváme více zblízka a vysvětlíme si, kdy jaký použít. Dnešní lekce bude hodně teoretická, ale o to více bude praktická ta příští. Na konci si vytvoříme pár jednoduchých ukázek.
Java rozeznává dva druhy datových typů, primitivní a referenční.
Primitivní datové typy
Proměnné primitivního datového typu si dokážeme jednoduše představit. Může se jednat např. o číslo nebo znak. V paměti je jednoduše uložena přímo hodnota a my k této hodnotě můžeme z programu přímo přistupovat. Slovo přímo jsem tolikrát nepoužil jen náhodou. V této sekci tutoriálů se budeme věnovat výhradně těmto proměnným.
Celočíselné datové typy
Podívejme se nyní na tabulku všech vestavěných celočíselných
datových typů v Javě, všimněte si typu int
, který již známe
z minule.
Datový typ | Rozsah | Velikost |
---|---|---|
byte | -128 až 127 | 8 bitů |
short | -32 768 až 32 767 | 16 bitů |
int | -2 147 483 648 až 2 147 483 647 | 32 bitů |
long | -9 223 372 036 854 775 808 až 9 223 372 036 854 775 807 | 64 bitů |
Asi vás napadá otázka, proč máme tolik možných typů pro uložení
čísla. Odpověď je prostá, záleží na jeho velikosti. Čím větší
číslo, tím více spotřebuje paměti. Pro věk uživatele tedy zvolíme
byte
, protože se jistě nedožije více, než 127 let. Představte
si databázi milionu uživatelů nějakého systému, když zvolíme místo
byte
int
, bude zabírat 4x více místa. Naopak když
budeme mít funkci k výpočtu faktoriálu, stěží nám bude stačit rozsah
intu
a použijeme long
.
Nad výběrem datového typu nemusíte moc přemýšlet a většinou se
používá jednoduše int
. Typ řešte pouze v případě, když
jsou proměnné v nějakém poli (obecně kolekci) a je jich tedy více, potom
se vyplatí zabývat se paměťovými nároky. Tabulky sem dávám spíše pro
úplnost. Mezi typy samozřejmě funguje již zmíněná implicitní konverze,
tedy můžeme přímo přiřadit int
do proměnné typu
long
a podobně, aniž bychom něco konvertovali.
Desetinná čísla
U desetinných čísel je situace poněkud jednodušší, máme na výběr
pouze dva datové typy. Samozřejmě se liší opět v rozsahu hodnoty, dále
však ještě v přesnosti (vlastně počtu des. míst). Typ double
má již dle názvu dvojnásobnou přesnost oproti float
.
Datový typ | Rozsah | Přesnost |
---|---|---|
float | +-1.5 * 10−45 až +-3.4 * 1038 | 7 čísel |
double | +-5.0 * 10−324 až +-1.7 * 10308 | 15-16 čísel |
Pozor, vzhledem k tomu, že desetinná čísla jsou v počítači uložena ve dvojkové soustavě, dochází k určité ztrátě přesnosti. Odchylka je sice téměr zanedbatelná, nicméně když budete programovat např. finanční systém, nepoužívejte tyto dat. typy pro uchování peněz, mohlo by dojít k malým odchylkám.
Když do float
u chceme dosadit přímo ve zdrojovém kódu,
musíme použít sufix F
, u double sufix D
(u double
ho můžeme vypustit, jelikož je výchozí desetinný typ):
float f = 3.14F; double d = 2.72;
Jako desetinný separátor používáme ve zdrojovém kódu vždy tečku, nehledě na to, jaké máme v operačním systému regionální nastavení.
Další vestavěné datové typy
Podívejme se na další datové typy, které nám Java nabízí:
Datový typ | Rozsah | Velikost/Přesnost |
---|---|---|
char | U+0000 až U+ffff | 16 bitů |
boolean | true nebo false | 8 bitů |
Char
Typ char
nám reprezentuje jeden znak, na rozdíl od
String
, který reprezentoval celý řetězec charů. Znaky v Javě
píšeme do apostrofů:
char c = 'A';
Typ char
patří v podstatě do celočíselných proměnných
(obsahuje číselný kód znaku), ale přišlo mi logičtější uvést ho
zde.
BigDecimal
Typ BigDecimal
řeší problém ukládání desetinných čísel
v binární podobě, ukládá totiž číslo vnitřně jako pole. Používá se
tedy pro uchování peněžních hodnot. Nebudeme si zde ukazovat použití,
protože se používá jako objekt. Pokud budete dělat někdy finanční
výpočty, tak si na něj vzpomeňte.
Pozn.: V Javě jsou čísla tzv. odděděna od třídy
Number
. To je spíše informace do budoucna. Jelikož nyní
nevíme, co dědičnost znamená, důležitá pro nás není.
Number
obsahuje ještě čtyři podtřídy, kterými se nebudeme
podrobněji zabývat. BigDecimal
a BigInteger
slouží
k výpočtům s vysokou přesností. Třídy AtomicInteger
a
AtomicLong
se používají v aplikacích s více podprocesy. Opět
je důležité, abyste věděli, že něco takového existuje a případně se
sem později vrátili.
Boolean
Boolean
nabývá dvou hodnot: true
(pravda) a
false
(nepravda). Budeme ho používat zejména tehdy, až se
dostaneme k podmínkám. Do proměnné typu boolean
lze uložit jak
přímo hodnotu true
/false
, tak i logický výraz.
Zkusme si jednoduchý příklad:
{JAVA_CONSOLE}
boolean b = false;
boolean vyraz = (15 > 5);
System.out.println(b);
System.out.println(vyraz);
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
false
true
Výrazy píšeme do závorek. Vidíme, že výraz nabývá hodnoty
true
(pravda), protože 15
je opravdu větší než
5
. Od výrazů je to jen krok k podmínkám, na ně se podíváme
příště.
Referenční datové typy
K referenčním typům se dostaneme až u objektově orientovaného
programování, kde si také vysvětlíme zásadní rozdíly. Zatím budeme
pracovat jen s tak jednoduchými typy, že rozdíl nepoznáme. Spokojíme se s
tím, že referenční typy jsou složitější, než ty primitivní. Jeden
takový typ již známe, je jím String
. Možná vás napadá, že
String
nemá nijak omezenou délku, je to tím, že s
referenčními typy se v paměti pracuje jinak. Hodnotové typy začínají na
rozdíl od typů primitivních velkým písmenem.
String
má na sobě řadu opravdu užitečných metod. Některé
si teď probereme a vyzkoušíme:
String
startsWith()
, endsWith()
a
contains()
Můžeme se jednoduše zeptat, zda řetězec začíná, končí nebo zda
obsahuje určitý podřetězec (substring). Podřetězcem myslíme část
původního řetězce. Všechny tyto metody budou jako parametr brát
samozřejmě podřetězec a vracet hodnoty typu boolean
(true
/false
). Zatím na výstup neumíme reagovat, ale
pojďme si ho alespoň vypsat:
{JAVA_CONSOLE}
String s = "Krokonosohroch";
System.out.println(s.startsWith("krok"));
System.out.println(s.endsWith("hroch"));
System.out.println(s.contains("nos"));
System.out.println(s.contains("roh"));
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
false
true
true
false
Vidíme, že vše funguje podle očekávání. První výraz samozřejmě neprošel díky tomu, že řetězec ve skutečnosti začíná velkým písmenem.
isEmpty()
Někdy se nám hodí vědět, zda je řetězec prázdný. To znamená, že
jeho délka je 0
a neobsahuje žádný znak, ani např. mezeru.
Takový řetězec můžeme získat např. tak, že uživatel nic nezadá do
nějakého vstupu. Metoda isEmpty()
nám vrátí true
pokud je řetězec prázdný a false
pokud není:
{JAVA_CONSOLE}
String s1 = " ";
String s2 = "";
String s3 = "slovo";
System.out.println(s1.isEmpty());
System.out.println(s2.isEmpty());
System.out.println(s3.isEmpty());
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
false
true
false
toUpperCase()
a toLowerCase()
Rozlišování velkých a malých písmen může být někdy na obtíž.
Mnohdy se budeme potřebovat zeptat na přítomnost podřetězce tak, aby
nezáleželo na velikosti písmen. Situaci můžeme vyřešit pomocí metod
toUpperCase()
a toLowerCase()
, které vrací řetězec
ve velkých a v malých písmenech. Uveďme si reálnější příklad než je
Krokonosohroch. Budeme mít v proměnné řádek konfiguračního souboru,
který psal uživatel. Jelikož se na vstupy od uživatelů nelze spolehnout,
musíme se snažit eliminovat možné chyby, zde např. s velkými písmeny.
{JAVA_CONSOLE}
String konfig = "Fullscreen shaDows autosave";
konfig = konfig.toLowerCase();
System.out.println("Poběží hra ve fullscreenu?");
System.out.println(konfig.contains("fullscreen"));
System.out.println("Budou zapnuté stíny?");
System.out.println(konfig.contains("shadows"));
System.out.println("Přeje si hráč vypnout zvuk?");
System.out.println(konfig.contains("nosound"));
System.out.println("Přeje si hráč hru automaticky ukládat?");
System.out.println(konfig.contains("autosave"));
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
Poběží hra ve fullscreenu?
true
Budou zapnuté stíny?
true
Přeje si hráč vypnout zvuk?
false
Přeje si hráč hru automaticky ukládat?
true
Vidíme, že jsme schopni zjistit přítomnost jednotlivých slov v řetězci tak, že si nejprve řetězec převedeme celý na malá písmena (nebo na velká) a potom kontrolujeme přítomnost slova jen malými (nebo velkými) písmeny. Takhle by mimochodem mohlo opravdu vypadat jednoduché zpracování nějakého konfiguračního skriptu.
trim()
Další nástrahou mohou být mezery a obecně všechny tzv. bílé znaky,
které nejsou vidět, ale mohou nám uškodit. Obecně může být dobré
trimovat všechny vstupy od uživatele. Zkuste si v následující aplikaci
před číslo a za číslo zadat několik mezer, trim()
je
odstraní. Odstraňují se vždy bílé znaky kolem řetězce, nikoli
uvnitř:
{JAVA_CONSOLE}
System.out.println("Zadejte číslo:");
String s = sc.nextLine();
System.out.println("Zadal jste text: " + s);
System.out.println("Text po funkci trim: " + s.trim());
int a = Integer.parseInt(s.trim());
System.out.println("Převedl jsem zadaný text na číslo parsováním, zadal jste: " + a);
{/JAVA_CONSOLE}
replace()
Asi nejdůležitější metodou na String
u je nahrazení
určité jeho části jiným textem. Jako parametry zadáme dva podřetězce,
jeden co chceme nahrazovat a druhý ten, kterým to chceme nahradit. Metoda
vrátí nový String
, ve kterém proběhlo nahrazení. Když daný
podřetězec metoda nenajde, vrátí původní řetězec. Zkusme si to:
{JAVA_CONSOLE}
String s = "C# je nejlepší!";
s = s.replace("C#", "Java");
System.out.println(s);
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
Java je nejlepší!
format()
format()
je velmi užitečná metoda, která nám umožňuje
vkládat do samotného textového řetězce zástupné značky. Ty jsou
reprezentovány jako procento a zkratka datového typu. Metoda se volá na typu
String
, prvním parametrem je textový řetězec se značkami,
další dále následují proměnné v tom pořadí, v kterém se mají do textu
místo značek vložit. Všimněte si, že se metoda nevolá na konkrétní
proměnné (přesněji instanci, viz další díly), ale přímo na typu
String
.
{JAVA_CONSOLE}
int a = 10;
int b = 20;
int c = a + b;
String s = String.format("Když sečteme %d a %d, dostaneme %d", a, b, c);
System.out.println(s);
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
Když sečteme 10 a 20, dostaneme 30
Značky jsou:
%d
pro celá čísla%s
proString
%f
profloat
. Ufloat
můžeme definovat délku desetinné části, např:%.2f
pro dvě desetinná místa.
Konzole sama umí přijímat text v takovémto formátu, jen musíme místo
println()
volat printf()
. Můžeme tedy napsat:
{JAVA_CONSOLE}
int a = 10;
int b = 20;
int c = a + b;
System.out.printf("Když sečteme %d a %d, dostaneme %d", a, b, c);
{/JAVA_CONSOLE}
Toto je velmi užitečná a přehledná cesta, jak sestavovat řetězce, i
přesto se však v Javě řetězce spojují spíše pomocí operátoru
+
.
length()
Poslední, ale nejdůležitější je length()
, tedy délka.
Vrací celé číslo, které představuje počet znaků v řetězci.
{JAVA_CONSOLE}
System.out.println("Zadejte vaše jméno:");
String jmeno = sc.nextLine();
System.out.printf("Délka vašeho jména je: %d", jmeno.length());
{/JAVA_CONSOLE}
Je toho ještě spoustu k vysvětlování a jsou další datové typy, které jsme neprobrali.
V následujícím cvičení, Řešené úlohy k 4. lekci Javy, si procvičíme nabyté zkušenosti z předchozích lekcí.
Komentáře


Zobrazeno 10 zpráv z 162. Zobrazit vše