Van a következő két metódus, ami egyébként funkcióját tekintve ugyanazt csinálja, de a szemmel látható különbség hogy az egyik névtelen belső osztályt ad vissza a másik meg egy lambdát. Egy jobb IDE egy kattintással ide-oda tudja őket konvertálni, viszont van köztük egy óriási viselkedésbeli különbség, ami remek alkalmat adhat a saját magunk vagy mások lábon lövésére. Hajtás után elmondom, addig lehet rajta gondolkodni:
public Function<String, String> createInner1() {
return new Function<String, String>() {
@Override
public String apply(String t) {
return t + t;
}
};
}
public Function<String, String> createInner2() {
return t -> t + t;
}
Szóval a különbség az, hogy az első metódus (ami a névtelen osztályt adja vissza) mindenképpen elteszi magának a befoglaló objektum referenciáját. Még akkor is, ha nem használ semmit a befoglaló osztályból. Hogyha eltároljuk a visszatérési értéket, a befoglaló objektumot sem tudja majd a GC felszabadítani, alkalmat adva egy jó kis memory leak-re. Egy apró megjegyzés: Java-ban a "memory leak" nem létező fogalom. A helyes kifejezés "unintentional object retention", azaz szándékon kívüli objektum megtartás, legalábbis ahogy én fordítanám.
Ezzel szemben a második metódus -ha a lambda kifejezés nem használ semmit a befoglaló osztályból- nem tárolja el a befoglaló osztály referenciáját. Szóval ha arra számítunk hogy a befoglaló osztály még megmarad, lehet hogy pofára esünk, mert a GC megeszi reggelire.
Meg lehet kérdezni, hogy miért csinálna valaki ilyeneket, miért adna vissza egy Function-t, vagy névtelen belső osztályt visszatérési értéknek. Előfordulhat sok okból hasonló eset. Pl. vissza lehet adni egy Runnable-szerűséget későbbi végrehajtásra vagy listener működést lehet így megvalósítani. Satöbbi.
Java 8-asításnál gondoljunk ezekre az eshetőségekre.
Mondanom sem kell, hogy a bájtkód is teljesen más a két metódusnál. A lambdához valójában nem készül külön class-fájl, de a bájtkód-bányászatot meghagyom javax0-nak. :)