Changes

Jump to: navigation, search

Java Funkcionális interfész & Lambda

5,736 bytes added, 09:35, 12 August 2022
Java Method Reference and Constructor Reference
https://www.amitph.com/java-method-and-constructor-reference/
==Method Reference==
A metódus referencia (akár statikus akár nem) arra jó, hogy egy meglévő osztály egy metódusát át tudjuk adni a funkcionális IF definíciót váró metódusnak ahelyett hogy definiálnánk helyben lambda belsejét. Azonban ez nem egyezik meg a Funkcionális interfész implementációját tartalmazó osztály használatával. Ha metódus referenciát használunk, akkor a funkcionális IF implementáció helyére megadott osztály és metódus nem kell hogy implementálja a funkcionális interfész funkcionális metódusát, elég ha megfelel a karakterisztikája az éppen használt funkcionális if kifejezésnek, vagyis az elvárt paraméterekkel rendelkezik, és a visszatérési érték típusa is megfelel a várt funkcionális if-nek kifejezésnek.
Nézzük ismét az alábbi példa class-t, aminek van egy metódusa, ami egy funkcionális interfészt vár (processVariable). Itt egy beépített funkcionális IF-et használunk megint
<source lang="java">
package hu.otp.auth.loginHelper.util;
import java.util.function.Function;
 
public class MyLambadClass {
 
private String variable1;
 
public MyLambadClass(String a) {
this.variable1 = a;
}
 
public void processVariable(Function<String, Integer> fn) {
 
Integer length = fn.apply(variable1);
System.out.println("Value given by function IF impl: "+ length.toString());
}
}
</source>
<br>
 
Emlékeztetőül, a java gyári Function nevű funkcionális IF implementációja így néz ki:
<source lang="java">
package java.util.function;
 
@FunctionalInterface
public interface Function<T, R> {
R apply(T var1);
...
</source>
Láthatjuk, hogy egy implementálandó metódusa van, ezt lehet egy lambda in line IF-el megadni, vagy akár egy implementációs osztállyal definiálni.
 
Tehát, normál esetben ez működne:
<source lang="java">
public class MyFunctionImpl implements Function<String, Integer> {
@Override
public Integer apply(String s) {
return s.length();
}
}
</source>
</br>
Majd ha meghajtjuk a metódust ezzel az implementációval:
<source lang="java">
MyLambadClass myLambadClass = new MyLambadClass("process_this_during_functional_if_call");
myLambadClass.processVariable(new MyFunctionImpl());
</source>
Akkor a konzolon meg fog jelenni hogy: "38"
 
<br>
Mert hogy: <br>
A '''processVariable()''' metódus belsejében azt mondtuk meg, hogy fogja meg a konstruktorban kapott változót, adja azt át a '''Function''' funkcionális if-et implementáló osztály '''apply''' metódusának és amit az visszaad, azt írja ki a képernyőre. A '''MyFunctionImpl''' -ban rögzítettük, hogy a generikus IF milyen típusokkal fog rendelkezni (String megy be, és Integer jön ki). Azt hogy ezt hogy állítja elő az implementáció, erről a '''processVariable()''' metódusban semmit sem tudunk, teljesen az implementációra van bízva.
 
 
<br>
Persze, ezt lambdával is megadhattuk volna, akkor így nézne ki:
<source lang="java">
MyLambadClass myLambadClass = new MyLambadClass("process_this_during_functional_if_call");
myLambadClass.processVariable(input -> {return input.length();}); ---> 38
</source>
Itt inline, lambda definíciót használtunk. A generikus változói a '''Function''' funkcionális interfésznek (T és R) explicit lett definiálva azáltal, hogy a '''processVariable(..)''' belsejében a funkcionális IF (apply) String paraméterrel van meghívva és Integer-t vár vissza.
 
<br>
<br>
Na már most, ezt lehet nagyban egyszerűsíteni bármilyen olyan Osztály statikus vagy nem statikus metódusával, ami String-et vár és Integer-t ad vissza. Erre szolgála '''::''' operátor. Statikus metódus használata esetén nem kell példányosítani az osztályt, ennyi a különbség. Ami a lényeg: '''ezen osztálynak nem kell implementálnia a várt funkcionális interfész itt használt metódusát!!'''
<source lang="java">
MyLambadClass myLambadClass = new MyLambadClass("process_this_during_functional_if_call");
myLambadClass.processVariable(String::length); ----> 38
</source>
Ezzel azt mondjuk meg, hogy az '''R pply(T)''' helyett inkább hívd meg az '''Integer Sring.length(String input)''' metódust.
 
<br>
VAGY ha nem statikus: <br>
<br>
Tegyük fel hogy van egy ilyen osztályom, ami nem implementál semmilyen IF-et:
<source lang="java">
public class MyString {
public Integer getLengthOfImput(String input) {
return input.length();
}
}
</source>
 
Akkor a '''getLengthOfImput(..)''' is átadható példányosítás után a '''::'' operátorral, mint behelyettesítés:
<source lang="java">
MyLambadClass myLambadClass = new MyLambadClass("process_this_during_functional_if_call");
MyString myString = new MyString();
myLambadClass.processVariable(myString::getLengthOfImput); ---> 38
</source>
Vagyis ahelyett hogy meghívná a funkcionális IF '''R apply(T)''' metódusát, inkább meghívja majd a '''getLengthOfImput''' metódust.
<br>
<br>
==Constructor Reference==
 
A konstruktor referencia egy speciális Metódus referencia, ami csavar még egyet a fenti metódus referencia koncepción, itt már nagyon kell figyelni. <br>
Ugyebár minden funkcionális IF visszaad egy objektumot, és vagy kap vagy nem input paramétereket. A lényeg, hogy egy előre nem definiált módon gyártson le egy olyan objektumot, amit visszaad akkor mikor meghívjuk a funkcionális metódusát, az előbbi példában az '''R apply(T)''' metódust. Ahol kap egy T-t és tök mindegy hogy hogy, csak gyártson le egy '''R''' osztály példányt.
 
<br>
==Constructor reference in Enum==
Ehhez elsőként ajánlott elolvasni az ENUM alapokat: [[ Java Enum]]
 
 
Ha az enum-nak készítünk Funkcionális interfész metódusokat
 
 

Navigation menu