Sprievodca rozhraním Java BiFunction

1. Úvod

Java 8 predstavila programovanie funkčných štýlov, čo nám umožnilo parametrizovať univerzálne metódy odovzdávaním funkcií.

Asi najviac poznáme funkčné rozhrania s jedným parametrom Java 8 Funkcia, Predikát, a Spotrebiteľ.

V tomto výučbe sa pozrieme na funkčné rozhrania, ktoré používajú dva parametre. Takéto funkcie sa nazývajú binárne funkcie a v Java sú reprezentované znakom BiFunkcia funkčné rozhranie.

2. Jednoparametrické funkcie

Poďme si rýchlo zrekapitulovať, ako používame funkciu s jedným parametrom alebo unárnou funkciou, ako to robíme v streamoch:

Zoznam mapovaný = Stream.of ("ahoj", "svet"). Mapa (slovo -> slovo + "!") .Collect (Collectors.toList ()); assertThat (mapované). obsahuje Presne ("ahoj!", "svet!");

Ako vidíme, mapa používa Funkcia, ktorý má jediný parameter a umožňuje nám vykonať operáciu s touto hodnotou a vrátiť novú hodnotu.

3. Dvojparametrové operácie

Knižnica Java Stream nám poskytuje a zmenšiť funkcia, ktorá nám umožňuje kombinovať prvky streamu. Musíme vyjadriť, ako sa hodnoty, ktoré sme doteraz zhromaždili, transformujú pridaním ďalšej položky.

The zmenšiť používa funkčné rozhranie BinaryOperator, ktorý naberá dva objekty rovnakého typu ako svoje vstupy.

Predstavme si, že chceme spojiť všetky položky v našom streame tak, že nové vložíme do popredia pomocou oddeľovača pomlčiek. V nasledujúcich častiach sa pozrieme na niekoľko spôsobov, ako to implementovať.

3.1. Pomocou lambdy

Implementácia lambda pre a BiFunkcia je predpona dvoma parametrami, obklopená zátvorkami:

Výsledok reťazca = Stream.of ("ahoj", "svet") .reduce ("", (a, b) -> b + "-" + a); assertThat (result) .isEqualTo ("world-ahoj-");

Ako vidíme, tieto dve hodnoty, a a bStruny. Napísali sme lambdu, ktorá ich kombinuje tak, aby vytvorili požadovaný výstup, pričom druhá je prvá a pomlčka je medzi nimi.

Mali by sme si to všimnúť zmenšiť používa začiatočnú hodnotu - v tomto prípade prázdny reťazec. Takže skončíme s koncovou pomlčkou s vyššie uvedeným kódom, pretože je s ňou spojená prvá hodnota z nášho streamu.

Mali by sme tiež poznamenať, že odvodenie typu Java nám umožňuje väčšinu času vynechať typy našich parametrov. V situáciách, keď typ lambdy nie je jasný z kontextu, môžeme pre naše parametre použiť typy:

Výsledok reťazca = Stream.of ("ahoj", "svet") .reduce ("", (reťazec a, reťazec b) -> b + "-" + a);

3.2. Používanie funkcie

Čo keby sme chceli, aby vyššie uvedený algoritmus nemal na konci pomlčku? Do našej lambdy by sme mohli napísať viac kódu, ale to by sa mohlo stať chaotickým. Namiesto toho extrahujeme funkciu:

private String combineWithoutTrailingDash (String a, String b) {if (a.isEmpty ()) {return b; } návrat b + "-" + a; }

A potom to nazvať:

Výsledok reťazca = Stream.of ("ahoj", "svet") .reduce ("", (a, b) -> combineWithoutTrailingDash (a, b)); assertThat (result) .isEqualTo ("world-ahoj");

Ako vidíme, lambda volá našu funkciu, ktorá je ľahšie čitateľná ako vloženie zložitejšej implementácie.

3.3. Použitie referenčnej metódy

Niektoré IDE nás automaticky vyzvú, aby sme vyššie uvedenú lambdu previedli na referenciu o metóde, pretože je často čitateľnejšia.

Prepíšme náš kód tak, aby používal odkaz na metódu:

Výsledok reťazca = Stream.of ("ahoj", "svet") .reduce ("", toto :: combineWithoutTrailingDash); assertThat (result) .isEqualTo ("world-ahoj");

Odkazy na metódy často uľahčujú vysvetlenie funkčného kódu.

4. Používanie BiFunkcia

Doteraz sme si demonštrovali, ako používať funkcie, kde sú oba parametre rovnakého typu. The BiFunkcia rozhranie nám umožňuje používať parametre rôznych typov, s návratovou hodnotou tretieho typu.

Poďme si predstaviť, že vytvárame algoritmus na spojenie dvoch zoznamov rovnakej veľkosti do tretieho zoznamu vykonaním operácie s každou dvojicou prvkov:

Zoznam list1 = Arrays.asList ("a", "b", "c"); List list2 = Arrays.asList (1, 2, 3); Výsledok zoznamu = nový ArrayList (); pre (int i = 0; i <list1.size (); i ++) {result.add (list1.get (i) + list2.get (i)); } assertThat (result) .containsExactly ("a1", "b2", "c3");

4.1. Zovšeobecniť funkciu

Túto špecializovanú funkciu môžeme zovšeobecniť pomocou a BiFunkcia ako kombinátor:

private static List listCombiner (List list1, List list2, BiFunction combineer) {Výsledok zoznamu = nový ArrayList (); for (int i = 0; i <list1.size (); i ++) {result.add (combineer.apply (list1.get (i), list2.get (i))); } vrátiť výsledok; }

Pozrime sa, čo sa tu deje. Existujú tri typy parametrov: T pre typ položky v prvom zozname, U pre typ v druhom zozname a potom R pre akýkoľvek typ vráti kombinovaná funkcia.

Používame BiFunkcia poskytované tejto funkcii volaním jej uplatniť metóda získať výsledok.

4.2. Volanie zovšeobecnenej funkcie

Náš kombinátor je a BiFunkcia, čo nám umožňuje vložiť algoritmus bez ohľadu na typ vstupu a výstupu. Vyskúšajme to:

Zoznam list1 = Arrays.asList ("a", "b", "c"); List list2 = Arrays.asList (1, 2, 3); Výsledok zoznamu = listCombiner (list1, list2, (a, b) -> a + b); assertThat (result) .containsExactly ("a1", "b2", "c3");

Môžeme to tiež použiť pre úplne odlišné typy vstupov a výstupov.

Poďme vložiť algoritmus na určenie, či je hodnota v prvom zozname väčšia ako hodnota v druhom a vytvorme a boolovský výsledok:

Zoznam list1 = Arrays.asList (1.0d, 2.1d, 3.3d); List list2 = Arrays.asList (0.1f, 0.2f, 4f); Výsledok zoznamu = listCombiner (list1, list2, (a, b) -> a> b); assertThat (result) .containsExactly (true, true, false);

4.3. A BiFunkcia Referenčná metóda

Prepíšeme vyššie uvedený kód pomocou extrahovanej metódy a odkazu na metódu:

Zoznam list1 = Arrays.asList (1.0d, 2.1d, 3.3d); List list2 = Arrays.asList (0.1f, 0.2f, 4f); Výsledok zoznamu = listCombiner (list1, list2, this :: firstIsGreaterThanSecond); assertThat (result) .containsExactly (true, true, false); private boolean firstIsGreaterThanSecond (Double a, Float b) {return a> b; }

Mali by sme poznamenať, že vďaka tomu je kód o niečo ľahšie čitateľný ako metóda firstIsGreaterThanSecond popisuje vložený algoritmus ako referenciu metódy.

4.4. BiFunkcia Metóda Referencie Použitie toto

Predstavme si, že chceme použiť vyššie uvedené Dvojfunkcia-založený na algoritme na určenie, či sú dva zoznamy rovnaké:

Zoznam list1 = Polia.asList (0,1f, 0,2f, 4f); List list2 = Arrays.asList (0.1f, 0.2f, 4f); Výsledok zoznamu = listCombiner (list1, list2, (a, b) -> a.equals (b)); assertThat (result) .containsExactly (true, true, true);

Riešenie môžeme skutočne zjednodušiť:

Výsledok zoznamu = listCombiner (list1, list2, Float :: equals);

Je to preto, lebo rovná sa funkcia v Plavák má rovnaký podpis ako a BiFunkcia. Trvá implicitný prvý parameter toto, objekt typu Plavák. Druhý parameter, inétypu Objekt, je hodnota na porovnanie.

5. Skladanie Dvojfunkcie

Čo keby sme mohli pomocou odkazov na metódy urobiť to isté ako náš príklad porovnania číselných zoznamov?

Zoznam list1 = Arrays.asList (1.0d, 2.1d, 3.3d); List list2 = Arrays.asList (0.1d, 0.2d, 4d); Výsledok zoznamu = listCombiner (list1, list2, Double :: compareTo); assertThat (vysledok) .obsahuje Presne (1, 1, -1);

Je to blízko k nášmu príkladu, ale vráti sa Celé číslo, skôr ako originál Boolovský. Je to preto, lebo porovnať s metóda v Dvojitý vracia Celé číslo.

Môžeme pridať ďalšie správanie, ktoré potrebujeme na dosiahnutie pôvodného použitím a potom zostaviť funkciu. Týmto sa získa a BiFunkcia že najskôr urobí jednu vec s dvoma vstupmi a potom vykoná ďalšiu operáciu.

Ďalej vytvoríme funkciu na vynútenie odkazu na našu metódu Double :: compareTo do a BiFunkcia:

private static BiFunction asBiFunction (BiFunction function) {return function; }

Lambda alebo odkaz na metódu sa stáva iba BiFunkcia po prevedení vyvolaním metódy. Pomocou tejto pomocnej funkcie môžeme previesť našu lambdu na BiFunkcia objekt vyslovene.

Teraz môžeme použiť a potom pridať správanie nad prvú funkciu:

Zoznam list1 = Arrays.asList (1.0d, 2.1d, 3.3d); List list2 = Arrays.asList (0.1d, 0.2d, 4d); Výsledok zoznamu = listCombiner (list1, list2, asBiFunction (Double :: compareTo). A potom (i -> i> 0)); assertThat (result) .containsExactly (true, true, false);

6. Záver

V tomto tutoriáli sme to preskúmali BiFunkcia a BinaryOperator v zmysle poskytovanej knižnice Java Streams a našich vlastných vlastných funkcií. Pozreli sme sa, ako prejsť Dvojfunkcie pomocou lambd a odkazov na metódy a videli sme, ako zostaviť funkcie.

Knižnice Java poskytujú iba jedno- a dvojparametrové funkčné rozhrania. Situácie, ktoré si vyžadujú viac parametrov, nájdete v našom článku o kari, kde nájdete ďalšie nápady.

Kompletné ukážky kódu sú ako vždy k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found