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

O programování 07 - Funkce jako argument aneb od factory k lambdě v Javě

V minulém díle jsem ukázal, jak lze v Javě implementovat čtyři varianty jednoho algoritmu s využitím veškerého aparátu OOP a návrhových vzorů, konkrétně vzorů strategy a factory. Výsledná implementace je sice Javovsky sofistikovaná ale zastírá podstatu, totiž to, že ve skutečnosti chci předat do metody funkci jako parametr. Pokud se podívám na příklad s factory trochu s nadhledem, tak v něm vlastně předáváme instanci třídy, která danou funkcionalitu implementuje a v rámci factory ji specifikuji názvem.



public static void main(String[] args) { LoopRunner runner = new LoopRunner(LoopFactory.get("foreach")); runner.run(); }

Dalším krokem je předat do konstruktoru anonymní třídu implementující danou funkcionalitu:



public static void main(String[] args) { LoopRunner runner = new LoopRunner(new ILoopMethod() { @Override public void testedMethod(List<Integer> inputList, List<Integer> outputList) { for (Integer integer : inputList) { outputList.add(++integer); } } }); runner.run(); }

Tento zápis lze přepsat s využitím funkcionálních možností následujícím způsobem:



public static void main(String[] args) { LoopRunner runner = new LoopRunner((List<Integer> inputList, List<Integer> outputList) -> { for (Integer integer : inputList) { outputList.add(++integer); } }); runner.run(); }

Tím jsem sice dosáhl toho, že předávám funkci (metodu) jako parametr, ale pořád mi to nepřipadá úplně intuitivní a přehledné. Navíc (mi) není na první pohled zřejmé, jak je zařízeno to, že předávaná implementace implementuje interface ILoopMethod. V předchozím příkladě je ILoopMethod explicitně zmíněno v konstruktoru, ale ve funkcionálním případě zcela chybí. Jak to?

Ono to funguje (jenom) díky tomu, interface ILoopMethod má (v tomto případě náhodou) jen jednu metodu a jde tedy o funkční interface zavedený v Java 8, což je opět přiohnutí syntaxe v tom smyslu, že interface s jednou metodou může mít speciální význam.

Každopádně je zajímavé, že jsem se k funkcionálnímu přístupu dostal vlastně domyšlením návrhového vzoru strategy a factory do důsledků, což mimo jiné potvrzuje můj názor, že (některé) návrhové vzory nejsou nic jiného než způsob, jak obejít omezení jazyka.

Mimochodem, použití funkce jako parametru je využití command patternu, viz zdezde. Lambda v Java 8 je pak pouhým syntaktickým cukrem nad výše uvedeným, doplněný zmíněným funkčním interfacem, což sice dává docela smysl, ale pořád mi to přijde lehce nepřehledné.

Nicméně budu pokračovat s úpravami kódu. Nejdříve přepíšu volání metody run() tak, aby se předávala pouze funkce (method), byť stále budu využívat můj (uživatelsky definovaný) interface:



public static void main(String[] args) { final ILoopMethod method = (List<Integer> inputList, List<Integer> outputList) -> { for (Integer integer : inputList) { outputList.add(++integer); } };
final LoopRunner runner = new LoopRunner(method); runner.run(); }

U vlastního volání v rámci metody run() je použito:


method.testedMethod(inputList, outputList);

Následně využijeme interface Function definované v Java 8:



public static void main(String[] args) {
Function<List<Integer>, List<Integer>> method = (List<Integer> inputList) -> { List<Integer> outputList = new ArrayList<>(inputList.size()); for (Integer integer : inputList) { outputList.add(++integer); } return outputList; };
final LoopRunner runner = new LoopRunner(method); runner.run(); }

U vlastního volání v rámci metody run() je použito:



private void run() {
...
final List<Integer> outputList = method.apply(inputList);
...
}

Tento zápis mi už dává smysl a celkem se mi i líbí, i když pořád zůstávají "nějak" pojmenované metody místo řešení na úrovni syntaxe jazyka a "zneužití" patřičně oanotovaného interface. Chápu, že je to kompromis mezi využitím toho, co už bylo v jazyce a jeho implementaci k dispozici a potřebou zavést novou a potřebnou funkcionalitu. Ovšem řešit to knihovnou místo rysem jazyka je ... už jsem to psal, má to výhody i nevýhody.

08.02.2017
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
extravaganza.controverso@seznam.cz: Zdravím, krásný a informacemi nabitý blog. Musím pochválit. Plánuji rozjet undergroundový zin, co by se týkal black matalu, ambientu, satanismu, left hand
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.