Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Pouze tento týden sleva až 80 % na e-learning týkající se Swiftu. Zároveň využij výhodnou slevovou akci až 30 % zdarma při nákupu e-learningu - více informací.
swift week + discount 30

Lekce 7 - Pole v Javě

V předešlém cvičení, Řešené úlohy k 6. lekci Javy, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

Dnes si v tutoriálu představíme datovou strukturu pole a vyzkoušíme si, co všechno umí.

Pole

Představte si, že si chcete uložit nějaké údaje o více prvcích. Např. chcete v paměti uchovávat 10 čísel, políčka šachovnice nebo jména 50ti uživatelů. Asi vám dojde, že v programování bude nějaká lepší cesta, než začít bušit proměnné uzivatel1, uzivatel2, ... až uzivatel50. Nehledě na to, že jich může být třeba 1000. A jak by se v tom potom hledalo? Brrr, takhle ne :)

Pokud potřebujeme 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, kde v každé máme uložený jeden prvek. Přihrádky jsou očíslované tzv. indexy, první má index 0.

Struktura pole

(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 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 modifikovat nemůžeme. Lze to samozřejmě obejít nebo použít jiné datové struktury, ale k tomu se dostaneme.

Možná vás napadá, proč se tu zabýváme s polem, když má evidentně mnoho omezení a existují lepší datové struktury. Odpověď je prostá: pole je totiž jednoduché. Nemyslím pro nás na pochopení (to také), ale zejména pro Javu. Rychle se s ním pracuje, protože prvky jsou v paměti jednoduše uloženy za sebou, zabírají všechny stejně místa a rychle se k nim přistupuje. Mnoho vnitřních funkčností v Javě proto nějak pracuje s polem nebo pole vrací. Je to klíčová struktura.

Pro hromadnou manipulaci s prvky pole se používají cykly.

Pole deklarujeme pomocí hranatých závorek:

int[] pole;

Slovo pole je samozřejmě název naší proměnné. Nyní jsme však pouze deklarovali, že v proměnné bude pole prvků typu int. Nyní ho musíme založit, abychom ho mohli používat. Použijeme k tomu klíčové slovo new, které zatím nebudeme vysvětlovat. Spokojme se s tím, že je to kvůli tomu, že je pole referenční datový typ (můžeme chápat jako složitější typ):

int[] pole = new int[10];

Nyní máme v proměnné pole pole o velikosti deseti čísel typu int.

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[] pole = new int[10];
pole[0] = 1;
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Plnit pole takhle ručně by bylo příliš pracné, použijeme cyklus a naplníme si pole čísly od 1 do 10. K naplnění použijeme for cyklus:

int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++) {
    pole[i] = i + 1;
}

Abychom pole vypsali, můžeme za předchozí kód připsat:

for (int i = 0; i < pole.length; i++) {
    System.out.print(pole[i] + " ");
}

Všimněte si, že pole má konstantu length, kde je uložena jeho délka, tedy počet prvků.

Konzolová aplikace
1 2 3 4 5 6 7 8 9 10

Můžeme použít zjednodušenou verzi cyklu pro práci s kolekcemi, známou jako foreach. Ten projede všechny prvky v poli a jeho délku si zjistí sám. Jeho syntaxe 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 foreach. Foreach nemá řídící proměnnou, není tedy vhodný pro vytvoření našeho pole a použijeme ho jen pro výpis.

int[] pole = new int[10];
pole[0] = 1;
for (int i = 0; i < 10; i++) {
    pole[i] = i + 1;
}
for (int i : pole) {
    System.out.print(i + " ");
}

Výstup programu:

Konzolová aplikace
1 2 3 4 5 6 7 8 9 10

Pole samozřejmě můžeme naplnit ručně a to i bez toho, abychom dosazovali postupně do každého indexu. Použijeme k tomu složených závorek 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ž něco potřebujeme 10x, tak to nebudeme 10x počítat, ale spočítáme to jednou a uložíme do pole, odtud 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 ně podívat:

sort()

Jak již název napovídá, metoda nám pole seřadí. Její jediný parametr je pole, které chceme seřadit. Je dokonce tak chytrá, že pracuje podle toho, co máme v poli uložené. Stringy třídí podle abecedy, čísla podle velikosti. Zkusme si seřadit a vypsat naši rodinku Simpsnů:

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
Arrays.sort(simpsonovi);
for (String s : simpsonovi) {
    System.out.print(s + " ");
}

Konzolová aplikace
Bart Homer Lisa Maggie Marge

Zkuste si udělat pole čísel a vyzkoušejte si, že to opravdu funguje i pro ně.

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 vrátí -1. Metoda bere dva parametry, prvním je pole, druhým hledaný prvek. Umožníme uživateli zadat jméno Simpsna a poté zkontrolujeme, zda je to opravdu Simpson. Pole musí být opravdu setříděné, než metodu zavoláme!

Scanner sc = new Scanner(System.in, "Windows-1250");

String[] simpsonovi = {"Homer", "Marge", "Bart", "Lisa", "Maggie"};
System.out.println("Zadej Simpsna (z rodiny Simpsnů): ");
String simpson = sc.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!");

Konzolová aplikace
Zadej Simpsna (z rodiny Simpsnů):
Homer
Jo, to je Simpson!

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

Říkali jsme si, že délku pole můžeme definovat i za běhu programu, pojďme si to zkusit:

Scanner sc = new Scanner(System.in, "Windows-1250");

System.out.println("Ahoj, spočítám ti průměr známek. Kolik známek zadáš?");
int pocet = Integer.parseInt(sc.nextLine());
int[] cisla = new int[pocet];
for (int i = 0; i < pocet; i++) {
        System.out.printf("Zadejte %d. číslo: ", i + 1);
        cisla[i] = Integer.parseInt(sc.nextLine());
}
// spočítání průměru
int soucet = 0;
for (int i: cisla) {
        soucet += i;
}
float prumer = soucet / (float)cisla.length;

System.out.printf("Průměr tvých známek je: %f", prumer);

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 např. vypsat zadaná čísla pozpátku? To už by bez pole nešlo. Takhle máme k dispozici v poli původní hodnoty a můžeme s nimi neomezeně a jednoduše pracovat.

U výpočtu průměru si všimněte, že při dělení je před jedním operandem napsáno (float), tím říkáme, že chceme dělit neceločíselně. Jistě si vzpomínáte, že při zadávání čísel při dělení jsme při 3 / 2 dostali výsledek 1 a při 3 / 2.0F dostali výsledek 1.5. Zde je princip stejný.

To by pro dnešek stačilo, můžete si s polem hrát.

V následujícím cvičení, Řešené úlohy k 7. lekci Javy, si procvičí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 1034x (12.31 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Řešené úlohy k 6. lekci Javy
Všechny články v sekci
Základní konstrukce jazyka Java
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 7. lekci Javy
Článek pro vás napsal David Čápka
Avatar
Uživatelské hodnocení:
156 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 13 let. Má rád Nirvanu, sushi a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity

 

 

Komentáře
Zobrazit starší komentáře (162)

Avatar
Tomáš Rosprim:18.9.2021 16:56

Nerozumím chybě v syntaxi, která je i zde v uvedeném příkladu známek, konkrétně toto:
System.out.prin­tf("Zadejte %d. číslo: ", i + 1);

Při vpisování známek se mi neobjeví požadovaná hláška, až když vyplním počet n známek(délka pole), vypíše mi to všechny hlášky s číslem n + průměr do jednoho řádku.
Moje řešení je: System.out.prin­tln("Zadejte " + (i+1) + ". číslo: ");

Byl bych rád, kdyby mi někdo objasnil, proč to nefunguje? Používám NetBeans, může to být způobeno tím? Díky!

 
Odpovědět
18.9.2021 16:56
Avatar
Odpovídá na Tomáš Rosprim
Tomáš Rosprim:18.9.2021 17:05

Zajímavé, takže je to způsobeno pouze chybějícím odřádkováním ...
Správná syntaxe je:

System.out.prin­tf("Zadejte %d. číslo: \n", i + 1);

 
Odpovědět
18.9.2021 17:05
Avatar
daniel.pszczolka:17.10.2021 13:24

Ahoj. Tento kód

for (int i=0;i<pocet;i++){
    System.out.printf("Zadejte %d. číslo: ",i+1);
    pole[i]=Integer.parseInt(sc.nextLine());
}

mi funguje takto že se nejdříve čeká až zadám všechny prvky a až na konec do jednoho řádku napíše
Zadejte 1. číslo: Zadejte 2. číslo: Zadejte 3. číslo: Zadejte 4. číslo: Zadejte 5. číslo:
Nevím proč

 
Odpovědět
17.10.2021 13:24
Avatar
Odpovídá na daniel.pszczolka
daniel.pszczolka:17.10.2021 13:26

nepřečetl jsem si předchozí vstup :-)

 
Odpovědět
17.10.2021 13:26
Avatar
Roger Young
Člen
Avatar
Roger Young:20.11.2021 14:57

není vysvětleno pocet += i

a nefunguje to odřádkování při načítání čísel.

 
Odpovědět
20.11.2021 14:57
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Jaroslav Drobek:26. ledna 9:35

Jak použít metodu size() tak aby vracela totéž co length?

Označení proměnné "i" v obou po sobě jdoucích cyklech for a foreach je vzhledem k odlišnému charakteru proměnné (inde pole/prvek pole) zavádějící.

Pro úlohu se Simpsny právě není třeba pole setřídit, protože index výskytu ve výstupu nepoužijeme..

"(float)cisla­.length" tedy znamená, že se celočíselná hodnota cisla.length před aktuálním použitím zkonvertuje na float?

 
Odpovědět
26. ledna 9:35
Avatar
Atrament
Supertvůrce
Avatar
Atrament:28. ledna 23:29

Pro úlohu se Simpsny právě není třeba pole setřídit, protože index výskytu ve výstupu nepoužijeme..

Jak chceš provádět binarySearch() na nesetřízeném poli?

 
Odpovědět
28. ledna 23:29
Avatar
David Poslt
Člen
Avatar
David Poslt:30. ledna 13:44

Ahoj, trošku mě zarazila velikost pole. Co jsem tak koukal, tak metoda size() pro něj použít nejde a používá se u seznamu tedy list. Není teda chyba v článku? Nebo jakým způsobem se dá použít, popřípadě jaký je rozdíl mezi size() a lenght

 
Odpovědět
30. ledna 13:44
Avatar
Atrament
Supertvůrce
Avatar
Odpovídá na David Poslt
Atrament:30. ledna 14:00

Jo to size() je chyba, zrovna předevčírem jsem poslal do redakce opravu, čeká to na schválení...

 
Odpovědět
30. ledna 14:00
Avatar
Odpovídá na Atrament
Jaroslav Drobek:7. února 9:24

Jo, teď to čtu znovu a už to chápu - to bych ale neočekával, že je metoda binarySearch() tak subtilní: často potřebujeme index prvku v nesetříděném poli. Lze jistě získat cyklem, ale neexistuje na to jiná metoda?

 
Odpovědět
7. února 9:24
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

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