images/logo.png
SHWB na blogspot  | Uživatel: Nepřihlášen

O programování 03 - Přehlednost funkcionálního zápisu v Java 8

V předchozím díle jsem zjistil, že výkonnost streamů, resp. funkcionálního zápisu není tak špatná, jak se na první pohled zdálo, spíše naopak. Nicméně hlavním argumentem pro zavedení funkcionálního přístupu do Java 8 je větší čitelnost kódu. V této oblasti však osobně docela narážím, protože mi použité řešení nepřipadá dobré.

Vrátím se k příkladu z minulého dílu. Použití klasického cyklu foreach není nijak zázračný zápis, ale na první pohled chápu, co se děje - iteruji přes celý seznam a do výstupního seznamu přidávám prvky zvětšené o jedna.



for (Integer value: inputList) { outputList.add(++value); }

Přímočarý přepis (jak ho nabízí NetBeansy) s využitím funkcionálních rysů vypadá takto:



inputList.stream().forEach((value) -> { outputList.add(++value); });

Zdánlivě je to skoro totéž, přesto se mi výsledek prostě nelíbí. Na listu volám volám jakousi metodu stream() a pak foreach(), následuje šipka a za ní kombinace různých závorek. Šipka a závorky jsou jen syntaktický cukr, možná ne úplně přehledný, ale zásadní je otázka - proč zrovna stream(), zvlášť, když existuje i metoda foreach() přímo na listu a kromě stream() je ještě k dispozici paralelStream(). To už je docela guláš, jednu věc mohu napsat třemi způsoby...

Samozřejmě, že si lze vše nastudovat v dokumentaci a použít optimální variantu, ale podle mě to ztrácí kouzlo funkcionálního přístupu, protože se (už zase) zabývám tím JAK, místo abych (jenom) popsal CO.

Hlavně se mi ale nelíbí to, že stream() je běžná metoda a ne klíčové slovo a tím pádem nejde o rys jazyka. Důvodem může být to, že díky tomu přistupuje kompilátor i runtime k funkcionálním rysům stejně jako k ostatním metodám, což má výhodu jednodušší implementace.

Nové klíčové slovo by se mi líbilo kvůli možnosti zvýraznění syntaxe v IDE - takto na první pohled nepoznám, že používám funkcionální rysy jazyka a mohu přehlédnout třeba to, že proměnná v lambda výrazu musí být effectively final. To samozřejmě platí i pro inner class pro nějž je lambda defakto syntaktický cukr ale i tak, je to prostě potenciální místo pro chybu. A hodně "přitaženě" za vlasy - tvůrci jazyka mohou metodu stream() v budoucnu označit jako deprecated a tím odstřihnout funkcionální rysy z Javy.

Ovšem i po takto krátké úvaze chápu, co vedlo tvůrce k tomu nezavádět úplně novou syntaxi ale využít stávající možnosti jazyka jak jen to šlo ale nadšen z toho nejsem.

***

Vezměme si o něco složitější případ, v němž chceme sečíst pole čísel. Pomiňme, že bych na to čekal knihovní funkci (a možná i taková existuje), přímočaře v Javě bych to napsal třeba takto:



Integer result = 0; for (Integer value : list) { result += value; }

Opět vidím na první pohled, co kód dělá, ale když ho přepíšu funkcionálně, např. takto, jsem zmaten.



Integer result = list.stream().map((value) -> value).reduce(0, Integer::sum);

Super je, že je zápis na jednom řádku, ale co to sakra znamená? V zápisu se objevují různé "tajemné" metody jako map()reduce(), o Integer::sum ani nemluvě. Zkrátka musím při čtení tohoto kousku kódu trochu přemýšlet, abych pochopil, co vlastně dělá, přitom jenom sčítám čísla a přitom používám 4 různé metody (stream(), map(), reduce(), sum()). Osobně by se mi prostě líbila nějaká elegantnější syntaxe.

Aktualizace 15. 12. 2016

V diskusi jsem byl upozorněn, že příklad na součet lze zapsat bez matoucí (a zbytečné) metody map takto:



Integer result = list.stream().reduce(0, Integer::sum);

Můj původní kód mi vygenerovaly NetBeansy a bohužel jsem ho detailně nezkoumal. Tenhle zápis je mnohem přehlednější ale padá jím tak trochu původní pointa celého článku.

13.12.2016
Diskuse k článku:
Počet příspěvků: 2 - zobrazeno v: 17.06.2019 - 20:46:03
Saha (14.12.2016 - 21:54:34):
Máš pravdu, to map je tam zbytečné. Odněkud jsem to opsal a nezkontroloval. Tím ovšem trochu padá pointa celého článku.
David P. (13.12.2016 - 22:19:45):
Jen takova otazka k tomu druhemu prikladu:
Proc tam tu cast s "map" ktera de facto s prvky toho streamu nic nedela? Nestacilo by
list.stream().reduce(0, Integer::sum);
?
Ja teda moc funkcionalni rysy v Jave jeste moc nestudoval (preci je to v soucasne praci otazka pristich 10 let), tak nevim zda to tam nema nejaky zvlastni vyznam (ktery pokud existuje bych pak oznacil jako za extra matouci).
Přidat názor:
Vyhrazuji si právo libovolný komentář smazat bez udání důvodu. Kritika mi nevadí, ale chci omezit anonymní výkřiky, které nemají s tématem nic společného.
V textu je možné používat HTML tagy a tuto zjednodušenou MarkDown syntaxi
Jméno
Text
Postřehy:
08.02.2019: Most! - Je to DÁŠA!
Chvíli jsem přemýšlel, jestli psát o seriálu Most! do Filmů nebo do Postřehů, nakonec jsem se rozhodl pro Postřehy. Důvod je ten, že seriály moc nesleduji, odrostl jsem na Červeným trpaslíkovi, Jistě pane ministře atd. a poslední, co jsem viděl, byla tak šestá série TBBT. Což je všechno docela vysoká laťka, zvlášť, když si vezmu ty různý český hospody a spol. tak si říkám, že je to
https://www.printertollfreenumber.com/epson-printer-support: Epson is a well-known brand for printers and scanners many users of Epson in worldwide if you are also an Epson customer and you
Poslední diskuse Postřehy
O programování 06 - Návrhové vzory - síla i slabina Javy
P.S. samozrejme "Context" mel byt "Client" .. To jsem jen narazil na nejak divne pojmenovany diagram.. (Context je samozrejme trosku neco jineho...)
...
David | 25.02.2017
O programování 06 - Návrhové vzory - síla i slabina Javy
To k cemu jsi dosel (tedy implementace LooperRunner + ILoopMethod), tak je ta prava Strategy by GoF :) To co je tam dulezite je ze Context (LooperRunner) je oddeleny od Strategy (ILoopMethod),
...
David | 25.02.2017
O programování 03 - Přehlednost funkcionálního zápisu v Java 8
Máš pravdu, to map je tam zbytečné. Odněkud jsem to opsal a nezkontroloval. Tím ovšem trochu padá pointa celého článku.
...
Saha | 14.12.2016
O programování 03 - Přehlednost funkcionálního zápisu v Java 8
Jen takova otazka k tomu druhemu prikladu:
Proc tam tu cast s "map" ktera de facto s prvky toho streamu nic nedela? Nestacilo by
list.stream().reduce(0, Integer::sum);
?
Ja teda moc
...
David P. | 13.12.2016
Paleo na půl - 01 - První tři dny bez mléka
Kvalitní hořké čokolády jsou bez mléka.. :) (a to i ty méně "kvalitní"). Mléko bývá součástí jen těch "sladkých".
...
David | 04.05.2015
Statistiky
Aktualizováno: 04.06.2019
Počet článků/fotek: 1365/13742
(C) Saha - 1990 - 2019 - Verze 1.3.32 - 11.05.2019 - Generated by SHREC 2.214
Veškeré zde uvedené materiály vyjadřují pouze moje soukromé názory (s výjimkou knihy návštěv a diskusí, kam může přispívat kdokoliv), a pokud s nimi někdo nesouhlasí, tak je to jeho problém, nikoliv můj.