Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Periaatteet | Stream API:n Perusteet ja Toiminnalliset Ominaisuudet
Stream API

bookPeriaatteet

Stream API:n toimintaperiaatteet perustuvat funktionaalisen ohjelmoinnin ja laiskan arvioinnin keskeisiin käsitteisiin. Tarkastellaan Stream API:n tärkeimpiä periaatteita.

Laiska arviointi

Yksi Stream API:n keskeisistä periaatteista on laiska arviointi.

Tämä tarkoittaa, että välioperaatioita kuten filter() tai map() ei suoriteta välittömästi. Ne muodostavat vain toimintojen ketjun, joka suoritetaan vasta, kun kutsutaan pääteoperaatio, kuten collect() tai forEach().

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }

Tämä koodi luo virran merkkijonolistasta, suodattaa alkiot säilyttäen vain ne, jotka alkavat kirjaimella A, ja laskee, kuinka moni täyttää ehdon. Tulos (1) tulostetaan, koska vain Alice täyttää ehdon.

Funktionaalinen ohjelmointityyli

Stream API hyödyntää lambda-lausekkeita ja funktionaalisia rajapintoja datan käsittelyyn. Imperatiivisen silmukoihin perustuvan lähestymistavan sijaan kuvataan, mitä datalla halutaan tehdä:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }

Tämä koodi luo virran hedelmälistasta, muuntaa merkkijonot isoiksi kirjaimiksi käyttäen map():ia ja ohittaa kolme ensimmäistä alkiota skip():n avulla. Tulos kerätään uuteen listaan ja tulostetaan alkaen neljännestä alkiosta.

Datan muuttumattomuus

Stream API ei muuta alkuperäistä dataa. Kaikki operaatiot luovat uuden virran tai palauttavat tuloksen muuttamatta kokoelmaa tai taulukkoa. Tämä parantaa datan turvallisuutta ja estää odottamattomat sivuvaikutukset.

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }

Stream API suodattaa listan nimet luodakseen uuden virran, updateNames, joka sisältää vain ne alkiot, jotka alkavat kirjaimella A. Alkuperäinen listan nimet kuitenkin säilyy muuttumattomana, sillä Stream API ei muokkaa dataa suoraan, mikä varmistaa datan turvallisuuden ja estää sivuvaikutukset.

Virrat ovat kertakäyttöisiä

Virtaa voidaan käyttää vain yhden kerran. Kun pääteoperaatio on suoritettu, virta ei ole enää käytettävissä jatkokäsittelyyn.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }

Tässä luodaan virta merkkijonolistasta ja tulostetaan jokainen alkio konsoliin. Kun virtaa on käytetty ensimmäisen kerran, sitä ei voi käyttää uudelleen, mikä aiheuttaa virheen, jos yrität kutsua forEach() uudelleen.

Rinnakkaiskäsittely

Stream API tukee rinnakkaisvirtoja, mikä mahdollistaa nopeamman datan käsittelyn moniydinkoneilla. Tätä käsitellään tarkemmin täällä

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }

Tämä koodi luo rinnakkaisvirran lukulistasta ja tulostaa jokaisen alkion konsoliin. Käyttämällä parallelStream() mahdollistetaan listan alkioiden rinnakkaiskäsittely, mikä voi nopeuttaa suoritusta suurten datan määrien kanssa.

Koodin selkeys ja luettavuus

Stream API:n käyttö tekee koodista deklaratiivisempaa. Sen sijaan, että kuvailisit miten tehtävä suoritetaan (esimerkiksi käyttämällä silmukoita), määrittelet mitä tarkalleen täytyy tehdä. Tämä parantaa luettavuutta ja yksinkertaistaa koodin ylläpitoa.

Esimerkki silmukalla:

List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
    System.out.println(name);
}

Esimerkki Stream API:sta:

List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);

Ensimmäisessä silmukkaesimerkissä kuvataan tarkasti, miten listaa käydään läpi ja tulostetaan elementit, kun taas toisessa esimerkissä, jossa käytetään Stream API:a, määritellään vain mitä tulee tehdä: käydä läpi elementit ja tulostaa ne. Tämä tekee koodista deklaratiivisempaa ja luettavampaa.

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 1. Luku 2

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

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

Awesome!

Completion rate improved to 2.33

bookPeriaatteet

Pyyhkäise näyttääksesi valikon

Stream API:n toimintaperiaatteet perustuvat funktionaalisen ohjelmoinnin ja laiskan arvioinnin keskeisiin käsitteisiin. Tarkastellaan Stream API:n tärkeimpiä periaatteita.

Laiska arviointi

Yksi Stream API:n keskeisistä periaatteista on laiska arviointi.

Tämä tarkoittaa, että välioperaatioita kuten filter() tai map() ei suoriteta välittömästi. Ne muodostavat vain toimintojen ketjun, joka suoritetaan vasta, kun kutsutaan pääteoperaatio, kuten collect() tai forEach().

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); long count = names.stream() .filter(name -> name.startsWith("A")) // Forming the operation .count(); // Triggering execution System.out.println(count); // Output: 1 } }

Tämä koodi luo virran merkkijonolistasta, suodattaa alkiot säilyttäen vain ne, jotka alkavat kirjaimella A, ja laskee, kuinka moni täyttää ehdon. Tulos (1) tulostetaan, koska vain Alice täyttää ehdon.

Funktionaalinen ohjelmointityyli

Stream API hyödyntää lambda-lausekkeita ja funktionaalisia rajapintoja datan käsittelyyn. Imperatiivisen silmukoihin perustuvan lähestymistavan sijaan kuvataan, mitä datalla halutaan tehdä:

Main.java

Main.java

copy
1234567891011121314
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "blueberry"); List<String> result = fruits.stream() .map(String::toUpperCase) // Convert all strings to uppercase .skip(3) .toList(); // Collect the result into a new list System.out.println(result); } }

Tämä koodi luo virran hedelmälistasta, muuntaa merkkijonot isoiksi kirjaimiksi käyttäen map():ia ja ohittaa kolme ensimmäistä alkiota skip():n avulla. Tulos kerätään uuteen listaan ja tulostetaan alkaen neljännestä alkiosta.

Datan muuttumattomuus

Stream API ei muuta alkuperäistä dataa. Kaikki operaatiot luovat uuden virran tai palauttavat tuloksen muuttamatta kokoelmaa tai taulukkoa. Tämä parantaa datan turvallisuutta ja estää odottamattomat sivuvaikutukset.

Main.java

Main.java

copy
12345678910111213
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<String> names = List.of("Alice", "Bob", "Charlie"); List<String> updateNames = names.stream() .filter(name -> name.startsWith("A")) .toList(); System.out.println(names); // Output: [Alice, Bob, Charlie] } }

Stream API suodattaa listan nimet luodakseen uuden virran, updateNames, joka sisältää vain ne alkiot, jotka alkavat kirjaimella A. Alkuperäinen listan nimet kuitenkin säilyy muuttumattomana, sillä Stream API ei muokkaa dataa suoraan, mikä varmistaa datan turvallisuuden ja estää sivuvaikutukset.

Virrat ovat kertakäyttöisiä

Virtaa voidaan käyttää vain yhden kerran. Kun pääteoperaatio on suoritettu, virta ei ole enää käytettävissä jatkokäsittelyyn.

Main.java

Main.java

copy
123456789101112
package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { Stream<String> stream = List.of("Alice", "Bob").stream(); stream.forEach(System.out::println); stream.forEach(System.out::println); // Error: Stream has already been used } }

Tässä luodaan virta merkkijonolistasta ja tulostetaan jokainen alkio konsoliin. Kun virtaa on käytetty ensimmäisen kerran, sitä ei voi käyttää uudelleen, mikä aiheuttaa virheen, jos yrität kutsua forEach() uudelleen.

Rinnakkaiskäsittely

Stream API tukee rinnakkaisvirtoja, mikä mahdollistaa nopeamman datan käsittelyn moniydinkoneilla. Tätä käsitellään tarkemmin täällä

Main.java

Main.java

copy
1234567891011
package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Integer> numbers = List.of(1, 2, 3, 4, 5); numbers.parallelStream() .forEach(System.out::println); // Elements are processed in parallel } }

Tämä koodi luo rinnakkaisvirran lukulistasta ja tulostaa jokaisen alkion konsoliin. Käyttämällä parallelStream() mahdollistetaan listan alkioiden rinnakkaiskäsittely, mikä voi nopeuttaa suoritusta suurten datan määrien kanssa.

Koodin selkeys ja luettavuus

Stream API:n käyttö tekee koodista deklaratiivisempaa. Sen sijaan, että kuvailisit miten tehtävä suoritetaan (esimerkiksi käyttämällä silmukoita), määrittelet mitä tarkalleen täytyy tehdä. Tämä parantaa luettavuutta ja yksinkertaistaa koodin ylläpitoa.

Esimerkki silmukalla:

List<String> names = List.of("Alice", "Bob", "Charlie");
for (String name : names) {
    System.out.println(name);
}

Esimerkki Stream API:sta:

List<String> names = List.of("Alice", "Bob", "Charlie");
names.stream().forEach(System.out::println);

Ensimmäisessä silmukkaesimerkissä kuvataan tarkasti, miten listaa käydään läpi ja tulostetaan elementit, kun taas toisessa esimerkissä, jossa käytetään Stream API:a, määritellään vain mitä tulee tehdä: käydä läpi elementit ja tulostaa ne. Tämä tekee koodista deklaratiivisempaa ja luettavampaa.

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 1. Luku 2
some-alt