4it101»Java8pr 6 Reseni

Java8pr 6 Reseni

Příklad Generocké funkční rozhraní - řešení

Úloha primárně spočívá ve správném vytvoření vhodného funkčního rozhraní. Prvním krokem tedy bude vytvořit takové funkční rozhraní pomocí, kterého lze řešit obě části úlohy. Obě řešení se budou lišit pouze samotnou implementací tohoto funkčního rozhraní s použitím lambda výrazů. Pomocí nichž pak lze získat patřičné výsledky.

Jelikož máme dva seznamy, které nemají shodné typy prvků, je nutné vytvořit takové funkční rozhraní, které je obecné pro různé datové typy, jedná se o tzv. generické funkční rozhraní. Nejprve je ale nutné se zamyslet, jak by vlastně mělo vypadat a co vlastně mají tyto dvě podúlohy společné.

Oba seznamy jsou typu List, ten bude třeba zadat jako parametr, aby bylo následně možné seznam procházet a pracovat s jeho prvky. Takže abstraktní metoda funkčního rozhraní bude mít jeden parametr typu List<T>, kde T je typ prvků v daném seznamu (u prvního seznamu to bude Integer a u druhého String).

Dále je ovšem třeba se zamyslet nad návratovou hodnotou. V druhém případě požadujeme z prvků typu String vytvořit opět String. To ale neplatí v prvním případě, kdy je úkolem z prvků Integer vytvořit long (v tomto případě je ale nutné jí „obalit“ na typ Long , aby se s daným typem dalo pracovat v takto obecně deklarované metodě). Návratová hodnota tedy musí opět být „neznámá“. Funkční rozhraní pak bude vypadat následovně.


interface GenerickeFunkcniRozhrani<T,U>{
    U sloucit(List<T> seznam);
}

 

Nyní už lze přejít k samotné implementaci. Pro řešení je zapotřebí vytvořit dvě instance nově vytvořeného funkčního rozhraní, protože tělo lambda výrazu pro jejich implementaci se bude lišit.

První instance bude pracovat s prvky typu Integer a výsledkem bude prvek typu Long (je nutné je zadat již při vytváření této instance, čímž předáme lambda výrazu informaci o typu prvků, se kterými pracuje). V tomto případě je vhodnější použít blokový lambda výraz, v jehož těle bude for cyklus, který projde seznam a sečte jeho prvky. A součet následně vrátí.

Druhá instance bude vypadat podobně. Liší se ovšem tím, že zde jako typ prvků seznamu zadáme String a výstup bude též String. V těle lambda výrazu pak cyklus for projde celý seznam, spojí prvky mezerou a vrátí spojený řetězec. Konečnou podobu lze vidět níže.


GenerickeFunkcniRozhrani<Integer,Long> soucet = (a) -> {
            long vysledek = 0;
            for(int i = 0; i< a.size();i++){
                vysledek += a.get(i);
            }
            return vysledek;
        };
GenerickeFunkcniRozhrani<String,String> retezec = (b) -> {
          String vysledek = "";
          for(int i = 0; i < b.size();i++){
              vysledek += b.get(i) + " ";
          }
          return vysledek;
        };

 

Nakonec, ať už si zvolíte jakýkoli postup, už je jen třeba zavolat na tyto instance abstraktní metodu sloucit() a jako parametr zadat patřičný zdrojový seznam. Součtem číselného seznamu je číslo 15 a výsledným řetězcem pak „propiska pastelka blok laptop“.

Celkové řešení je v projektu Generické funkční rozhraní - řešení.

Další možností je místo for cyklů použít datové proudy k implementaci třídy pro instanci výše uvedeného funkčního rozhraní. Pro získání součtu prvků typu Integer a získání výsledku jako typ Long lze ze seznamu vytvořit datový proud pomocí metody stream(). Jelikož úkolem je získat výsledek jako Long, je nutné zavolat metodu mapToLong(), která prvky typu Integer „přemapuje“ na prvky typu Long a vytvoří datový proud typu LongStream. Na ten už pak stačí jen zavolat metodu sum(), která vrátí součet prvků datového proudu jako hodnotu primitivního datového typu long. Pro sloučení seznamu s textovými řetězci lze postupovat obdobně. Ze seznamu se vytvoří datový proud a s pomocí metody collect() se vytvoří výstup. Metodě collect() je nutné zadat jako parametr instanci rozhraní Collector<T,A,R> získanou s pomocí třídy Collectors a její metody joining(CharSequence delimiter). Té se jako oddělovač (delimiter) zadá mezera. Výše popsaný postup lze vidět níže.


  GenerickeFunkcniRozhrani<Integer,Long> soucet = (a) -> {
            return a.stream().mapToLong(i -> (long) i).sum();
        };

  GenerickeFunkcniRozhrani<String,String> retezec = (b) -> {
          return b.stream().collect(Collectors.joining(" "));
        };