7,540
edits
Changes
→Hogyan működik
=Funkcionális Interfész alapok= ==Mire jó a funkcionális interfész== A funkcionális interfészek használatával megszabadulhatunk az úgynevezett boilerplate (közhelyes) code használatától, vagyis nagyon egyszerűen, osztály példányosítás nélkül tudunk interfész metódus implementációkat készíteni. Ennek az egyik kulcs eszköze a JAVA8-ban bejött LAMBDA és úgynevezett metódus referencia, amire majd látunk bőven példát. Azt mondják hogy ez a java-ba valaha behozott legnagyobb újítás. <br><br>A fent leírtakat persze persze anonymous osztályokkal is el lehet érni, csak többet kell hozzá írni. Pl: A Theread osztályban szokásos anonymous osztályokat létrehozni a run() definiálására:<source lang="java">public class AnonymousClassExample { public static void main(String[] args) { Thread thread = new Thread(){ public void run(){ System.out.println("Understanding what is an anonymous class"); } }; thread.start(); }}</source><br><br>Lambda kifejezéssel ugyan ez így írható le: <source lang="java">public class AnonymousClassExample { public static void main(String[] args) { Runnable runnable = () -> { System.out.println("Understanding functional interfaces"); }; runnable.run(); }}</source> <br><br> ==Hogyan működik==A funkcionális interfész egy olyan interfész, amiben csak egy darab absztrakt metódus van. (vagyis ami implementálandó). Ezt kidomborítandó, a '''@FunctionalInterface''' annotációval is el lehet látni az interfészt. Készítsünk egy egyedi String osztályt, amivel majd példálózunk (ez még nem kapcsolódik a funkcionális if-re)<source lang="java">public class MyString { private String input; public MyString(String input) { System.out.println("MyString consturctor is called with input:" + input); this.input = input; } public String getInput() { return input; } }</source><br><br>Tekintsük az alábbi funkcionális if-et, aminek egy absztrakt metódusa van, ami egy String-et vár, és egy MyString-et ad vissza. <source lang="java">@FunctionalInterfacepublic interface MyFunction { MyString process(String input);}</source> Egy funkcionális interfész implementációjának a megadására az alábbi 5 lehetőségünk van: * Hagyományos implementációs osztály példányosítása* anonymous osztály használata* Lambda kifejezés használata* Metódus referencia használata: lásd [[#Java_Method_Reference_and_Constructor_Reference]]* Konstruktor referencia használata lásd [[#Java_Method_Reference_and_Constructor_Reference]]<br><br>===Implementációs osztály példányosítása===A klasszikus használata egy interfésznek, ha készítünk egy osztályt, ami implementálja az absztrakt metódusokat, majd példányosítjuk az osztályt, és klasszikus módon használjuk. Ehhez nincs szükség funkcionális IF-re, vagyis hogy csak egy absztrakt metódusa legyen az interfésznek, mivel az implementációban explicit megmondjuk, hogy melyiket implementáljuk: <source lang="java">public class MyFunctionImpl implements MyFunction { @Override public MyString process(String input) { return new MyString(input); }}</source><br>Majd ezt így használhattuk: <source lang="java"> MyFunctionImpl2 myFunctionImpl2 = new MyFunctionImpl2(); MyString myString = myFunctionImpl2.process("MyInput"); System.out.println(myString.getInput());</source><br><br>===Anonymous osztály használata===Ahogy a bevezetőben is láttuk, bármilyen interfésznek lehet anonymous osztállyal definiálni a még nem definiált interfészeit az alábbi szintaxissal: <pre>new InterfaceName() { @Override public <implementálandó metódus definíció> {..}};</pre>Itt sincs szükség funkcionális interfészre, vagyis hogy csak egy absztrakt metódusa legyen az interfésznek, mert explicit megmondjuk hogy melyiket implementáljuk. <br>Gyakorlatban ez így néz ki az előbbi példára: <source lang="java"> MyFunction fm2 = new MyFunction() { @Override public MyString process(String input) { return new MyString(input); } }; fm2.process("input"); </source> <br><br>===Lambada kifejezés használata===A fenti anonymous osztály definíció egy sokkal rövidebb Lambda kifejezéssel kiváltható, de csak akkor ha a szóban forgó interfész egy '''funkcionális interfész''', vagyis pontosan egy darab absztrakt metódusa van. A Lambda alapokkifejezés szintaxisa az alábbi: <pre>(arguments) -> {function body}</pre>Ahol az argumentumok az egy szem absztrakt metódus input paraméterei, a function bdoy-ban pedig leírjuk, hogy mit tegyen ezekkel az input paraméterekkel az implementáció. Az argumentumok típus nélküliek, a típusuk implicit következik a felhasználási módból, lásd lentebb. * A paraméterek neve tetszőleges lehet, nem kell megegyezzen a funkcionális metódus paraméter neveivel. A sorrend viszont számít. A lényeg, hogy a body-ban az argumentumokban felsorolt nevekkel tudunk hivatkozni az input paraméterekre. * Ha az interfész input paraméter generikus, csak akkor fognak típust kapni, amikor a generikus értékeket definiáljuk az interfész változó létrehozásánál. * Ha a visszatérési érték is generikus az implementálandó metódusban, akkor annak a típusa is csak az adott felhasználásból fog következni. * Ha a funkcionális interfész nem generikus, akkor az interfész input és return értékéből már explicit következik a lambdában használt paraméterek és visszatérési értékék típusa. <br><br>Nézzünk egy konkrét példát. A 'MyFunction' egy funkcionális interfész, mert pontosan egy absztrakt metódusa van: 'MyString process(String)'. Tehát a lambda kifejezéssel ennek a 'process(..)' absztrakt metódusnak az implementációját kell definiálni: <source lang="java"> MyFunction fm = var1 -> { System.out.println("inside lambda body"); return new MyString(var1); }; System.out.println("Start"); fm.process("input"); System.out.println("End");</source>Láthatjuk, hogy a 'MyFunction' egy szem absztrakt metódusát egy lambda kifejezéssel definiáltuk, amivel egyben el is készítettük a MyFunction implementációjának példányosítását. A 'MyFunction'-enk egy darab absztrakt metódusa van, az alábbi szignatúrával: 'MyString process(String)', ebből következik, hogy a '->' elé pontosan egy változó nevet kell kitaláljunk, ami bármi lehet, lényeg, hogy a body-ban ezzel a névvel tudunk rá hivatkozni. Mi itt 'var1' nevet találtunk ki, aminek a típusa 'String', mivel a 'process(..) metódusban egy darab String input paraméter van. Ha a 'process(..)' generikus inputtal rendelkezne, akkor a lambada-ban a 'var1' nek a típusa csak használat közben derülne ki, majd később erre is látunk példát. <br>Fontos, hogy a 'var1'-nek a globálisan semmi jelentése nincs, nem létező változó a fenti kódot futtató kontextusban. Ezt úgy kell elképzelni, mint egy metódus leírója, ami majd akkor kerül meghívásra csak, ha meghíjuk programozottan a 'process(..)' metódust, csak akkor fog feltöltődni értékekkel. <br>Az stdout-ra a következő kerül: <pre>Startinside lambda bodyEnd</pre> <br><br> Tehát az alábbi két sor egyenlő: <source lang="java">MyFunction fm = var1 -> { return new MyString(var1); }; fm.process("input"); EGYENLŐMyFunction fm = new MyFunctionImpl();fm.process("input");</source> !!!Mit fontos itt látni: A lambda definiálásának a sorába még nem fut le a lambda törzsében megadott kód, vagyis ez: return new MyString(var1); !!! <br><br>===Lambda generikus interfésszel===Tegyük fel, hogy adott az alábbi generikus, funkcionális interfész. A funkcionális (absztrakt) metódusa egy T-t és H-t vár és R-t gyárt belőle. Azt hogy hogyan, és hogy mi a T, H és mi az R, az implementációra van bízva. <source lang="java">@FunctionalInterfacepublic interface MyFunctionGeneric<R, T, H> { R doIt(T var, H var2);} </source><br>Definiáljuk a 'MyFunctionGeneric' interfész absztrakt metódusát egy lambda kifejezéssel. A 'MyFunctionGeneric fm' változó létrehozásakor már definiálni kell az R és T és H típusokat, ebből fog következni, hogy a lambada-ban használt paraméter listának milyen értékei vannak, hogy mi kell legyen a visszatérési érték. <br><br>Az alábbi példában létrehoztuk az fm3 'MyFunctionGeneric' változót, és itt meghatároztuk, hogy a visszatérési érték Integer, és a bement két String. A lambda kifejezés input paramétereiben már két értéket kell megadni, ezért zárójelet kell alkalmazni. <source lang="java"> MyFunctionGeneric<Integer, String, String> fm3 = (myInput1, myInput2) -> myInput1.length(); fm3.doIt("my input", "my input2");</source>Az input argumentumoknak megint csak bármilyen nevet megadhatunk, a fenti kódot futtató kontextusban nem léteznek, ez csak egy metódus tervrajz, nem metódus futtatás. A 'myInput1' és 2-nek a típusa következik az fm3-ban megadott generikus típusokból, vagyis mind a kettő String. A visszatérési érték pedig Integer. Ha a lambda body-ban nem akarunk több soros művelet végrehajtani, csak egy 'return (one line logic)' sort tartalmazna, akkor a 'return' kulcsszó elhagyható. Fontos megint csak látni, hogy a doIt(..) metódus hívás hatására fog csak lefutni a lambda-ban definiált kód. <br><br> =Lambda használati példák ===Tipikus használati minták== ..TODO: mindig egy metódus beljesében van, és a metódus lambda-t vár input paraméterben, és az osztály belsejében lévő változókkal szokott operálni. ... <br><br>
==List-forEach()==
<br>
Ez miért működik?
<br><br>
A List a java.lang.Iterale osztály leszármazottja. Ebben van egy default forEach(..) nevű metódus implementáció a forEach-reami egy úgynevezett funkcionális interfész implementációt vár input paraméterben, vagyis egy '''Consumer''' implementációt.
<source lang="java">
package java.lang;
import java.util.function.Function;
public class MyLambadClass MyClassUsingFunctionalif {
private String variable1;
public MyLambadClassMyClassUsingFunctionalif(String a) {
this.variable1 = a;
}
<source lang="java">
MyFunctionImpl myFunction = new MyFunctionImpl();
</source>
<br>
public static void main(String[] args) {
}
Ami nem csinál mást, mint visszaadja a kapott string hosszát. Kívülről nézve a var1 nem értelmezhető, az mindig a lamdát futtató osztály egy osztály változója, kívülről nem megadható.
{{warning|Itt a 'var1' nem kívülről jövő, a metódus meghívásakor előállt paraméter! Ez a 'MyLambadClassMyClassUsingFunctionalif' belső változója, vagyis ide kívülről nem tudunk változót betolni a metódus meghívásakor }}
Tehát, ahogy ezt majd látni fogjuk a CompletionSage-nél, a 'FunctionalInterface'-t futtató osztályt kell előre feltölteni minden olyan változóval, amire szükség van a lamda kifejezés futtatására. A fenti példákban ez egyrészt a 'MyLambadClassMyClassUsingFunctionalif', vagy az első példában a ArrayList osztályok.
* A 'MyLambadClassMyClassUsingFunctionalif' konstruktorában adtuk át azt a string-et, amit a 'processVariable' feldolgoz, attól függetlenül, hogy milyen lamda kifejezéssel implementáljuk a funkcionális interfészét.
* Az ArrayList pedig belső változóiban tárolja
<hr>
<br>
<br>
=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 MyClassUsingFunctionalif {
private String variable1;
public MyClassUsingFunctionalif(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">
MyClassUsingFunctionalif MyClassUsingFunctionalif = new MyClassUsingFunctionalif("process_this_during_functional_if_call");
MyClassUsingFunctionalif.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">
MyClassUsingFunctionalif MyClassUsingFunctionalif = new MyClassUsingFunctionalif("process_this_during_functional_if_call");
MyClassUsingFunctionalif.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">
MyClassUsingFunctionalif MyClassUsingFunctionalif = new MyClassUsingFunctionalif("process_this_during_functional_if_call");
MyClassUsingFunctionalif.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">
MyClassUsingFunctionalif MyClassUsingFunctionalif = new MyClassUsingFunctionalif("process_this_during_functional_if_call");
MyString myString = new MyString();
MyClassUsingFunctionalif.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=Rövidítés= 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. (ez tökre hajaz egy konstruktor definíciójára, na nézzük csak meg:) ) Tekintsük az alábbi funkcionális IF-et: <source lang="java">@FunctionalInterfacepublic interface MyFunction { MyString process(String input);}</source> Bármi is legyen az implementáció (impl osztállyal vagy inline lambda kifejezéssel) a lényeg, hogy előállítson a MyString objektumot. <br>A konstruktor referencia lehetővé teszi, hogy a funkcionális IF implementációt egy osztály konstruktorával helyettesítsük be. Vagyis a funkcionális metódus visszatérési objektumát úgy állítja elő, hogy szimplán példányosítja a megadott osztályt, jelen esetben a MyString-et. Az osztálynak rendelkeznie kell egy olyan konstruktorral, ami a funkcionális metódus input paramétereivel megegyezik. A fenti esetben tehát akkor fogjuk tudni a MyString -et konstruktor referenciában használni, ha rendelkezik egy olyan konstruktorral, ami String-et vár. pl:<source lang="java">public class MyString { private String input; public MyString(String input) { System.out.println("MyString consturctor is called with input:" + input); this.input =input; } Na de mit jelent ez public String getInput() { return input; } }</source> A konstruktor referenciát ::new val kel megadni, vagy a '''::'' operátor után a '''new''' kulcsszót kell írni. Egy lehetséges példa: Tegyük fel, hogy van egy java osztályunk, amiben van egy metódus, ami felhasználja a '''MyFunction''' funkcionális if-et:<source lang="java">public class MyClassUsingFunctionalif { private String variable1; public MyClassUsingFunctionalif(String a) { System.out.println("MyClassUsingFunctionalif consturctor is called with input:" + a); this.variable1 = a; } public void processVariable2(MyFunction mf) { System.out.println("MyClassUsingFunctionalif.processVariable2 START"); MyString myString = mf.process(variable1); System.out.println("MyString instance created by function if call: "+ myString.getInput()); System.out.println("MyClassUsingFunctionalif.processVariable2 END"); }}</source>Vagyis vagy a MyFunction implementálásával vagy egy inline lambda kifejezéssel gyártsunk olyan kódot, ami a saját osztály String változóját (varibale1) átalakítja egy MyString osztállyá, amit ő aztán fel tud használni a sormetódusban (jelen esetben kiíratjuk). És ahelyett hogy: * Implementációt készítünk a MyFunction-hez* lambda kifejezésben adjuk meg inline* Metódus referenciát használunk egy olyan osztály metódusával, ami String-et vár és gyárt belőle egy MyString-et Simán megfogjuk a MyString osztályt és a konstruktorára hivatkozunk a '''MyClassUsingFunctionalif.processVariable2(..)''' metódus használatakor.
<source lang="java">
</source>
<pre>
</pre>
<source lang="java">
</source>
<hrbr><br>Ha olyan osztály változót készítünk az ENUM-nak, ami egy funkcionális interfész, és ezt szintén a konstruktorral inicializáljuk, akkor minden egyes ENUM érték esetében a konstruktorban meg kell adni ennek a funkcionális interfésznek a definícióját. Tegyük fel, hogy adott az alábbi osztály, ami egy saját String változat: <source lang="java">public class MyString { private String input; public MyString(String input) { System.out.println("MyString consturctor is called with input:" + input); this.input = input; } public String getInput() { return input; }}</source><br>Tegyük fel, hogy adott az alábbi funkcionális IF:<source lang="java">@FunctionalInterfacepublic interface MyFunction { MyString process(String input);}</source>Itt a 'process(..)' implementáció egy string-et vár és egy MyString-et ad vissza. <br>Tekintsük az alábbi ENUM-ot. Az enum-nak van egy MyFunction típusú funkcionális if osztály változója, amit a konstruktor inicializál. Tehát minden enum értéknek meg kell adni egy MyFnction implementációt. <source lang="java">public enum MyEnum2 { ENUMV1(..<MyFunction implementáció>...), ; private final MyFunction function; private MyEnum2(MyFunction function) { System.out.println("ENUM constructor is called with input"); this.function = function; } public MyFunction getFunction() { return function; }}</source><br>Láttuk már, hogy elvi szinten egy funkcionális if megadására 4 lehetőségünk van, azonban itt most nem használhatjuk mindent: * Implementációt készítünk a MyFunction-hez: Ez nem fog működni, mert az enum példányosításakor statikus kontextusban vagyunk, nincs hol példányosítsuk a funkcionális if implementációnkat, nem olyan mint amikor enum kívül, normál class metódusban használjuk. * lambda kifejezésben adjuk meg inline* Metódus referenciát használunk egy olyan osztály metódusával, ami String-et vár és gyárt belőle egy MyString-et* Konstruktor referenciát használunk ===lambda kifejezésben adjuk meg inline===Az vetődhet fel kapásból bennünk, hogy az itt lambda-val definiált funkcionális if implementáció (vagyis a 'MyString process(String) impl') mikor fog lefutni, ki fogja meghívni, és mi lesz az a String érték amin dolgozni fog. A korábbi példákban mindig volt egy akármilyen metódus, ami várta paraméterül a funkcionális if-et, majd meghívta rajta a funkcionális metódusát (jelen esetben a process(Stringt)-et), úgy, hogy az a bizonyos metódus töltötte fel az összes input paraméterrel a funkcionális if hívást. Pszeudó kóddal ez elvi szinten így néz ki amiről itt beszélek: <source lang="java">class MyClassUsingFunctionIF { void myMethodUsingFunctionIF(MyFunction mf) { String inputForFuncion = "this is the input"; MyString result = mf.process(inputForFunction); }}</source>Itt a 'myMethodUsingFunctionIF(..)' meghívásával tudjuk implicit lefuttatni a funkcionális if implementációt. A process(..) input paraméterét saját belső változójából tölti fel. ENUM konstruktor referencia estében el kell kérni az enum-tol a konstruktorban inicializált funkcionális függvényt, és meg kell hívni a funkcionális interfészét úgy hogy feltöltjük azt a megfelelő paraméterekkel. Nézzük ezt részletesen. Az alábbi példában az enum konstruktorában egy 'MyFunction' funkcionális interfészt kell átadni, amit egy inline lambda kifejezéssel definiáltunk (mármint a process metódusát). <source lang="java">public enum MyEnum2 { ENUMV1(var1 -> { System.out.println("ENUM lambda is called with input: " + var1); return new MyString(var1); }), ;</source> {note||Az itt megadott kód ugyebár nem fog lefutni a a MyEnum2 példányosításakor. A példányosításkor a konstruktorban ezzel a lambda kifejezéssel csak megadtuk a MyFunction if tervrajzát, vagyis hogy a MyFunction osztály változó rakjon bele egy olyan "virtuális" implementációs példányt, amiben az itt megadott 'MyString process(String)' implementáció található. }} Ahhoz hogy a 'process(String)'-et implementáló lambda kifejezésünk lefusson, elsőként példányosítani kell az ENUM-ot a megfelelő típusra, arra, ami a lambda kifejezést tartalmazza, ami nem más mint az '''ENUMV1''' (lehetne több értéke is az enum-nak, és mindegyikben más és más implementációt is megadhattunk volna). Majd a példányosított enmum-tól a getter-el el kell kérni a funkcionális IF osztály változót, aminek meg kell hívni a process(..) metódusát, úgy hogy megadjuk az if-en kötelező egy darab String input paramétert. <source lang="java"> System.out.println("START"); MyEnum2 myEnum21 = MyEnum2.ENUMV1; System.out.println("Enum was created"); MyString result = myEnum21.getFunction().process("process input"); <<---- itt fut csak le a konstruktorban megadott lambda</source>Fontos, hogy az ENUM példányosításakor tudunk semmit "kívülről" megadni, tehát, nem lehet így példányosítani az ENUM-ot: <pre>MyEnum2.ENUMV1(..constructor values...); <------WRONG</pre> Nézzük meg futási sorrendet, ezt logolja az stdout-ra. Látható, hogy a lambda-ba megadott kifejezés csak a 'process(..)' metódus meghívásakor futott le. A lambda kifejezés tartalmazott egy 'MyString' példányosítást, az futott le utoljára. <pre>STARTENUM constructor is called with inputEnum was createdENUM lambda is called with input: process inputMyString consturctor is called with input:process input</pre><br><br> ===Metódus referenciát használunk===Metódus referenciát használunk egy olyan osztály metódusával, ami String-et vár és gyárt belőle egy MyString-et:
<br>
<br>
=Java Method Reference and Constructor Reference==Konstruktor referenciát használunk===Emlékezzünk rá, hogy funkcionális IF definíciókat meg kelhet adni azon osztály konstruktor referenciájával is, amikkel a funkcionális metódus visszatér, abban az esetben ha ez az osztály rendelkezik olyan konstruktorral, aminek a paraméterei megegyeznek a funkcionális metódus paramétereivel. httpsPl. ha adott a már ismert Funkcionális if:<source lang="java">@FunctionalInterfacepublic interface MyFunction { MyString process(String input);}<//wwwsring>Akkor a funkcionális if definiálható a '''MyString::new''' konstruktor referenciával, ha rendelkezik String paraméterű konstruktorral: <source lang="java">public class MyString { private String input; public MyString(String input) { <<<<---------- ez itt a lényeg!!!! System.out.amitphprintln("MyString consturctor is called with input:" + input); this.cominput = input; } public String getInput() { return input; } }</source> <br>Nézzük a már ismert javaENUM-methodot, ezt egészítsük ki egy új értékkel: '''ENUMV2''', ahol a funkcionális if-andet a konstruktorban a 'MyString' konstruktor referenciájával adjuk meg: <source lang="java">public enum MyEnum2 { ENUMV1(var1 -> { System.out.println("ENUM lambda is called with input: " + var1); return new MyString(var1); }), ENUMV2(MyString::new) <<<-------------- ez itt a lényeg!!! ; private final MyFunction function; private MyEnum2(MyFunction function) { System.out.println("ENUM constructoris called with input"); this.function = function; } public MyFunction getFunction() { return function; }}</source> Ha példányosítjuk az enum-reference/ot a ENUMV2 értékkel, majd azon meghívjuk a funkcionális if process(..) metódusát, akkor fog lefutni a MyString konstruktora: <source lang="java"> System.out.println("START"); MyEnum2 myEnum22 =Method Reference==MyEnum2.ENUMV2; System.out.println("Enum was created"); myEnum22.getFunction().process("prcoess again");</source>
<br>
Az output az alábbi lesz:
<pre>
START
Enum was created
MyString consturctor is called with input:prcoess again
</pre>
<br>
<br>
==Constructor ReferenceMire használható (komplex példa)==<br><br>
=Stream=
https://stackify.com/streams-guide-java-8/
..TODO..