{"id":98,"date":"2017-08-17T18:59:07","date_gmt":"2017-08-17T16:59:07","guid":{"rendered":""},"modified":"2018-11-05T19:52:27","modified_gmt":"2018-11-05T18:52:27","slug":"java-8-streamy","status":"publish","type":"post","link":"https:\/\/spireng.sk\/en\/java-8-streamy\/","title":{"rendered":"Java 8: Streamy"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"imgp_img\" style=\"float: left; margin: 2px 5px;\" src=\"\/sites\/default\/files\/imagepicker\/1\/cxz687gf.png\" alt=\"Obr\u00e1zok\" width=\"217\" height=\"232\" \/>Ak by ste sa p\u00fdtali, ak\u00e9 s\u00fa najv\u00e4\u010d\u0161ie novinky v Jave 8, tak odpove\u010f bude jednozna\u010dne, \u017ee Lambda v\u00fdrazy (referencie na met\u00f3dy) a Streamy. O tom prvom som u\u017e p\u00edsal tu a <a href=\"http:\/\/spireng.sk\/en\/java-8-lambda\/\">tu<\/a>. O tom druhom si povieme teraz. Streamy s\u00fa nov\u00fd sp\u00f4sob ako pracova\u0165 s mno\u017einami \u00fadajov. A podobne ako Lambda v\u00fdrazy, aj oni tak trochu pos\u00favaj\u00fa Javu do sveta funkcion\u00e1lnych jazykov.<!--more--><!--break--><\/p>\n<p>Streamy predstavuj\u00fa nov\u00fd pr\u00edstup k spracovaniu \u00fadajov. Na prv\u00fd poh\u013ead by sa mohlo zda\u0165, \u017ee je to len \u010fal\u0161ia forma kolekci\u00ed, ale ich implement\u00e1cia je z\u00e1sadne in\u00e1 a v\u010faka tomu maj\u00fa nieko\u013eko v\u00fdrazne in\u00fdch vlastnost\u00ed. Streamy sa daj\u00fa charakterizova\u0165 troma vlastnos\u0165ami:<\/p>\n<ul>\n<li><strong>deklarat\u00edvnos\u0165<\/strong> \u2013 pr\u00e1ca s nimi pripom\u00edna viac deklarat\u00edvne jazyky (napr. SQL), kde hovor\u00edte k\u00f3dom, \u010do chcete dosta\u0165 a nie ako to dosiahnu\u0165<\/li>\n<li><strong>komponovate\u013enos\u0165<\/strong> \u2013 spracovanie streamu (ako si o chv\u00ed\u013eu uk\u00e1\u017eeme) je s\u00e9ria oper\u00e1ci\u00ed, ktor\u00e9 sa daj\u00fa jednoducho radi\u0165 jedna k druhej<\/li>\n<li><strong>paralelizmus<\/strong> \u2013 od sekven\u010dn\u00e9ho spracovania streamu k paraleln\u00e9mu sa d\u00e1 dosta\u0165 ve\u013emi jednoducho. Streamy s\u00fa budovan\u00e9 tak, aby paralelizmus bol \u00faplne transparentn\u00fd.<\/li>\n<\/ul>\n<p>Aby tej te\u00f3rie nebolo pr\u00edli\u0161, po\u010fme si uk\u00e1za\u0165 jednoduch\u00fd pr\u00edklad. M\u00e1me zoznam mien, z ktor\u00e9ho chceme z\u00edska\u0165 d\u013a\u017eky jednotliv\u00fdch polo\u017eiek a pre tie, \u010do maj\u00fa viac ako 5 znakov, vyp\u00edsa\u0165 ich d\u013a\u017eku:<\/p>\n<pre style=\"padding-left: 30px;\"> List&lt;String&gt; names = new ArrayList&lt;&gt;();\r\n names.add(\"Lubomir\");\r\n names.add(\"Ivana\");\r\n names.add(\"Jan\");\r\n names.add(\"Ludmila\");\r\n List&lt;Integer&gt; filterNames = names.stream()\r\n   .map(String::length)\r\n   .filter(nameLength -&gt; nameLength &gt; 5)\r\n   .collect(Collectors.toList());\r\n filterNames.forEach(value -&gt; System.out.println(value));<\/pre>\n<p>Prv\u00fdch p\u00e4\u0165 riadkov je klasika. Len definujeme pole a nap\u013a\u0148ame ho \u00fadajmi. Zauj\u00edmav\u00e9 to za\u010dne by\u0165 a\u017e volan\u00edm <em>names.stream()<\/em><span style=\"font-style: normal;\">. To je moment, kedy sa zo sveta klasick\u00fdch kolekci<\/span><span style=\"font-style: normal;\">\u00ed<\/span><span style=\"font-style: normal;\"> dost\u00e1vame do sveta streamov. V\u00fdsledkom tohto volania je stream, ktor\u00fd n\u00e1sledne nech\u00e1me spracova\u0165 s\u00e9riou oper\u00e1ci<\/span><span style=\"font-style: normal;\">\u00ed<\/span><span style=\"font-style: normal;\">. Najprv re\u0165azce prekonvertujeme na ich d\u013a\u017eky a n\u00e1sledne nech\u00e1me cez filter prejs\u0165 len tie, ktor\u00e9 maj\u00fa viac ako 5 znakov. Na z\u00e1ver z polo\u017eiek, ktor\u00e9 ostali v streame, zostav\u00edme nov\u00fd zoznam. Ten potom vyp\u00ed\u0161eme do konzoly.<\/span><\/p>\n<p>Toto je kr\u00e1tka uk\u00e1\u017eka toho, ako sa d\u00e1 so streamami pracova\u0165. Po\u010fme ale pekne po poriadku. Ako vieme stream vytvori\u0165?<\/p>\n<ul>\n<li>zo zoznamu hodn\u00f4t: <em>Stream.of(\u201eJan\u201c, \u201eFrantisek\u201c, \u201eMartin\u201c);<\/em><\/li>\n<li>z po\u013ea: <em>Arrays.Stream(pole);<\/em><\/li>\n<li>zo s\u00faboru: <em>Files.lines(cesta_k_suboru);<\/em><\/li>\n<li>generovan\u00edm: <em>Stream.generate(Math::<\/em><em>r<\/em><em>andom);<\/em><\/li>\n<li>iterat\u00edvnym volan\u00edm met\u00f3dy: <em>Stream.iterate(0, n -&gt; n+2);<\/em><\/li>\n<\/ul>\n<p>Stream m\u00e1me vytvoren\u00fd, \u010do sa s n\u00edm d\u00e1 robi\u0165? Oper\u00e1cie, ktor\u00e9 stream podporuje, sa delia do dvoch kateg\u00f3ri\u00ed:<\/p>\n<ol>\n<li>prechodn\u00e9 (alebo tranzitn\u00e9) \u2013 vracaj\u00fa op\u00e4\u0165 objekt stream, tak\u017ee je k n\u00edm mo\u017en\u00e9 pripoji\u0165 \u010fal\u0161ie oper\u00e1cie streamu<\/li>\n<li>kone\u010dn\u00e9 \u2013 vracaj\u00fa in\u00fd objekt ako stream, tak\u017ee ukon\u010duj\u00fa spracovanie streamu<\/li>\n<\/ol>\n<p><span style=\"font-style: normal;\">V na\u0161om pr\u00edklade boli met\u00f3dy <\/span><em>map<\/em><span style=\"font-style: normal;\"> a <\/span><em>filter<\/em><span style=\"font-style: normal;\"> prechodn\u00e9 met\u00f3dy a met\u00f3da <\/span><em>collect<\/em><span style=\"font-style: normal;\"> kone\u010dn\u00e1. <\/span><span style=\"font-style: normal;\">Takto vyzer\u00e1 zoznam prechodn\u00fdch funkci<\/span><span style=\"font-style: normal;\">\u00ed<\/span><span style=\"font-style: normal;\">:<\/span><\/p>\n<ul>\n<li><em>filter<\/em> \u2013 v streame \u010falej pokra\u010duj\u00fa len objekty, ktor\u00e9 splnia predik\u00e1t<\/li>\n<li><em><span style=\"text-decoration: none;\">distinct<\/span><\/em> \u2013 v streme bud\u00fa u\u017e len jedine\u010dn\u00e9 hodnoty<\/li>\n<li><em>limit(n)<\/em> \u2013 v streame ostane len prv\u00fdch n prvkov<\/li>\n<li><em>skip(n)<\/em> \u2013 prv\u00fdch n prvkov je zo streamu vyl\u00fa\u010den\u00fdch<\/li>\n<li><em>map<\/em> \u2013 vykon\u00e1 nejak\u00fa oper\u00e1ciu nad ka\u017ed\u00fdm prvkom. V\u00fdsledok tej oper\u00e1cie m\u00f4\u017ee by\u0165 aj prvok in\u00e9ho typu.<\/li>\n<li><em>flatMap<\/em> \u2013 to ist\u00e9 ako predch\u00e1dzaj\u00faci pr\u00edpad, ale ak je v\u00fdsledok oper\u00e1cie pole, tak nedostanem stream pol\u00ed, ale stream prvkov (namiesto streamu pol\u00ed len stream prvok v\u0161etk\u00fdch pol\u00ed)<\/li>\n<li><em>sorted<\/em><span style=\"font-style: normal;\"> \u2013 <\/span><span style=\"font-style: normal;\">usporiadanie streamu (stream \u0161ta<\/span><span style=\"font-style: normal;\">n<\/span><span style=\"font-style: normal;\">dardne zachov\u00e1va poradie od vytvorenia a\u017e po koniec spracovania)<\/span><\/li>\n<\/ul>\n<p><span style=\"font-style: normal;\">A takto vyzer\u00e1 zoznam ko<\/span><span style=\"font-style: normal;\">n<\/span><span style=\"font-style: normal;\">e<\/span><span style=\"font-style: normal;\">\u010d<\/span><span style=\"font-style: normal;\">n\u00fdch met\u00f3d:<\/span><\/p>\n<ul>\n<li><em>forEach<\/em> \u2013 vykon\u00e1 oper\u00e1cie nad ka\u017ed\u00fdm prvkom (n\u00e1vratovou hodnotou je void)<\/li>\n<li><em>collect<\/em> \u2013 zo streamu vytvor\u00ed kolekciu pod\u013ea zadan\u00e9ho kolektora<\/li>\n<li><em>allMatch<\/em> \u2013 vr\u00e1ti true, ak v\u0161etky prvky v streame sp\u013a\u0148aj\u00fa podmienku<\/li>\n<li><em>noneMatch<\/em> \u2013 vr\u00e1ti true, ak ani jeden prvok v streame nesp\u013a\u0148a podmienku<\/li>\n<li><em>anyMatch<\/em> \u2013 vr\u00e1ti true, ak aspo\u0148 jeden prvok v streame sp\u013a\u0148a podmienku<\/li>\n<li><em>findAny<\/em> \u2013 vr\u00e1ti n\u00e1hodn\u00fd prvok zo streamu vo forme Optional objektu<\/li>\n<li><em>findFirst<\/em> \u2013 vr\u00e1ti prv\u00fd prvok zo streamu vo forme Optional objektu<\/li>\n<li><em>count<\/em> \u2013 vr\u00e1ti po\u010det prvok v streame<\/li>\n<li><em>reduce<\/em> \u2013 zredukuje stream na jednu hodnotu pod\u013ea zadanej oper\u00e1cie<\/li>\n<\/ul>\n<p><span style=\"font-style: normal;\">Variabilita pr\u00e1ce so strea<\/span><span style=\"font-style: normal;\">ma<\/span><span style=\"font-style: normal;\">mi je naozaj ve\u013ek\u00e1.<\/span><span style=\"font-style: normal;\"> Sta\u010d\u00ed kombinova\u0165 r\u00f4zne prechodn\u00e9 <\/span><span style=\"font-style: normal;\">funkcie <\/span><span style=\"font-style: normal;\">a ukon\u010di\u0165 spr\u00e1vnou kone\u010dnou funkciou. Napr. kone\u010dn\u00e1 met\u00f3da reduce je celkom zauj\u00edmav\u00e1, preto\u017ee zredukuje pole do jednej hodnoty pod\u013ea nejakej oper\u00e1cie. Sta\u010d\u00ed jej teda doda\u0165 oper\u00e1ciu, ktor\u00e9 z dvoch hodn\u00f4t rob\u00ed jednu a ona v\u00e1m zo streamu vyrob\u00ed nakoniec len jednu hodnotu (spolu s oper\u00e1ci<\/span><span style=\"font-style: normal;\">o<\/span><span style=\"font-style: normal;\">u map tvoria zn\u00e1me duo z map-reduce algoritmu). Napr. pod\u013ea oper\u00e1ci<\/span><span style=\"font-style: normal;\">\u00ed<\/span><span style=\"font-style: normal;\"> Math.max alebo Math.min:<\/span><\/p>\n<pre>Optional&lt;Integer&gt; minValue = list.stream().reduce(Math::max);\r\nOptional&lt;Integer&gt; maxValue = list.stream().reduce(Math::min);<\/pre>\n<p>Toto v\u0161etko je len \u00favod do oblasti streamov. Nespomenul som, \u017ee existuj\u00fa aj typov\u00e9 streamy: <em>IntStream<\/em>, <em>DoubleStream<\/em> a <em>LongStream<\/em>. Tieto nie len \u0161etria energiu a \u010das t\u00fdm, \u017ee nerobia boxing a unboxing nad prvkami, ale poskytuj\u00fa tie\u017e oper\u00e1cie relevantn\u00e9 dan\u00fdm typom. Nespomenul som tie\u017e, \u017ee sa d\u00e1 implementova\u0165 vlastn\u00fd Collector (trieda, ktor\u00fa potrebuje collect met\u00f3da), alebo \u017ee sa prvky v streame daj\u00fa zoskupova\u0165 na z\u00e1klade definovanej oper\u00e1cie. A tie\u017e som nespomenul, \u017ee medzi oby\u010dajn\u00fdm streamom a paral\u00e9lnym je len tak\u00fdto mal\u00fd rozdiel vo vytvoren\u00ed:<\/p>\n<pre>Optional&lt;Integer&gt; max = list.parallelStream().reduce(Math::max);<\/pre>\n<p><span style=\"font-style: normal;\">Nevol\u00e1m teda met\u00f3du <\/span><em>stream<\/em><span style=\"font-style: normal;\"> ale <\/span><em>parallelStream<\/em><span style=\"font-style: normal;\">. V\u00fdsledok je, \u017ee oper\u00e1cie sa m\u00f4\u017eu v streame vykon\u00e1va\u0165 paralelne. <\/span><span style=\"font-style: normal;\">Ale to, \u010di sa to nakoniec udeje, je z\u00e1visl\u00e9 od toho, ak\u00e9 oper\u00e1cie sa so stream bud\u00fa vykon\u00e1va\u0165.<\/span><\/p>\n<p>T\u00e9ma streamov je naozaj \u0161irok\u00e1 a pokojne by zaplnila nieko\u013eko tak\u00fdchto \u010dl\u00e1nkov. \u00da\u010delom tohto bolo uk\u00e1za\u0165, \u017ee je to t\u00e9ma nanajv\u00fd\u0161 zauj\u00edmav\u00e1. Z\u00e1sadn\u00e9 je uvedomi\u0165 si, \u017ee stream nie je nov\u00fd druh kolekcie. Je objekt s \u00faplne novou filozofiou, vn\u00fatornou implement\u00e1ciou, a teda aj mo\u017enos\u0165ami. Je to ka\u017edop\u00e1dne n\u00e1stroj, ktor\u00fd m\u00e1 ur\u010dite svoje scen\u00e1re pou\u017eitia, v ktor\u00fdch je lep\u0161\u00ed ako \u010doko\u013evek in\u00e9.<\/p>","protected":false},"excerpt":{"rendered":"<p>Ak by ste sa p\u00fdtali, ak\u00e9 s\u00fa najv\u00e4\u010d\u0161ie novinky v Jave 8, tak odpove\u010f bude jednozna\u010dne, \u017ee Lambda v\u00fdrazy (referencie na met\u00f3dy) a Streamy. O tom prvom som u\u017e p\u00edsal tu a tu. O tom druhom si povieme teraz. Streamy s\u00fa nov\u00fd sp\u00f4sob ako pracova\u0165 s mno\u017einami \u00fadajov. A podobne ako Lambda v\u00fdrazy, aj oni [&hellip;]<\/p>","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-98","post","type-post","status-publish","format-standard","hentry","category-vyvoj-softveru"],"_links":{"self":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts\/98","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/comments?post=98"}],"version-history":[{"count":4,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts\/98\/revisions"}],"predecessor-version":[{"id":310,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/posts\/98\/revisions\/310"}],"wp:attachment":[{"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/media?parent=98"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/categories?post=98"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/spireng.sk\/en\/wp-json\/wp\/v2\/tags?post=98"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}