Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Stream-rajapinta Javassa | Edistyneet Java-Ominaisuudet ja -Tekniikat
Practice
Projects
Quizzes & Challenges
Quizzes
Challenges
/
Java-tietorakenteet

bookStream-rajapinta Javassa

Java-kielessä on useita tapoja käsitellä dataa – silmukat, metodit ja erilaiset algoritmit. Kuitenkin Java 8:ssa esiteltiin erittäin tehokas työkalu – Stream API.

Yksinkertaisesti sanottuna Stream API mahdollistaa tietovirran käsittelyn nopeasti ja helposti. Tässä yhteydessä tietovirta edustaa kokoelmia. Stream API:lla on useita käsitteitä. Tässä ovat tärkeimmät.

Keskeiset käsitteet

  • Stream: edustaa tietoelementtien jonoa, jota voidaan käsitellä;

  • Välioperaatiot: operaatiot, jotka luovat uuden streamin suorituksen jälkeen. Esimerkkejä: filter, map, distinct, sorted;

  • Pääteoperaatiot: operaatiot, jotka viimeistelevät streamin käsittelyn ja palauttavat tuloksen. Esimerkkejä: collect, forEach, count, reduce;

  • Rinnakkaiset streamit: mahdollistavat datan rinnakkaisen käsittelyn. Menetelmiä parallel() ja parallelStream() käytetään rinnakkaisten streamien luomiseen.

Riittävästi teoriaa, nyt siirrytään koodaukseen!

Virran (stream) luominen tapahtuu käyttämällä metodia kokoelmassa, jonka haluat muuntaa virraksi:

Main.java

Main.java

copy
12
List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();

stream()-metodilla saadaan merkkijonojen virta. Jotta voimme työskennellä virran kanssa, on ymmärrettävä, mitä lambda-lausekkeet ovat, sillä virran metodit toimivat pääasiassa niiden avulla.

Lambda-lausekkeet

Lambda-lausekkeet otettiin käyttöön Java 8:ssa, ja ne edustavat yksinkertaistettua tapaa luoda anonyymejä funktioita Javassa. Emme ole aiemmin käsitelleet anonyymejä funktioita, koska ne eivät ole olleet erityisen tarpeellisia, mutta nyt tutustumme niihin lambda-lausekkeiden kautta.

Lambda-lausekkeen syntaksi:

Yleinen syntaksi lambda-lausekkeille Javassa näyttää tältä:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Parametrit: tämä on parametrilista, joka voi olla tyhjä tai sisältää yhden tai useamman parametrin;

  • Nuoli: esitetään symbolilla ->, joka erottaa parametrit lambda-lausekkeen rungosta;

  • Lauseke tai lauseet: tämä on funktion runko, joka sisältää lausekkeen tai lohkon lauseita.

Tässä on esimerkki lambda-lausekkeesta, joka kuvaa yksinkertaista funktiota, joka laskee yhteen kaksi lukua:

Example.java

Example.java

copy
12345678910
// Traditional way MathOperation addition = new MathOperation() { @Override public int operate(int a, int b) { return a + b; } }; // Using a lambda expression MathOperation addition = (int a, int b) -> a + b;

Tarkastellaan tarkemmin, mitä yllä olevassa koodissa tapahtuu ja miten lambda-lausekkeita käytetään:

Main.java

Main.java

copy
1234567891011121314
package com.example; // Functional interface with a single abstract method interface MyMathOperation { int operate(int a, int b); } public class Main { public static void main(String[] args) { // Using a lambda expression to implement the interface MyMathOperation addition = (a, b) -> a + b; System.out.println("Sum: " + addition.operate(5, 3)); } }

Yllä olevassa koodissa:

Luotu funktionaalinen rajapinta MyMathOperation, jossa on yksi abstrakti metodi operate.

Käytetty lambda-lauseketta tämän metodin toteuttamiseen, suorittaen kahden luvun yhteenlaskun.

Tulostettu yhteenlaskun tulos.

On ymmärrettävää, että tämän koodin toiminnan hahmottaminen voi olla haastavaa tässä vaiheessa, mutta palataan takaisin Stream API:in pariin, jossa lambda-lausekkeita käytetään usein, ja pyritään ymmärtämään niiden käyttöä käytännössä.

Kuten aiemmin, loimme merkkijonovirran merkkijonolistasta. Nyt käytetään stream-metodeja jokaisen merkkijonon muuttamiseksi isoiksi kirjaimiksi tässä virrassa:

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); stream.map(e -> e.toUpperCase()).toList(); } }

Yllä olevassa koodissa käytettiin lambda-lauseketta ja kahta metodia: map() ja toList(). Jos on selvää, mitä toList()-metodi tekee, map()-metodi muuttaa jokaisen virran alkion annetun lambda-lausekkeen mukaisesti.

Tarkastellaan tarkemmin, miten lambda-lauseke toimii tässä:

map()-metodi käyttää toUpperCase()-metodia jokaiselle virran alkiolle. Määrittelimme tämän virran alkion nimellä e ja lambda-lausekkeen avulla ohjeistimme ohjelmaa soveltamaan tätä metodia jokaiseen alkioon.

Tämä ei kuitenkaan ole vielä lopullinen vaihe, koska käytimme välioperaatiota. Tämä tarkoittaa, että operaatiot virralla eivät ole vielä valmiit. Jotta työ virran kanssa saadaan päätökseen, täytyy käyttää pääteoperaatiota, joka viimeistelee operaatiot virralla ja palauttaa tietyn arvon. Esimerkiksi voit käyttää toList()-metodia, jolloin muokattu virta muunnetaan listaksi.

Esimerkiksi:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.toUpperCase()).toList(); System.out.println(list); } }

Tarkastellaan tarkemmin mahdollisia välioperaatioita streamissa.

Välioperaatiot

map()-metodi – olet jo tutustunut tähän metodiin; se suorittaa lambda-lausekkeessa määritellyt toiminnot jokaiselle streamin alkiolle.

Esimerkiksi käytetään substring()-metodia jokaiselle merkkijonovirran alkiolle:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

filter()-metodi ottaa lambda-lausekkeen, jossa on ehto, jonka perusteella virtaa suodatetaan. Toisin sanoen, kaikki ehdon täyttävät alkiot jäävät virtaan, ja alkiot, jotka eivät täytä ehtoa, poistetaan virrasta. Muokataan virtaa niin, että siihen jäävät vain ne alkiot, joiden pituus on suurempi kuin 5:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); stream = stream.filter(e -> e.length() > 5); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

filter()-menetelmällä poistetaan merkkijono "with" virrasta, koska tämä sana on alle 5 merkkiä pitkä.

Voit myös käyttää välimuotoisia operaatioita useita kertoja peräkkäin.

Esimerkiksi voimme hieman yksinkertaistaa yllä olevaa koodia:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); List<String> list = strings.stream() .filter(e -> e.length() > 5) .map(e -> e.substring(1, 4)) .toList(); System.out.println("Modified list: " + list); } }

Kun ketjutat useita stream-menetelmiä yhteen, on suositeltavaa sijoittaa jokainen menetelmä uudelle riville, jotta koodin luettavuus paranee huomattavasti.

Metodi flatMap() muuntaa jokaisen virran alkion uudeksi virraksi ja yhdistää tulokset yhdeksi virraksi. Toisin sanoen, tämän metodin avulla voimme jakaa virran useisiin virtoihin, jotka yhdistetään lopuksi yhdeksi virraksi. Esimerkiksi, jos sinulla on lista merkkijonoja, joissa jokaisessa voi olla useampi kuin yksi sana, kuten lista etu- ja sukunimistä. Ja sinun täytyy muuttaa jokaisen sanan ensimmäinen kirjain isoksi:

Main.java

Main.java

copy
123456789101112131415161718192021222324
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

Yllä olevassa koodissa kirjoitimme erillisen yksityisen metodin, joka muuttaa sanan ensimmäisen kirjaimen isoksi, ja käytimme tätä metodia map()-metodin kanssa yhdessä lambda-lausekkeen kanssa.

Huomaa, että käyttämällä flatMap-metodia jaoimme jokaisen virran alkion eri virroiksi käyttämällä Arrays.stream(e.split(" ")) -metodia. Koska split()-metodi palauttaa taulukon, meidän täytyy käyttää Arrays.stream()-metodia muuttaaksemme tämän taulukon virroiksi.

Tämän jälkeen kaikki nämä virrat yhdistetään yhdeksi virraksi, minkä jälkeen käytämme kirjoittamaamme metodia. Nyt meillä on kaikkien käyttäjien nimet ja sukunimet, joiden ensimmäinen kirjain on iso.

Tiedätkö mikä olisi hienoa? Jos laittaisimme nämä nimet ja sukunimet HashMap-rakenteeseen, jossa avain on sukunimi ja arvo on etunimi.

Toteutetaan tämä koodissa:

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334
package com.example; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); Map<String, String> usersKeyValue = new HashMap<>(); for (int i = 0; i < list.size() - 1; i+=2) { String name = list.get(i); String surname = list.get(i + 1); usersKeyValue.put(surname, name); } System.out.println("Map with surnames as keys and names as values: " + usersKeyValue); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

Yksinkertaisella silmukalla tallensimme etunimen ja sukunimen muuttujiin ja sitten map-rakenteeseen. Huomaa, miten silmukka toimii. Kasvatamme muuttujaa i aina kahdella jokaisella iteraatiolla, koska meidän täytyy ohittaa sukunimi, kun olemme jo tallentaneet sen.

  • distinct()-metodi poistaa duplikaatit streamista. Yleisesti tämä on hyödyllistä, jos tarvitset uniikkeja alkioita streamissa tai haluat poistaa duplikaatit listasta nopeasti. Tämän voi helposti toteuttaa seuraavalla rakenteella:
list.stream().distinct().toList()
  • sorted-metodi järjestää kaikki streamin alkiot luonnolliseen järjestykseen, pienimmästä suurimpaan tai aakkosjärjestykseen. Tämä on hyödyllistä, jos tarvitset järjestetyn streamin tai haluat nopeasti lajitella listan;

  • skip(n)-metodi ohittaa streamin ensimmäiset n alkiota. Tämä voi olla hyödyllistä työskenneltäessä tekstitiedostojen kanssa, joissa ensimmäiset n riviä voivat olla esimerkiksi metadataa tai tiedoston kuvaus. On myös mainitsemisen arvoinen limit(n)-metodi, joka yleisesti rajoittaa streamin alkioiden määrää. Vaikka loisimme streamin, jossa on 1000 alkiota ja käyttäisimme sitten limit(200), stream sisältää vain ensimmäiset 200 alkiota.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example = example.stream().skip(3).limit(5).toList(); System.out.println("List: " + example); } }

Nämä ovat tärkeimmät välimetodit, joita tarvitset. Voit tutustua muihin metodeihin viittaamalla linkki viralliseen Java-dokumentaatioon. Siirrytään seuraavaksi päätemetodeihin.

Päätemetodit

  • Tunnetuin päätemetodi on toList(). Se muuntaa streamin listaksi ja palauttaa sen. Toisin sanoen voit suoraan liittää tämän streamin metodeineen listaan. Tämä metodi esiteltiin Java 17 -versiossa ja korvaa monimutkaisemman rakenteen collect(Collectors.toList());

  • collect()-metodi muuntaa myös streamin tiettyyn tietorakenteeseen. Se käyttää parametrina Collectors-rajapinnan metodia. Tämä rajapinta sisältää metodeja kuten toList(), toSet() ja toCollection(). Esimerkiksi:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Set<Integer> integerSet = example.stream().collect(Collectors.toSet()); System.out.println("List: " + example); System.out.println("Set: " + integerSet); } }

forEach()-metodi ottaa lambda-lausekkeen ja suorittaa tietyn toiminnon jokaiselle virran alkiolle.

Esimerkiksi:

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example.stream().forEach(e -> System.out.println(e + 1)); } }

Ero tämän menetelmän ja map-menetelmän välillä on, että tämä menetelmä on päätemenetelmä ja sen jälkeen et voi kutsua muita menetelmiä.

Nämä ovat kaikki perusmenetelmät virtojen käsittelyyn. Tämä on monimutkainen aihe, eikä sitä välttämättä ymmärrä heti. Kuitenkin kyseessä on aihe, joka opitaan harjoittelemalla. Tulevissa harjoitusluvuissa virtojen kanssa saat runsaasti mahdollisuuksia työskennellä niiden parissa, sillä se on erittäin kätevä ja käytännöllinen tapa käsitellä listoja ja taulukoita!

1. Mikä on Stream API:n ensisijainen tarkoitus Javassa?

2. Mikä seuraavista on päätemenetelmä Stream API:ssa?

3. Mitä map-operaatio tekee Stream API:ssa?

4. Miten flatMap-operaatio eroaa map-operaatiosta Stream API:ssa?

5. Mitä filter-operaatio tekee Stream API:ssa?

6. Mikä on forEach-operaation tarkoitus Stream API:ssa?

7. Mikä seuraavista on välivaiheen operaatio Stream API:ssa?

8. Miten limit-operaatiota käytetään Stream API:ssa?

question mark

Mikä on Stream API:n ensisijainen tarkoitus Javassa?

Select the correct answer

question mark

Mikä seuraavista on päätemenetelmä Stream API:ssa?

Select the correct answer

question mark

Mitä map-operaatio tekee Stream API:ssa?

Select the correct answer

question mark

Miten flatMap-operaatio eroaa map-operaatiosta Stream API:ssa?

Select the correct answer

question mark

Mitä filter-operaatio tekee Stream API:ssa?

Select the correct answer

question mark

Mikä on forEach-operaation tarkoitus Stream API:ssa?

Select the correct answer

question mark

Mikä seuraavista on välivaiheen operaatio Stream API:ssa?

Select the correct answer

question mark

Miten limit-operaatiota käytetään Stream API:ssa?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 4. Luku 3

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

bookStream-rajapinta Javassa

Pyyhkäise näyttääksesi valikon

Java-kielessä on useita tapoja käsitellä dataa – silmukat, metodit ja erilaiset algoritmit. Kuitenkin Java 8:ssa esiteltiin erittäin tehokas työkalu – Stream API.

Yksinkertaisesti sanottuna Stream API mahdollistaa tietovirran käsittelyn nopeasti ja helposti. Tässä yhteydessä tietovirta edustaa kokoelmia. Stream API:lla on useita käsitteitä. Tässä ovat tärkeimmät.

Keskeiset käsitteet

  • Stream: edustaa tietoelementtien jonoa, jota voidaan käsitellä;

  • Välioperaatiot: operaatiot, jotka luovat uuden streamin suorituksen jälkeen. Esimerkkejä: filter, map, distinct, sorted;

  • Pääteoperaatiot: operaatiot, jotka viimeistelevät streamin käsittelyn ja palauttavat tuloksen. Esimerkkejä: collect, forEach, count, reduce;

  • Rinnakkaiset streamit: mahdollistavat datan rinnakkaisen käsittelyn. Menetelmiä parallel() ja parallelStream() käytetään rinnakkaisten streamien luomiseen.

Riittävästi teoriaa, nyt siirrytään koodaukseen!

Virran (stream) luominen tapahtuu käyttämällä metodia kokoelmassa, jonka haluat muuntaa virraksi:

Main.java

Main.java

copy
12
List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream();

stream()-metodilla saadaan merkkijonojen virta. Jotta voimme työskennellä virran kanssa, on ymmärrettävä, mitä lambda-lausekkeet ovat, sillä virran metodit toimivat pääasiassa niiden avulla.

Lambda-lausekkeet

Lambda-lausekkeet otettiin käyttöön Java 8:ssa, ja ne edustavat yksinkertaistettua tapaa luoda anonyymejä funktioita Javassa. Emme ole aiemmin käsitelleet anonyymejä funktioita, koska ne eivät ole olleet erityisen tarpeellisia, mutta nyt tutustumme niihin lambda-lausekkeiden kautta.

Lambda-lausekkeen syntaksi:

Yleinen syntaksi lambda-lausekkeille Javassa näyttää tältä:

Example.java

Example.java

copy
123
(parameters) -> expression // or (parameters) -> { statements; }
  • Parametrit: tämä on parametrilista, joka voi olla tyhjä tai sisältää yhden tai useamman parametrin;

  • Nuoli: esitetään symbolilla ->, joka erottaa parametrit lambda-lausekkeen rungosta;

  • Lauseke tai lauseet: tämä on funktion runko, joka sisältää lausekkeen tai lohkon lauseita.

Tässä on esimerkki lambda-lausekkeesta, joka kuvaa yksinkertaista funktiota, joka laskee yhteen kaksi lukua:

Example.java

Example.java

copy
12345678910
// Traditional way MathOperation addition = new MathOperation() { @Override public int operate(int a, int b) { return a + b; } }; // Using a lambda expression MathOperation addition = (int a, int b) -> a + b;

Tarkastellaan tarkemmin, mitä yllä olevassa koodissa tapahtuu ja miten lambda-lausekkeita käytetään:

Main.java

Main.java

copy
1234567891011121314
package com.example; // Functional interface with a single abstract method interface MyMathOperation { int operate(int a, int b); } public class Main { public static void main(String[] args) { // Using a lambda expression to implement the interface MyMathOperation addition = (a, b) -> a + b; System.out.println("Sum: " + addition.operate(5, 3)); } }

Yllä olevassa koodissa:

Luotu funktionaalinen rajapinta MyMathOperation, jossa on yksi abstrakti metodi operate.

Käytetty lambda-lauseketta tämän metodin toteuttamiseen, suorittaen kahden luvun yhteenlaskun.

Tulostettu yhteenlaskun tulos.

On ymmärrettävää, että tämän koodin toiminnan hahmottaminen voi olla haastavaa tässä vaiheessa, mutta palataan takaisin Stream API:in pariin, jossa lambda-lausekkeita käytetään usein, ja pyritään ymmärtämään niiden käyttöä käytännössä.

Kuten aiemmin, loimme merkkijonovirran merkkijonolistasta. Nyt käytetään stream-metodeja jokaisen merkkijonon muuttamiseksi isoiksi kirjaimiksi tässä virrassa:

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); stream.map(e -> e.toUpperCase()).toList(); } }

Yllä olevassa koodissa käytettiin lambda-lauseketta ja kahta metodia: map() ja toList(). Jos on selvää, mitä toList()-metodi tekee, map()-metodi muuttaa jokaisen virran alkion annetun lambda-lausekkeen mukaisesti.

Tarkastellaan tarkemmin, miten lambda-lauseke toimii tässä:

map()-metodi käyttää toUpperCase()-metodia jokaiselle virran alkiolle. Määrittelimme tämän virran alkion nimellä e ja lambda-lausekkeen avulla ohjeistimme ohjelmaa soveltamaan tätä metodia jokaiseen alkioon.

Tämä ei kuitenkaan ole vielä lopullinen vaihe, koska käytimme välioperaatiota. Tämä tarkoittaa, että operaatiot virralla eivät ole vielä valmiit. Jotta työ virran kanssa saadaan päätökseen, täytyy käyttää pääteoperaatiota, joka viimeistelee operaatiot virralla ja palauttaa tietyn arvon. Esimerkiksi voit käyttää toList()-metodia, jolloin muokattu virta muunnetaan listaksi.

Esimerkiksi:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("a", "b", "c"); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.toUpperCase()).toList(); System.out.println(list); } }

Tarkastellaan tarkemmin mahdollisia välioperaatioita streamissa.

Välioperaatiot

map()-metodi – olet jo tutustunut tähän metodiin; se suorittaa lambda-lausekkeessa määritellyt toiminnot jokaiselle streamin alkiolle.

Esimerkiksi käytetään substring()-metodia jokaiselle merkkijonovirran alkiolle:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

filter()-metodi ottaa lambda-lausekkeen, jossa on ehto, jonka perusteella virtaa suodatetaan. Toisin sanoen, kaikki ehdon täyttävät alkiot jäävät virtaan, ja alkiot, jotka eivät täytä ehtoa, poistetaan virrasta. Muokataan virtaa niin, että siihen jäävät vain ne alkiot, joiden pituus on suurempi kuin 5:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); Stream<String> stream = strings.stream(); stream = stream.filter(e -> e.length() > 5); List<String> list = stream.map(e -> e.substring(1, 4)).toList(); System.out.println("Modified list: " + list); } }

filter()-menetelmällä poistetaan merkkijono "with" virrasta, koska tämä sana on alle 5 merkkiä pitkä.

Voit myös käyttää välimuotoisia operaatioita useita kertoja peräkkäin.

Esimerkiksi voimme hieman yksinkertaistaa yllä olevaa koodia:

Main.java

Main.java

copy
12345678910111213141516
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> strings = Arrays.asList("Unlock", "Infinity", "with", "Codefinity"); System.out.println("List of strings: " + strings); List<String> list = strings.stream() .filter(e -> e.length() > 5) .map(e -> e.substring(1, 4)) .toList(); System.out.println("Modified list: " + list); } }

Kun ketjutat useita stream-menetelmiä yhteen, on suositeltavaa sijoittaa jokainen menetelmä uudelle riville, jotta koodin luettavuus paranee huomattavasti.

Metodi flatMap() muuntaa jokaisen virran alkion uudeksi virraksi ja yhdistää tulokset yhdeksi virraksi. Toisin sanoen, tämän metodin avulla voimme jakaa virran useisiin virtoihin, jotka yhdistetään lopuksi yhdeksi virraksi. Esimerkiksi, jos sinulla on lista merkkijonoja, joissa jokaisessa voi olla useampi kuin yksi sana, kuten lista etu- ja sukunimistä. Ja sinun täytyy muuttaa jokaisen sanan ensimmäinen kirjain isoksi:

Main.java

Main.java

copy
123456789101112131415161718192021222324
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

Yllä olevassa koodissa kirjoitimme erillisen yksityisen metodin, joka muuttaa sanan ensimmäisen kirjaimen isoksi, ja käytimme tätä metodia map()-metodin kanssa yhdessä lambda-lausekkeen kanssa.

Huomaa, että käyttämällä flatMap-metodia jaoimme jokaisen virran alkion eri virroiksi käyttämällä Arrays.stream(e.split(" ")) -metodia. Koska split()-metodi palauttaa taulukon, meidän täytyy käyttää Arrays.stream()-metodia muuttaaksemme tämän taulukon virroiksi.

Tämän jälkeen kaikki nämä virrat yhdistetään yhdeksi virraksi, minkä jälkeen käytämme kirjoittamaamme metodia. Nyt meillä on kaikkien käyttäjien nimet ja sukunimet, joiden ensimmäinen kirjain on iso.

Tiedätkö mikä olisi hienoa? Jos laittaisimme nämä nimet ja sukunimet HashMap-rakenteeseen, jossa avain on sukunimi ja arvo on etunimi.

Toteutetaan tämä koodissa:

Main.java

Main.java

copy
12345678910111213141516171819202122232425262728293031323334
package com.example; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { List<String> users = Arrays.asList("Ethan Johnson", "Olivia smith", "mason davis", "Ava taylor", "logan brown", "Emma Anderson", "jackson miller"); System.out.println("List of users: " + users); List<String> list = users.stream() .flatMap(e -> Arrays.stream(e.split(" "))) .map(e -> capitalizeFirstLetter(e)) .toList(); System.out.println("List with capitalized names and surnames: " + list); Map<String, String> usersKeyValue = new HashMap<>(); for (int i = 0; i < list.size() - 1; i+=2) { String name = list.get(i); String surname = list.get(i + 1); usersKeyValue.put(surname, name); } System.out.println("Map with surnames as keys and names as values: " + usersKeyValue); } private static String capitalizeFirstLetter(String word) { if (word == null || word.isEmpty()) { return word; } return Character.toUpperCase(word.charAt(0)) + word.substring(1); } }

Yksinkertaisella silmukalla tallensimme etunimen ja sukunimen muuttujiin ja sitten map-rakenteeseen. Huomaa, miten silmukka toimii. Kasvatamme muuttujaa i aina kahdella jokaisella iteraatiolla, koska meidän täytyy ohittaa sukunimi, kun olemme jo tallentaneet sen.

  • distinct()-metodi poistaa duplikaatit streamista. Yleisesti tämä on hyödyllistä, jos tarvitset uniikkeja alkioita streamissa tai haluat poistaa duplikaatit listasta nopeasti. Tämän voi helposti toteuttaa seuraavalla rakenteella:
list.stream().distinct().toList()
  • sorted-metodi järjestää kaikki streamin alkiot luonnolliseen järjestykseen, pienimmästä suurimpaan tai aakkosjärjestykseen. Tämä on hyödyllistä, jos tarvitset järjestetyn streamin tai haluat nopeasti lajitella listan;

  • skip(n)-metodi ohittaa streamin ensimmäiset n alkiota. Tämä voi olla hyödyllistä työskenneltäessä tekstitiedostojen kanssa, joissa ensimmäiset n riviä voivat olla esimerkiksi metadataa tai tiedoston kuvaus. On myös mainitsemisen arvoinen limit(n)-metodi, joka yleisesti rajoittaa streamin alkioiden määrää. Vaikka loisimme streamin, jossa on 1000 alkiota ja käyttäisimme sitten limit(200), stream sisältää vain ensimmäiset 200 alkiota.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example = example.stream().skip(3).limit(5).toList(); System.out.println("List: " + example); } }

Nämä ovat tärkeimmät välimetodit, joita tarvitset. Voit tutustua muihin metodeihin viittaamalla linkki viralliseen Java-dokumentaatioon. Siirrytään seuraavaksi päätemetodeihin.

Päätemetodit

  • Tunnetuin päätemetodi on toList(). Se muuntaa streamin listaksi ja palauttaa sen. Toisin sanoen voit suoraan liittää tämän streamin metodeineen listaan. Tämä metodi esiteltiin Java 17 -versiossa ja korvaa monimutkaisemman rakenteen collect(Collectors.toList());

  • collect()-metodi muuntaa myös streamin tiettyyn tietorakenteeseen. Se käyttää parametrina Collectors-rajapinnan metodia. Tämä rajapinta sisältää metodeja kuten toList(), toSet() ja toCollection(). Esimerkiksi:

Main.java

Main.java

copy
123456789101112131415
package com.example; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Set<Integer> integerSet = example.stream().collect(Collectors.toSet()); System.out.println("List: " + example); System.out.println("Set: " + integerSet); } }

forEach()-metodi ottaa lambda-lausekkeen ja suorittaa tietyn toiminnon jokaiselle virran alkiolle.

Esimerkiksi:

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> example = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); example.stream().forEach(e -> System.out.println(e + 1)); } }

Ero tämän menetelmän ja map-menetelmän välillä on, että tämä menetelmä on päätemenetelmä ja sen jälkeen et voi kutsua muita menetelmiä.

Nämä ovat kaikki perusmenetelmät virtojen käsittelyyn. Tämä on monimutkainen aihe, eikä sitä välttämättä ymmärrä heti. Kuitenkin kyseessä on aihe, joka opitaan harjoittelemalla. Tulevissa harjoitusluvuissa virtojen kanssa saat runsaasti mahdollisuuksia työskennellä niiden parissa, sillä se on erittäin kätevä ja käytännöllinen tapa käsitellä listoja ja taulukoita!

1. Mikä on Stream API:n ensisijainen tarkoitus Javassa?

2. Mikä seuraavista on päätemenetelmä Stream API:ssa?

3. Mitä map-operaatio tekee Stream API:ssa?

4. Miten flatMap-operaatio eroaa map-operaatiosta Stream API:ssa?

5. Mitä filter-operaatio tekee Stream API:ssa?

6. Mikä on forEach-operaation tarkoitus Stream API:ssa?

7. Mikä seuraavista on välivaiheen operaatio Stream API:ssa?

8. Miten limit-operaatiota käytetään Stream API:ssa?

question mark

Mikä on Stream API:n ensisijainen tarkoitus Javassa?

Select the correct answer

question mark

Mikä seuraavista on päätemenetelmä Stream API:ssa?

Select the correct answer

question mark

Mitä map-operaatio tekee Stream API:ssa?

Select the correct answer

question mark

Miten flatMap-operaatio eroaa map-operaatiosta Stream API:ssa?

Select the correct answer

question mark

Mitä filter-operaatio tekee Stream API:ssa?

Select the correct answer

question mark

Mikä on forEach-operaation tarkoitus Stream API:ssa?

Select the correct answer

question mark

Mikä seuraavista on välivaiheen operaatio Stream API:ssa?

Select the correct answer

question mark

Miten limit-operaatiota käytetään Stream API:ssa?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 4. Luku 3
some-alt