Listat
Tällä viikolla tutustumme Javan kenties yleisimpään kokoelmaan: listoihin. Listat ovat tietorakenteita, joiden pituus kasvaa joustavasti, kun niihin lisätään uusia arvoja. Listoihin voidaan lisätä arvoja myös aiempien arvojen väliin ja listan väleistä voidaan poistaa arvoja. Listat ovat olioita ja niillä on metodeita, joiden avulla arvoja lisätään, poistetaan, etsitään jne.
Sisällysluettelo
- Tehtäväpohjien kloonaaminen GitHubista 9:48
- ArrayList:in perusteet
- Eri listatyypit: ArrayList vs. LinkedList
- Listaoperaatiot
- Video: Listan luominen, arvojen lisääminen ja arvojen hakeminen 25:00
- Listalle lisääminen
- Lisääminen tiettyyn indeksiin
- Listalta hakeminen
- Listalta poistaminen
- Listan sisällön tutkiminen
- Listalla olevien arvojen lukumäärä
- Listan arvojen läpikäynti (indeksillä)
- Video: listan sisällön tutkiminen ja arvojen läpikäynti 42:48
- Listan luominen valmiilla arvoilla
- Listamuuttujien yhteensopivuus
- Listan järjestäminen
- Tehtäväideoita tunnille
Tehtäväpohjien kloonaaminen GitHubista 9:48
Tällä viikolla teemme Viopessa tehtäväkokonaisuuden, joka on lainattu Helsingin yliopiston Ohjelmoinnin MOOC -kurssilta. Tehtäväkokonaisuuden suoraviivaistamiseksi tehtäviin on saatavilla valmiit pohjat GitHubissa osoitteessa https://github.com/swd1tn002/mooc.fi-2019-osa3/.
Voit kopioida tehtäväpohjat itsellesi yksi kerrallaan Viope-tehtävän linkkien kautta, tai kopioida koko projektipohjan kerralla. Alla oleva video esittelee, miten projekti kloonataan GitHubista omaan Eclipseen:
Huom! Tehdessäsi tehtäväpohjiin liittyviä tehtäviä Viopessa, varmista tehtävän nimen ja muokattavan luokan perusteella, että käsittelet oikeaa tehtäväpohjaa. Tehtävien numerointi poikkeaa hieman toisistaan Viopessa ja GitHubissa.
ArrayList:in perusteet
Seuraava valinnainen Helsingin yliopiston Ohjelmoinnin MOOC -kurssin video esittelee Javan ArrayList-tietorakenteen toimintaa ja käyttämistä:
Hyödynnä myös Helsingin yliopiston MOOC-kurssin muita materiaaleja: https://ohjelmointi-20.mooc.fi/osa-3/2-listat.
Eri listatyypit: ArrayList vs. LinkedList
Javassa on useita eri listatyyppejä. Kaikki listat toimivat ulkoisesti samalla tavalla, vaikka niiden sisäiset toteutustavat vaihtelevat merkittävästi. ArrayList
on sisäisesti toteutettu taulukon avulla, kun taas LinkedList
on toteutettu linkittämällä listan alkiot toisiinsa “ketjuksi”. Sopivin lista kuhunkin tarkoitukseen vaihtelee listan käyttötavasta riippuen, mutta pääsääntöisesti pärjäät hyvin käyttämällä aina ArrayList
-listoja.
Listat sijaitsevat java.util
-paketissa, joten ne otetaan käyttöön esim. seuraavilla import
-käskyillä:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
Voit luoda itsellesi merkkijonolistoja seuraavasti:
ArrayList<String> taulukkoLista = new ArrayList<String>();
LinkedList<String> linkitettyLista = new LinkedList<String>();
Geneeriset tyypit
Listat ovat geneerisiä, eli niiden sisällön tyyppi voidaan määritellä itse. Edellä määritellyt listat säilyttävät merkkijonoja ja tämä ArrayList
voi säilyttää kokonaislukuja:
// kulmasuluissa oleva tyypin nimi kertoo, mitä arvoja listalla säilytetään:
ArrayList<Integer> numerot = new ArrayList<Integer>();
Java osaa päätellä luotavan listan tyypin muuttujan tyypistä, joten voimme määritellä listan luonnissa tyypin tyhjäksi <>
. Java päättelee tyypiksi <String>
:
// jälkimmäiset kulmasulut voidaan jättää tyhjiksi:
ArrayList<String> merkkijonot = new ArrayList<>();
Yhdessä listassa voidaan varastoida ainoastaan yhdentyyppisiä arvoja, eikä varastoitavaa tyyppiä voida myöhemmin vaihtaa.
Alkeistietotyypit ja kääreluokat
Listoilla käsiteltävien arvojen on oltava olioita, eli ei aikaisemmilta viikoilta tuttuja alkeistietotyyppejä, kuten boolean
, int
tai double
.
Alkeistietotyyppien varastoimiseksi Javassa on olemassa valmiita kääreluokkia, joiden oliot pitävät vain sisällään tallessa yksittäisiää alkeistyyppisiä arvoja. Kääreluokat on nimetty kuten alkeistyypit, mutta niiden nimet alkavat isolla alkukirjaimella, esim: Boolean
, Integer
ja Double
. Kääreluokan avulla numerosi “kääritään” olion sisälle, jolloin myös numeroita voidaan käsitellä listoilla.
Java huolehtii onneksi kääreluokkien käyttämisestä automaattisesti lähes jokaisessa operaatiossa. Sinun tulee ainoastaan määritellä listan tyypiksi käytettävä kääreluokka:
ArrayList<Integer> kokonaisluvut = new ArrayList<>();
ArrayList<Double> liukuluvut = new ArrayList<>();
ArrayList<Boolean> totuusarvot = new ArrayList<>();
Listaoperaatiot
Listoja käytetään aina kutsumalla listan metodeja. Seuraava oppituntitallenne käy läpi keskeiset listaoperaatiot, jotka on esitetty myös tekstimuodossa alempana.
Video: Listan luominen, arvojen lisääminen ja arvojen hakeminen 25:00
Tällä videolla opettelemme luomaan listan, asettamaan sinne arvoja ja hakemaan arvoja haluamistamme kohdista. Valmis lähdekooditiedosto löytyy GitHubista: Hiihtojoukkue.java
Listalle lisääminen
add
-metodi lisää listalle uusia arvoja listan loppuun:
List<String> sanat = new ArrayList<>();
sanat.add("Hello");
sanat.add("World");
System.out.println(sanat); // [Hello, World]
Lisääminen tiettyyn indeksiin
Listalle voidaan lisätä myös arvoja tiettyyn indeksiin. Tällöin add
-metodille annetaan ensimmäiseksi parametriarvoksi haluttu indeksi. Seuraavien listalla olevien arvojen indeksit kasvavat yhdellä:
List<String> sanat = new ArrayList<>();
// lisätään arvoja listan loppuun:
sanat.add("Hello");
sanat.add("World");
// lisätään arvoja tiettyyn indeksiin:
sanat.add(0, "Terve");
sanat.add(1, "Maailma");
System.out.println(sanat); // [Terve, Maailma, Hello, World]
Listalta hakeminen
Listalta voidaan hakea yksittäisiä arvoja get
-metodin avulla. Muista, että listojen indeksit alkavat aina nollasta!
List<String> sanat = new ArrayList<>();
sanat.add("Hello");
sanat.add("World");
System.out.println(sanat.get(0)); // Hello
System.out.println(sanat.get(1)); // World
Listalta poistaminen
Listalta voidaan poistaa joko tietyn indeksin perusteella tai tiettyjä arvoja remove
-metodin avulla. Muista, että listojen indeksit alkavat aina nollasta!
List<String> sanat = new ArrayList<>();
sanat.add("Hello");
sanat.add("World");
sanat.add("!");
// poistetaan indeksin perusteella:
sanat.remove(0);
// poistetaan tietty arvo:
sanat.remove("World");
System.out.println(sanat); // [!]
Listan sisällön tutkiminen
Listoilta voidaan etsiä alkioita kahdella metodilla:
contains
palauttaatrue
, jos annettu arvo löytyy jostain kohtaa listaltaindexOf
palauttaa sen indeksin, josta annettu arvo löytyy- Huom! Listojen indeksit alkavat aina nollasta
- Huom! Jos annettua arvoa ei löydy,
indexOf
palauttaa luvun-1
ArrayList<String> nimet = new ArrayList<>();
nimet.add("Matti");
nimet.add("Maija");
System.out.println(nimet.contains("Matti")); // true
System.out.println(nimet.indexOf("Maija")); // 1
System.out.println(nimet.indexOf("Maikki")); // -1, eli ei löydy!
Listalla olevien arvojen lukumäärä
Listan koko selviää size
-metodilla:
List<String> sanat = new ArrayList<>();
sanat.add("Hello");
sanat.add("World");
int pituus = sanat.size();
System.out.println(pituus); // 2
Listan pituutta tarvitaan usein, kun halutaan käsitellä listan kaikkia arvoja niiden indeksien avulla.
Listan arvojen läpikäynti (indeksillä)
- Listan sisältö on usein tarpeellista käydä läpi alusta loppuun
- Tämä voidaan toteuttaa toistorakenteella, jossa lähdetään liikkeelle nollasta ja edetään viimeiseen indeksiin
- Koska indeksit alkavat nollasta, viimeinen indeksi on aina yhtä pienempi kuin listan pituus:
int vikaIdeksi = lista.size() – 1;
- Toistorakenteen sisällä listan arvot voidaan pyytää yksi kerrallaan get-metodin avulla:
lista.get(i)
import java.util.ArrayList;
import java.util.List;
public class ListanLapikayntiFor {
public static void main(String[] args) {
List<Integer> numerot = new ArrayList<>();
numerot.add(321);
numerot.add(456);
numerot.add(789);
// käydään kaikki listan arvot läpi:
for (int i = 0; i < numerot.size(); i++) {
System.out.println(numerot.get(i));
}
}
}
Listan arvojen läpikäynti (for-each)
For-each –silmukalla on mahdollista käydä kätevästi kaikki tietyn listan arvot läpi ilman, että pidämme itse kirjaa indeksistä ja haemme arvoja get
-metodilla:
import java.util.ArrayList;
import java.util.List;
public class ListanLapikayntiForEach {
public static void main(String[] args) {
List<Integer> numerot = new ArrayList<>();
numerot.add(321);
numerot.add(456);
numerot.add(789);
// käydään kaikki listan arvot läpi:
for (Integer arvo : numerot) {
System.out.println(arvo);
}
}
}
Katso esim: https://stackoverflow.com/a/22114571
Video: listan sisällön tutkiminen ja arvojen läpikäynti 42:48
Tällä videolla opettelemme pyytämään listalle alkioita käyttäjältä (ListanKysyminenKayttajalta.java). Kun perustapaus on hallussa, sovellamme logiikkaa muodostaaksemme HTML-valintarakenteen käyttäjän syöttämien automerkkien nimien perusteella (Automerkit.java).
Listan luominen valmiilla arvoilla
Toisinaan ohjelmassa on tarpeen luoda lista joillain valmiilla ennalta tunnetuilla arvoilla. Tällaisen listan luominen new ArrayList<>()
-operaatiolla ja täyttäminen add
-metodilla olisi kovin työlästä. Voit sen sijaan käyttää List.of
-metodia, jolle voit antaa listan sisällön valmiina:
List<String> viikonpaivat = List.of("ma", "ti", "ke", "to", "pe", "la", "su");
Muista myös lisätä luokan alkuun import java.util.List;
.
Huom! List.of
-metodin palauttama lista ei ole tavallinen ArrayList
, eli et voi muokata yllä esitettyä listaa enää sen luomisen jälkeen. Muut operaatiot, kuten arvojen haku, etsiminen ja läpikäynti, toimivat normaalisti.
Listamuuttujien yhteensopivuus
Vaikka ArrayList
ja LinkedList
ovat toiminnallisesti täysin samanlaiset, et voi asettaa eri tyyppistä listaa toisen tyyppiseen muuttujaan. Poikkeuksen tähän sääntöön tekee kaikkien listojen yhteisen rajapinnan määrittelevä List
-tyyppi, joka on yhteensopiva kaikkien listojen kanssa:
List<String> nimet = new ArrayList<>();
List<String> osoitteet = new LinkedList<>();
List<String> kaupungit = List.of("Helsinki", "Porvoo");
Käyttämällä List
-tyyppiä muuttujien tyyppinä ja myöhemmin metodien parametrien tyyppinä, vältät useita ongelmatilanteita mahdollisten epäyhteensopivien listojen kanssa.
Muista, että tarvitset List
-tyypille oman import
-komennot luokan alkuun:
import java.util.List;
Listan järjestäminen
Lista on mahdollista järjestää eli helposti alkioiden “luonnolliseen järjestykseen”. Collections
-apuluokalla on olemassa sort
-niminen metodi, joka järjestää sille annetun listan:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class KaupunkienSorttaus {
public static void main(String[] args) {
List<String> kaupungit = new ArrayList<>();
kaupungit.add("Rauma");
kaupungit.add("Helsinki");
kaupungit.add("Espoo");
kaupungit.add("Vantaa");
kaupungit.add("Turku");
// Tulostaa siinä järjestyksessä, kun lisäsimme arvot:
System.out.println(kaupungit); // [Rauma, Helsinki, Espoo, Vantaa, Turku]
Collections.sort(kaupungit); // järjestää "luonnolliseen" järjestykseen
// Lista on nyt eri järjestyksessä:
System.out.println(kaupungit); // [Espoo, Helsinki, Rauma, Turku, Vantaa]
}
}
Huomaa, että merkkijonojen luonnollinen järjestys ei toimi odotetusti eri kokoisia kirjaimia vertaillessa, koska vertailussa käytetään merkkien Unicode-arvoja.
Listan kopioiminen ja viittaustyyppiset muuttujat 32:17
Seuraavalla oppituntitallenteella käsitellään listojen käsittelyä eri muuttujien kautta sekä listojen kopioimista uusien listojen luomista varten:
Tällä videolla tutustumme ensin listojen luomiseen valmiiksi määritellyillä arvoilla (ListanLuominenValmiillaArvoilla.java).
Seuraavaksi perehdymme siihen, miksi alkeistietotyypit kuten int
, double
ja boolean
eivät sovellu listojen tyypeiksi, ja miten asia voidaan kiertää ns. kääreluokkien avulla (NumerotListoilla.java).
Lopuksi tarkastelemme konkreettisesti miten listat käyttäytyvät, mikäli viittaamme samaan listaan usean muuttujan kautta (ViittaustyyppisetMuuttujat.java).
Tehtäväideoita tunnille
Nimigeneraattori
Kirjoitetaan ohjelma, joka arpoo satunnaisia sanoja erilaisista ryhmistä ja muodostaa yritysten, bändien tai henkilöiden nimiä.
Opittavat aiheet: listan muodostaminen, listan pituuden selvittäminen ja listalta haku.
HTML-valintarakenne
Kirjoitetaan ohjelma, johon määritellään lista asioista, jotka esitetään toistorakenteella HTML-muodossa.
Opittavat aiheet: listan muodostaminen, listan kaikkien arvojen läpikäynti.