Body zdarma Java týden
Využij podzimních slev a získej od nás až 40 % bodů zdarma! Více zde
Pouze tento týden sleva až 80 % na Java e-learning!

Lekce 7 - Pole v Javě

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Cykly v Javě, jsme si v našem Java seriálu ukázali cykly. 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, takle 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;

Pole je samozřejmě název naší proměnné. Nyní jsme však pouze deklarovali, že v proměnné bude pole 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 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ů. Stejně tak můžeme použít metodu size(), která vrátí stejný výsledek.

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()

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 příští lekci, Textové řetězce v Javě podruhé - práce s jednotlivými znaky, na vás čeká překvapení ;-)


 

Stáhnout

Staženo 913x (79.04 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

 

Článek pro vás napsal David Čápka
Avatar
Jak se ti líbí článek?
42 hlasů
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor sítě se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.
Předchozí článek
Cykly v Javě
Všechny články v sekci
Základní konstrukce jazyka Java
Miniatura
Následující článek
Cvičení k 7. lekci Javy
Aktivity (10)

 

 

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

Avatar
Víťa Š.
Člen
Avatar
Víťa Š.:10. září 21:11

Nefunguje to.

Odpovědět 10. září 21:11
Život by byl mnohem snazší, kdybychom k němu měli zdrojový kód.
Avatar
Odpovídá na Víťa Š.
Matúš Olejník:10. září 23:46

Tak keď spravíš to, že v mene ktoré hľadáš prevedieš všetky písmená na malé tak treba mať aj v tom poli "simpsonovi" mená napísané len malými písmenami.

Odpovědět  +1 10. září 23:46
/* I am not sure why this works but it fixes the problem */
Avatar
Jan Béňa
Člen
Avatar
Jan Béňa:3. října 22:44

Prosím, nějaká dobrá duše. Co by mi vysvětlila, jak vypsat v poli Stringy místo intů. Zjistil jsem, že víceméně až do kapitoly s poli mi bylo vše jasné. Tak jsem si v práci říkal, že bych si doma zkusil vypsat pole se jmény pro moji budoucí databázi jmen. Ve které bych pak náhodně generoval jména. Pochopitelně až bych došel do OOP, kde jsem zahlédnul nahodný generátor(kostka). Bohůžel jsem ztroskotal jen na pouhém vypsání jmen do pole.Přikládám dva asi z 50 možností co jsem zkoušel. Tyhle dva sice neukazují chybu, ale program i přesto spadne :D.

String[] jmena= {"Black","Whi­te","Reed","McDo­nald","Storm"};
System.out.prin­tln(jmena[0]);

A nebo ...

String[] jmena= new String[1];
jmena[0]= ("Black");
jmena[1]= ("White");
System.out.prin­tln(jmena[1]);

Předem děkuji za pomoc.

 
Odpovědět 3. října 22:44
Avatar
Jan Béňa
Člen
Avatar
Odpovídá na Jan Béňa
Jan Béňa:3. října 23:03

Tak beru zpět to první funguje, měl jsem tam navíc složenou závorku, která mi tam asi dělala paseku. Jinak děkuji za skvělé stránky. Palec nahoru.

 
Odpovědět 3. října 23:03
Avatar
Odpovídá na Jan Béňa
Matúš Olejník:3. října 23:21

Ahoj, áno prvý spôsob ti bude fungovať a v tom druhom ti hodí chybu už pri

jmena[1] = ("White"); //tie zátvorky sú tu zbytočné

je to preto, lebo týmto príkazom

String[] jmena = new String[N]; //kde v tvojom prípade N = 1

hovoríš, že chceš aby sa do poľa jmena zmestil len N počet mien. No a ako už vieš indexovanie začína od nuly takže hodnoty môžeš vkladať na indexy od 0 po N - 1. Keďže ty si si tam deklaroval pole o veľkosti 1 tak nemôžeš už vkladať údaje na index 1 a viac.
Keď chceš aby ti prešiel aj druhý spôsob tak môžeš napr. zmeniť deklaráciu na

String[] jmena = new String[2];

prípade inú, tebou potrebnú, veľkosť :)

Odpovědět  +1 3. října 23:21
/* I am not sure why this works but it fixes the problem */
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Jan Béňa
Člen
Avatar
Odpovídá na Matúš Olejník
Jan Béňa:3. října 23:47

Aha já s tím právě počítal že v programování začíná od nuly proto jsem tam na deklaraci napsal 1 teď když jsi to tak pěkně napsal si uvědomuji že by to byla blbost. Jsem to asi prehlednul. Nicméně děkuji za odpověď pomohla mi. Databázi bych měl teď ještě se naučit to náhodně generovat ale tam budu muset ještě dojít a ještě jednou děkuji za odpověď.

 
Odpovědět  +1 3. října 23:47
Avatar
Víťa Š.
Člen
Avatar
Odpovídá na Víťa Š.
Víťa Š.:7. října 19:41

Už kód po úpravě funguje krásně. změna na int pozice = Arrays.binary­Search(simpso­novi, simpson.toLower­Case());
if (pozice <= 0)

package lekce4;

import java.util.Arrays;
import java.util.Scanner;

public class lekce4 {

    public static void main(String[ ] args) {
Scanner sc = new Scanner(System.in, "UTF-8");

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.toLowerCase());  /**Arrays.binarySearch(z jakeho pole, co hledam)  */
if (pozice <= 0)
{
    System.out.println("Jo, to je Simpson!");
} else
{
    System.out.println("Hele, tohle není Simpson!");
}

}
}
Odpovědět  -1 7. října 19:41
Život by byl mnohem snazší, kdybychom k němu měli zdrojový kód.
Avatar
Odpovídá na Víťa Š.
Matúš Olejník:7. října 20:53

A to už podľa čoho si si povedal, že to funguje správne?

V poli simpsonovi máš mená ktoré začínajú veľkými písmenami a potom keď ideš hľadať či sa v ňom nachádza požadované meno tak v ňom zmeníš všetky písmená na malé a to hľadáš. Už len tu je jasné, že niečo nie je dobre a asi slovo "Bart" nebude to isté ako "bart".

A keby aj hej tak máš potom podmienku, o ktorej tvrdíš, že vyriešila tvoj problém

if (pozice <= 0)

Keď pozreš dokumentáciu k binarySearch tak v nej je napísané

index of the search key, if it is contained in the array; otherwise, (-(insertion point) - 1). The insertion point is defined as the point at which the key would be inserted into the array:

čiže ti vráti číslo 0 alebo väčšie ako 0 ak sa hľadaný výraz nachádza v poli. Inak vráti záporné číslo, ktoré ak dáš do absolútnej hodnoty ti označí index na ktorom by sa hľadané slovo nachádzalo ak by v tom poli naozaj bolo.

Stačí pri zadávaní simpsona napísať random reťazec a tvoj program vypíše, že je z rodiny Simpsnov pretože funkcia binarySearch vráti zápornú hodnotu.

Najprv svoj program poriadne otestuj než ho tu pre nováčikov označíš ako super fungujúce riešenie.

Odpovědět 7. října 20:53
/* I am not sure why this works but it fixes the problem */
Avatar
Víťa Š.
Člen
Avatar
Odpovídá na Víťa Š.
Víťa Š.:8. října 1:38

Uvedený kód funguje, viz. screeny, vyzkoušej si ho.

Odpovědět  -1 8. října 1:38
Život by byl mnohem snazší, kdybychom k němu měli zdrojový kód.
Avatar
Odpovídá na Víťa Š.
Matúš Olejník:8. října 9:52

Nemusím ho ani skúšať aby som videl, že je to zle. Otestuj si svoj program poriadne a uvidíš. Máš podmienku s dvomi vetvami a testuješ program len na jeden vstup.

Až si to všimneš, zistíš, že neplechu ti tam robí najmä to "toLowerCase" kvôli čomu tam potom robíš chybnú podmienku len aby sa zdalo, že to funguje.

10. září 23:46 som ti dokonca písal čo treba spraviť ak chceš ignorovať veľkosti písmen.

Odpovědět 8. října 9:52
/* I am not sure why this works but it fixes the problem */
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 129. Zobrazit vše