Lekce 11 - Pole v Javě
V předešlém cvičení, Řešené úlohy k 9.-10. lekci Javy, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
V dnešním Java tutoriálu si představíme datovou strukturu pole a vyzkoušíme si, co všechno umí.
Pole
Představme si, že si chceme uložit nějaké údaje o více prvcích.
Například chceme v paměti uchovávat 10 čísel, políčka šachovnice nebo
jména padesáti uživatelů. Asi nám dojde, že v programování bude nějaká
lepší cesta než začít bušit proměnné uzivatel1
,
uzivatel2
až např. uzivatel50
. Nehledě na to, že
jich může být třeba 1000! Jak by se pak navíc v takovém systému hledalo?
Brrr, takto ne
Potřebujeme-li uchovávat větší množství proměnných stejného
typu, tento problém nám řeší pole. Můžeme si ho
představit jako řadu přihrádek, kdy v každé máme uložený jeden prvek.
Přihrádky jsou očíslované tzv. indexy, přičemž první
přihrádka má index 0
:
(Na obrázku je vidět pole osmi čísel.)
Programovací jazyky se velmi liší v tom, jak s polem pracují. V některých jazycích (zejména starších, kompilovaných) nebylo možné za běhu programu vytvořit pole s dynamickou velikostí (např. mu dát velikost dle nějaké proměnné). Pole se muselo deklarovat s konstantní velikostí přímo ve zdrojovém kódu. Toto se obcházelo tzv. pointery a vlastními datovými strukturami, což často vedlo k chybám při manuální správě paměti a k nestabilitě programu (např. v C++). Naopak některé interpretované jazyky umožňují nejen deklarovat pole s libovolnou velikostí, ale dokonce tuto velikost na již existujícím poli měnit (např. PHP). My víme, že Java je virtuální stroj, tedy cosi mezi kompilerem a interpretem. Proto můžeme pole založit s velikostí, kterou dynamicky zadáme až za běhu programu, ale velikost existujícího pole již modifikovat nemůžeme. Toto lze samozřejmě obejít nebo použít jiné datové struktury, ale k tomu se dostaneme.
Výhody pole
Možná vás napadá, proč se tu polem zabýváme, když má evidentně mnoho omezení a existují lepší datové struktury. Odpověď je prostá: pole je totiž jednoduché. Nemyslíme tím pouze pro nás na pochopení, ale zejména pro samotnou Javu. S polem se rychle pracuje, protože prvky jsou v paměti jednoduše uloženy za sebou, všechny prvky zabírají stejně místa a rychle se k nim přistupuje. Mnoho vnitřních funkčností v Javě proto nějak s polem pracuje nebo pole vrací. Jedná se tedy o klíčovou strukturu.
Pro hromadnou manipulaci s prvky pole se používají cykly.
Práce s polem
V několika dalších krocích si pole deklarujeme, následně ho založíme a na závěr naplníme vlastními daty.
Deklarace pole
Pole deklarujeme pomocí hranatých závorek:
int[] cisla;
Na české klávesnici jsou hranaté závorky ukryté pod Pravým Alt společně s klávesami F a G:
Slovo cisla
je samozřejmě název naší proměnné. Nyní jsme
však pouze deklarovali, že v proměnné bude pole prvků typu
int
. Nyní musíme pole založit, abychom ho mohli používat. Pole
pojmenováváme vždy množným číslem podle toho, co pole
obsahuje.
Založení pole
K založení použijeme klíčové slovo new
, které zatím
nebudeme vysvětlovat. Spokojíme se s informací, že je to kvůli tomu, že je
pole referenční datový typ (můžeme chápat jako složitější typ):
int[] cisla = new int[10];
Nyní máme v proměnné cisla
pole o velikosti deseti čísel
typu int
.
Přístup k prvkům pole
K prvkům pole potom přistupujeme přes hranatou závorku. Pojďme na první
index (tedy index 0
) uložit číslo 1
:
int[] cisla = new int[10]; cisla[0] = 1;
Naplnění pole cyklem
Plnit pole ručně daty by bylo příliš pracné, proto použijeme
cyklus a naplníme si pole čísly od 1
do
10
. K naplnění použijeme cyklus for
:
int[] cisla = new int[10]; for (int i = 0; i < 10; i++) { cisla[i] = i + 1; }
Abychom pole vypsali, můžeme za předchozí kód připsat:
{JAVA_CONSOLE}
int[] cisla = new int[10];
for (int i = 0; i < 10; i++) {
cisla[i] = i + 1;
}
for (int i = 0; i < cisla.length; i++) {
System.out.print(cisla[i] + " ");
}
{/JAVA_CONSOLE}
Všimněme si, že pole má konstantu length
, kde
je uložena jeho délka, tedy počet prvků.
Výstup programu:
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
Cyklus foreach
Můžeme použít zjednodušenou verzi cyklu pro práci s kolekcemi, známou jako tzv. foreach. Ten projede všechny prvky v poli a jeho délku si zjistí sám. Syntaxe cyklu je následující:
for (datovytyp promenna : kolekce) { // příkazy }
Cyklus projede prvky v kolekci (to je obecný název pro struktury, které obsahují více prvků, u nás to bude pole) postupně od prvního do posledního. Prvek máme v každé iteraci cyklu uložený v dané proměnné.
Přepišme tedy náš dosavadní program pro cyklus foreach. Cyklus foreach nemá řídicí proměnnou, není tedy vhodný pro vytvoření našeho pole a použijeme ho jen pro výpis:
{JAVA_CONSOLE}
int[] cisla = new int[10];
for (int i = 0; i < 10; i++) {
cisla[i] = i + 1;
}
for (int cislo : cisla) {
System.out.print(cislo + " ");
}
{/JAVA_CONSOLE}
Výstup programu:
Konzolová aplikace
1 2 3 4 5 6 7 8 9 10
Naplnění pole ručně
Pole samozřejmě můžeme naplnit i ručně, a to i bez toho, abychom dosazovali postupně do každého indexu. Použijeme k tomu složené závorky a prvky oddělujeme čárkou:
String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Pole často slouží k ukládání mezivýsledků, které se potom dále v programu používají. Když potřebujeme nějaký výsledek 10x, tak ho nebudeme 10x počítat, ale spočítáme ho jednou a uložíme ho do pole, odkud poté výsledek jen načteme.
Metody na třídě Arrays
Java nám poskytuje třídu Arrays
, která obsahuje pomocné
metody pro práci s poli.
K jejímu použití je třeba ji naimportovat:
import java.util.Arrays;
Pojďme se na metody podívat:
Metoda sort()
Jak již název napovídá, metoda sort()
nám pole seřadí.
Její jediný parametr je pole, které chceme seřadit. Metoda je dokonce tak
chytrá, že pracuje podle toho, co máme v poli uložené. Řetězce třídí
podle abecedy, čísla podle velikosti. Zkusme si seřadit a vypsat naši
rodinku Simpsonů:
package onlineapp;
import java.util.Arrays;
public class Program {
public static void main(String[] args) {
String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Arrays.sort(simpsonovi);
for (String simpson : simpsonovi) {
System.out.print(simpson + " ");
}
}
}
Výstup programu:
Konzolová aplikace
Bart Homer Lisa Maggie Marge
Zkuste si vytvořit pole čísel a vyzkoušejte si, že metoda opravdu funguje i pro ně.
Metoda binarySearch()
Když pole seřadíme, umožní nám v něm Java vyhledávat prvky. Metoda
binarySearch()
nám vrátí index prvního nalezeného prvku. V
případě nenalezení prvku metoda vrátí záporné číslo, jehož přesná
hodnota závisí na pozici, kam by daný prvek v poli patřil. Metoda bere dva
parametry, prvním je pole, druhým hledaný prvek. Umožníme uživateli zadat
jméno Simpsona a poté zkontrolujeme, zda je to opravdu Simpson:
package onlineapp;
import java.util.Arrays;
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
System.out.println("Zadej Simpsona (z rodiny Simpsonů): ");
String simpson = scanner.nextLine();
Arrays.sort(simpsonovi);
int pozice = Arrays.binarySearch(simpsonovi, simpson);
if (pozice >= 0) {
System.out.println("Jo, to je Simpson!");
}
else {
System.out.println("Hele, tohle není Simpson!");
}
}
}
Pole musí být opravdu nejprve setříděné, než metodu zavoláme!
Výstup programu:
Konzolová aplikace
Zadej Simpsona (z rodiny Simpsonů):
Homer
Jo, to je Simpson!
Metoda copyOfRange()
Metoda copyOfRange()
již podle názvu zkopíruje část pole do
jiného pole. Prvním parametrem je zdrojové pole, druhým startovní pozice a
třetím konečná pozice. Metoda vrací nové pole, které je výsekem
původního pole.
Proměnná délka pole
Již jsme si říkali, že délku pole můžeme definovat i za běhu programu. Pojďme si to zkusit:
Scanner scanner = new Scanner(System.in); System.out.println("Ahoj, spočítám ti průměr známek. Kolik známek zadáš?"); int pocetZnamek = Integer.parseInt(scanner.nextLine()); int[] znamky = new int[pocetZnamek]; for (int i = 0; i < pocetZnamek; i++) { System.out.printf("Zadejte %d. číslo:%n", i + 1); znamky[i] = Integer.parseInt(scanner.nextLine()); } // spočítání průměru int soucet = 0; for (int znamka : znamky) { soucet += znamka; } double prumer = soucet / (double)znamky.length; System.out.printf("Průměr tvých známek je: %.1f", prumer);
Příkaz soucet += znamka
je pouze zkrácený
zápis pro soucet = soucet + znamka
.
Při výpisu jsme použili výraz %n
. Tento výraz
nám zajistí, že máme nový řádek nezávisle na platformě. Například na
platformě MacOS se výraz automaticky nahradí za znaky \r
.
Alternativně můžeme využít například znaky \n
, ale je
možné, že se na nějaké platformě nový řádek nevytvoří.
Výstup programu:
Konzolová aplikace
Ahoj, spočítám ti průměr známek. Kolik známek zadáš?
5
Zadejte 1. číslo: 1
Zadejte 2. číslo: 2
Zadejte 3. číslo: 2
Zadejte 4. číslo: 3
Zadejte 5. číslo: 5
Průměr tvých známek je: 2.6
Tento příklad by šel samozřejmě napsat i bez použití pole, ale co kdybychom chtěli spočítat např. medián? Nebo vypsat zadaná čísla pozpátku? To už by bez pole nešlo. Takto máme v poli k dispozici původní hodnoty a můžeme s nimi neomezeně a jednoduše pracovat.
U výpočtu průměru si všimněme, že při dělení je před jedním
operandem napsáno (double)
, čímž říkáme, že chceme dělit
neceločíselně. Při dělení 3 / 2
dostaneme výsledek
1
a při dělení 3 / 2.0F
dostaneme výsledek
1.5
. Druhé číslo musí být vždy reálné, aby Java dělila
taktéž reálně (na více desetinných míst).
To by pro dnešek stačilo, můžete si s polem hrát.
V následujícím kvízu, Kvíz - Podmínky, cykly a pole v Javě, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 1359x (71.07 kB)
Aplikace je včetně zdrojových kódů v jazyce Java