Letní akce PHP týden
Pouze tento týden sleva až 80 % na kurzy PHP. Lze kombinovat s akcí Letní slevy na prémiový obsah!
Brno? Vypsali jsme pro vás nové termíny školení Základů programování a OOP v Brně!

Lekce 11 - ArrayList 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, Gettery a settery v Javě, jsme si řekli něco o datu a času. Dnes si v tutoriálu ukážeme jednu kolekci, která je chytřejší, než pole. Umožňuje totiž prvky libovolně přidávat a mazat.

Pojem kolekce jsme tu již zmínili. Je to struktura, do které můžeme ukládat více objektů. Kolekcí je v Javě velké množství, jsou uzpůsobeny na různé účely a můžeme s nimi zacházet různými způsoby. Proto jim je věnována celá sekce. Dosud známe pouze kolekci pole. V průběhu seriálu však budeme potřebovat něco chytřejšího, kam budeme moci jednoduše za běhu programu přidávat a mazat záznamy. Jistě by se nám hodilo si v paměti spravovat databázi nějakých objektů. Víme, že pole má konstantní velikost, což je daň za jeho vysokou rychlost. Nyní si představíme ArrayList, který můžeme již podle názvu chápat jako nadstavbu pole.

ArrayList

ArrayList je tzv. generická kolekce. Pojem genericita si plně vysvětlíme až u kolekcí, nyní nám bude stačit vědět, že při deklaraci ArrayListu specifikujeme datový typ objektů, které v něm budou uloženy. Začněme jednoduše a udělejme si ArrayList čísel, která budeme náhodně losovat.

Losování

Program se nás vždy zeptá, zda chceme losovat další číslo a to se přidá do ArrayListu. Pokud již nebudeme chtít losovat, program vypíše losovaná čísla, seřazená od nejmenšího po největší. Založme si nový projekt Losovani a vytvořme si třídu Losovac. Třída bude obsahovat ArrayList typu Integer, kde budou čísla uložena.

Narážíme na třídu Integer, která slouží k uložení celých čísel a v podstatě obaluje typ int. Do ArrayListu se totiž dají vkládat pouze objekty, tedy proměnné referenčního typu. Pro tyto účely existuje typ Integer. Ke každému primitivnímu typu v Javě existuje jeho referenční "obal", brzy si je uvedeme. ArrayList bude privátní a bude sloužit pouze jako interní úložiště dané třídy, aby se na něj zvenku nedalo přistupovat.

ArrayList deklarujeme takto:

ArrayList<Integer> cisla;

Datový typ píšeme u generických kolekcí do špičatých závorek. ArrayList je samozřejmě objekt, jako každý jiný. Stejně jako u pole a jiných objektů, i zde proměnnou před použitím inicializujeme:

ArrayList<Integer> cisla = new ArrayList<Integer>();

Všimněte si závorek, které značí konstruktor. Takovýto list tedy umístíme do naší třídy, spolu s náhodným generátorem Random. Pro práci s třídou ArrayList je třeba přidat import java.util.Arra­yList. V konstruktoru atributy inicializujeme:

import java.util.ArrayList;
import java.util.Random;

public class Losovac {
    private ArrayList<Integer> cisla;
    private Random random;

    public Losovac() {
        random = new Random();
        cisla = new ArrayList<Integer>();
    }

}

Dále přidáme metody losuj() a vypis(), kde losuj() přidá do ArrayListu nové náhodné číslo a také ho vrátí jako návratovou hodnotu. vypis() vrátí textový řetězec pro vypsání. Ten bude obsahovat čísla z cisla, seřazená a oddělená mezerou.

Losování náhodného čísla již známe z dílu o hrací kostce, zde budeme vyhazovat čísla od 1 do 100. Číslo do ArrayListu přidáme pomocí metody add():

public int losuj() {
    Integer cislo = random.nextInt(100) + 1;
    cisla.add(cislo);
    return cislo;
}

Velmi jednoduché, že? Kolekce ArrayList je interně poměrně složitá a zatím se nebudeme zabývat tím, co se uvnitř děje. To je ostatně účel Javy, nabízet kvalitní a sofistikované komponenty, které se jednoduše používají.

Výpis čísel bude ještě snazší. K setřídění ArrayListu použijeme metodu sort ze třídy Collections, která list setřídí. Bude tedy potřeba import java.util.Collec­tions. Metoda nic nevrací, pouze ArrayList setřídí uvnitř.

public String vypis() {
    String s = "";
    Collections.sort(cisla);
    for (int i : cisla) {
        s += i + " ";
    }
    return s;
}

Hotovo.

Přesuňme se do main() a pomocí while cyklu umožněme uživateli ovládat objekt. Podobný program byla kalkulačka z prvních lekcích, kde jsme se v cyklu ptali, zda si uživatel přeje opakovat výpočet. Zde budeme postupovat totožně.

Ovládání bude pomocí možností 1, 2, 3 (losuj, vypiš, konec). Budeme je načítat pomocí sc.nextLine() jako String.

Scanner sc = new Scanner(System.in, "Windows-1250");
Losovac losovac = new Losovac();
System.out.println("Vítejte v programu losování.");
String volba = "0";
// hlavní cyklus
while (!(volba.equals("3"))) {
    // výpis možností
    System.out.println("1 - Losovat další číslo");
    System.out.println("2 - Vypsat čísla");
    System.out.println("3 - Konec");
    volba = sc.nextLine();
    System.out.println();
    // reakce na volbu
    switch (volba) {
        case "1":
            System.out.printf("Padlo číslo: %s\n", losovac.losuj());
            break;
        case "2":
            System.out.printf("Padla čísla: %s\n", losovac.vypis());
            break;
        case "3":
            System.out.println("Děkuji za použití programu");
            break;
        default:
            System.out.println("Neplatná volba, zadejte prosím znovu.");
            break;
    }
}

Nezapomeneme na import Scanner. Vlastně můžeme nechat řešení importů na NetBeans, stačí kliknout pravým tlačítkem a zvolit Fix imports, případně použít klávesovou zkratku Ctrl + Shift + I.

Průběh programu je z kódu dobře viditelný, nejprve nastavíme volbu na nějakou výchozí hodnotu, aby cyklus poprvé proběhl. Poté volbu načteme z klávesnice. String zpracujeme pomocí switche a provedeme příslušné akce. Pokud bylo zadáno něco jiného, pokryje to možnost default.

Konzolová aplikace
3 - Konec
1
Padlo číslo: 52
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec
1
Padlo číslo: 40
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec
1
Padlo číslo: 62
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec
2
Padla čísla: 2 6 7 7 8 8 9 9 10 10 12 14 17 19 19 21 23 25 25 27 27 27 28 28 28 30 30 31 32 33 33 35 35 36 36 36 37 38 38 40 41 42 42 42 44 45 45 45 45 45 48 51 52 52 53 55 56 56 56 57 58 58 59 61 62 66 68 68 71 72 73 73 74 76 82 83 84 84 85 87 88 88 89 90 90 91 93 94 98 98 98 99 100
1 - Losovat další číslo
2 - Vypsat čísla
3 - Konec

Vidíme, že můžeme stále přidávat nová a nová čísla. Máme mnohem větší možnosti, než s polem. Zároveň však můžeme s ArrayListem pracovat podobně, jako jsme pracovali s polem.

K přístupu můžeme využít metody get() a set(), ale pozor, prvek musí existovat. Zkusme si napsat následující kód:

ArrayList<String> l = new ArrayList<String>();
l.add("První");
System.out.println(l.get(0));
l.set(0, "První položka");
System.out.println(l.get(0));
l.set(1, "Druhá položka");  // vyhodí chybu

Vytvoříme si list Stringů. Přidáme položku "První" a poté vypíšeme položku na indexu 0. Vypíše se nám "První". Můžeme na ni samozřejmě i takto zapisovat. S druhou položkou na pozici 1 však již nemůžeme pracovat, protože jsme ji do listu nepřidali. U pole jsme zadali velikost a on všechny "přihrádky" (proměnné pod indexy) založil. Nyní velikost nezadáváme a "přihrádky" si přidáváme sami.

Podívejme se na ArrayList podrobněji a vypišme si metody, které jsou pro nás nyní zajímavé:

Konstruktory

Kromě prázdného ArrayListu můžeme List vytvořit i jako kopii z jiného listu, pole nebo jiné kolekce. Stačí kolekci předat do konstruktoru:

String[] poleStringu = {"První", "Druha", "Třetí"};
ArrayList<String> l = new ArrayList<String>(Arrays.asList(poleStringu));
System.out.println(l.get(2));

Kód výše vypíše "Třetí". Prvky pole se do nového listu zkopírují. Stejně můžeme předat i jiný ArrayList.

Metody na ArrayListu

  • size() - Funguje jako length na poli, vrací počet prvků v kolekci.
  • add(položka) - Metodu add() jsme si již vyzkoušeli, jako parametr bere položku, kterou vloží do listu.
  • addAll(kolekce) - Přidá do listu více položek, např. z pole.
  • clear() - Vymaže všechny položky v listu.
  • contains(položka) - Vrací true/false podle toho, zda ArrayList obsahuje předanou položku.
  • indexOf(položka) - Vrátí index prvního výskytu položky (jako u pole). Vrací -1 při neúspěchu.
  • lastIndexOf(po­ložka) - Vrací index posledního výskytu položky v Listu. Vrací -1 při neúspěchu.
  • remove(položka) - Vymaže první nalezenou položku.
  • removeAll(index, počet) - Vymaže daný počet prvků od zadaného indexu.
  • toArray() - Zkopíruje položky z ArrayListu do pole a to vrátí.

Další metody

Další metody a pro práci s listem najdeme ve třídě Collections. Jako parametr berou danou kolekci.

  • min() - Vrátí nejmenší prvek z kolekce.
  • max() - Vrátí největší prvek z kolekce.
  • reverse() - Obrátí list tak, že je první položka poslední a naopak. Metoda nic nevrací, změny se provedou v zadaném listu.
  • sort() - Sort již také známe, setřídí položky v listu. Metoda opět nic nevrací.

Vidíme, že kolekce ArrayList toho umí mnohem více, než pole. Největší výhodou je přidávání a mazání prvků. Daň ve výkonu je zanedbatelná. V sekci s kolekcemi zjistíme, že ArrayList má ještě další metody, ale zatím na to nemáme zkušenosti.

Program pro ukládání losovaných čísel byl zajímavý, ale jistě se nám bude v budoucnu hodit ukládat spíše plnohodnotné objekty, než čísla. V příští lekci, Datum a čas v Javě 8 - Vytváření a formátování, si uděláme pomocí ArrayListu databázi, bude to elektronický diář! :)


 

Stáhnout

Staženo 664x (22.32 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?
25 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
Gettery a settery v Javě
Všechny články v sekci
Objektově orientované programování v Javě
Miniatura
Následující článek
Cvičení k 11. lekci OOP v Javě
Aktivity (10)

 

 

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

Avatar
Matúš Olejník:11.10.2018 8:24

A aký kus kódu konkrétne myslíš? Ak je to toto

System.out.println("Zadejte prosím kolik kusů chcete vytvořit:");
int pocet = Integer.parseInt(sc.nextLine());

tak je logické že to zbehne ešte pred ukončením cyklu pretože vyhodnocovanie aká bola zadaná voľba je až za tým.
Môžeš logiku z case 4 vytiahnuť do ifu hneď za načítanie voľby, kde teda ak zistíš že voľba je 4 tak ukončíš cyklus bez toho aby sa vyhodnocoval switch :) Rovnako default case sa ti vykoná až po tom čo zadáš pocet hoci voľba bola mimo dovolených hodnôt.

Odpovědět 11.10.2018 8:24
/* I am not sure why this works but it fixes the problem */
Avatar
Odpovídá na Matúš Olejník
Jakub Krsička:11.10.2018 10:15

Ano tomu samozrejme rozumím, jenomže pokud mi vypíše println zadejte hodnotu, já zadám 4 potvrdim enter. Tak i přes to, že vstupní podmínka po ukončení cyklu nesouhlasí tak se mi spustí println, i scanner a další cyklus se ukončí až po těchto řádcích.

 
Odpovědět 11.10.2018 10:15
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Jakub Krsička
pocitac770:12.10.2018 13:32

Tvůj problém je ten, že proběhne kód za tímto načtením, a teprv pak se to dostane ke switchi, po čemž skončí cyklus. Máš dvě možnosti

  1. To druhé načtení z konzole dát do podmínky, tzn pokud volba není 4, tak má smysl načítat počet, jinak přejdeš dále do switche, takto to můžeš použít i do budoucna na jiné volby, které taktéž nebudou vyžadovat počet
  2. použít v cyklu řádek "break;", ten samý, co znáš ze switche, ukončí to okamžitě právě probíhající cyklus, tímpádem rovnou skočíš na rádek za while cyklem, kde můžeš mít ono rozloučení programu
 
Odpovědět 12.10.2018 13:32
Avatar
Odpovídá na pocitac770
Jakub Krsička:13.10.2018 2:52

Díky za info, jak budu u PC tak to zkusím, to takhle cyklus while probíhá normálně a vždy ?

 
Odpovědět 13.10.2018 2:52
Avatar
pocitac770
Redaktor
Avatar
Odpovídá na Jakub Krsička
pocitac770:14.10.2018 8:34

Každý cyklus má svá pravidla, jako například while cyklus, který se OPAKUJE, dokud je splněna podmínka. Důležité je ono opakuje, tzn, pokud je na začátku cyklu podmínka splněna, tak celý proběhne, kontrola probíhá opět když má začít nové opakování. Onen příkaz break je jenom taková pomůcka, zadní vrátka dalo by se říct, díky které můžeš ty pravidla "porušit". Stejně tak příkaz "continue;", který dělá to samé co "break;", ale narozdíl od něj neukončí cyklus, pouze ukončí ono opakování, a cyklus pokračuje jako by již program došel na konec bloku. Zjednodušeně, přeskočí zbytek kódu v cyklu a vrátí se zpět na začátek.

 
Odpovědět 14.10.2018 8:34
Avatar
Jakub Krsička:16. března 17:40

zdravim potraboval bych znova radu s arraylistem.... chyba:

Exception in thread "main" java.lang.NullPointerException
        at databazefno.Databaze.pridatUzivatele(Databaze.java:38)
        at databazefno.Rozhrani.pridejTestUzivatele(Rozhrani.java:81)
        at databazefno.Rozhrani.spustitRozhrani(Rozhrani.java:20)
        at databazefno.DatabazeFNO.main(DatabazeFNO.java:19)

Rozhrani:

private void pridejTestUzivatele()
    {
        String [] poleJmen = {"Jakub","Veronika","Tobias","Pavel","Tomáš"};
        String [] poleLoginu = {"jak","ver","tob","pav","tom"};
        String heslo = "heslojeveslo";
        int [] poleVolba = {1,2,2,3,1};
        for (int i = 0; i < poleJmen.length; i++)
        {
            databaze.pridatUzivatele(poleLoginu[i], heslo, poleJmen[i], poleVolba[i]);//TADY TO PÍŠE CHYBU
        }
    }

Databaze:
ArrayList v databazi:

private ArrayList <Sestra> uzivatele;
private ArrayList <Pacienti> pacienti;
private int indexPac = -1;
private int indexUz = 0;
private boolean prihlaseny =false;
private String zprava = "";
private int typUzivatele;
public void pridatUzivatele (String login, String heslo, String jmeno, int volba)
{

    switch(volba)
    {
        case 1:
            Sestra s = new Sestra (login,heslo,jmeno);
            uzivatele.add(s);//TADY TO PÍŠE CHYBU
            zprava = String.format("Sestra byla přidána login: %s heslo: %s ", login,heslo);
            break;
        case 2:
            uzivatele.add(new Doktor(login,heslo,jmeno));
            zprava = String.format("Doktor byl přidán login: %s heslo: %s ", login,heslo);
            break;
        case 3:
            uzivatele.add(new Administrator(login,heslo,jmeno));
            zprava = String.format("Administrator byla přidána login: %s heslo: %s ", login,heslo);
            break;

    }

}

Sestra:

protected String login = "";
protected String jmeno = "";
protected String heslo = "";
private static int minimalniDelkaHesla = 6;
protected boolean prihlaseny = false;
private String typ = "sestra";



public Sestra (String login, String heslo, String jmeno)
{
    this.login = login;
    this.heslo = heslo;
    this.jmeno = jmeno;

}
 
Odpovědět 16. března 17:40
Avatar
Odpovídá na Jakub Krsička
Matúš Olejník:16. března 17:48

Nemáš inicializovaný List uzivatele. Tak ako inicializuješ iné objekty napr. Sestra s = new Sestra(); tak musíš niekde inicializovať aj ArrayList, uzivatele = new ArrayList(); pred tým ako budeš volať uzivatele.add(s) atď.

Editováno 16. března 17:48
Odpovědět 16. března 17:48
/* I am not sure why this works but it fixes the problem */
Avatar
Odpovídá na Matúš Olejník
Jakub Krsička:16. března 18:41

Jasně úplně jsem na to klasicky zapomněl a pak u toho sedím dvě hodiny a hledám chybu. :-D

 
Odpovědět 16. března 18:41
Avatar
Roman Harna
Člen
Avatar
Roman Harna:27. května 18:47

package alprog;
import java.util.Arrays;
import java.util.Arra­yList;

public class ALprog {

public static void main(String[] args) {

String[] poleStringu = {"První", "Druha", "Třetí"};
ArrayList<String> l = new ArrayList<Strin­g>(Arrays.asLis­t(poleStringu));
System.out.prin­tln(l.get(2));
String[] poleStringu2 = {"Ahoj", "Nazdar", "Cus"};
ArrayList<String> 2 = new ArrayList<Strin­g>(Arrays.asLis­t(poleStringu2));
System.out.prin­tln(2.get(2));
}

}

predposlední radek chyba - not a statement ";" expected
posledni radek: ")" a ";" expected

Nechapu, muze mi to nekdo vysvetlit??

 
Odpovědět 27. května 18:47
Avatar
Roman Harna
Člen
Avatar
Odpovídá na Roman Harna
Roman Harna:27. května 18:51

Uz to vim ta 2 je spatne :-###

 
Odpovědět 27. května 18:51
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 57. Zobrazit vše