Aki követi a Java fejlődését, találhat egy érdekességet a JDK8 (Lambda build) kipróbálható verziójában, amely letölthető a http://jdk8.java.net/lambda/ oldalról: az interfészekben meg tudunk adni alapértelmezett kódrészletet, amely felüldefiniálható a leszármazott osztályban. A megoldás előnye, hogy ezzel lehetőségünk van egy interfészhez hozzáadni egy új metódust, s bevezetéséhez nem kell az összes leszármazottban ezt az új metódust implementálnunk.
Nézzünk egy példát, hozzunk létre egy interfészt, amelynek legyen egy meglévő metódusa, illetve egy új metódust, amelyet nem szeretnénk a leszármazott osztályokban implementálni:
interface LambdaInterface { public void oldMethod(); public void newMethod() default { System.out.println("Default behaviour"); } } |
A megfelelő JDK8 használatával könnyedén lefordíthatjuk:
$ /opt/jdk1.8.0/bin/java -version openjdk version "1.8.0-ea" OpenJDK Runtime Environment (build 1.8.0-ea-lambda-nightly-h161-20120511-b39-b00) OpenJDK 64-Bit Server VM (build 24.0-b07, mixed mode) $ /opt/jdk1.8.0/bin/javac LambdaInterface.java |
Készítsünk egy implementációt, amely nem implementál egy metódust sem:
public class LambdaImplementation implements LambdaInterface { } |
Fordításkor nyilván panaszkodni fog a fordító, hogy nem implementáltuk az oldMethod metódust:
$ /opt/jdk1.8.0/bin/javac LambdaImplementation.java LambdaImplementation.java:1: error: LambdaImplementation is not abstract and does not override abstract method oldMethod() in LambdaInterface public class LambdaImplementation implements LambdaInterface ^ 1 error |
Implementáljuk a hiányolt metódust:
public class LambdaImplementation implements LambdaInterface { public void oldMethod() { System.out.println("Implemented oldMethod"); } } |
Majd fordítsuk le, amely során azt kell tapasztalnunk, hogy hiba nélkül fordul:
$ /opt/jdk1.8.0/bin/javac LambdaImplementation.java $ |
Írjunk gyorsan futtató osztályt, amely egyszerűen példányosítja az implementációt, majd meghívja az interfész két metódusát:
public class LambdaRun { public static void main(String[] args) { LambdaInterface li = new LambdaImplementation(); li.oldMethod(); li.newMethod(); } } |
A fordítás után, illetve futtatás során az alábbit kell lássuk:
$ /opt/jdk1.8.0/bin/javac LambdaRun.java $ /opt/jdk1.8.0/bin/java LambdaRun Implemented oldMethod Default behaviour $ |
A newMethod metódust nem kellett implementálnunk, s a futtatás során lefutott a általunk megadott alapértelmezett metódustörzs.
Amint az kitalálható: ha implementáljuk az új metódust is...
public class LambdaImplementation implements LambdaInterface { public void oldMethod() { System.out.println("Implemented oldMethod"); } public void newMethod() { System.out.println("Implemented newMethod"); } } |
...akkor az implementáció metódustörzse fog lefutni:
$ /opt/jdk1.8.0/bin/javac LambdaImplementation.java $ /opt/jdk1.8.0/bin/java LambdaRun Implemented oldMethod Implemented newMethod |
Az emberben felmerül a kérdés, hogy a megoldással viszünk-e a platformba bizonytalanságot, ha két interfészben azonos metódus szignatúrát vértezünk fel alapértelmezett metódussal, ezért hozzuk létre egy új interfészt:
interface LambdaInterfaceOther { public void oldMethod(); public void newMethod() default { System.out.println("Other default behaviour"); } } |
Látható, hogy a két interfész azonos metódusokat tartalmaz, ám a newMethod metódus mindkettőben tartalmaz különböző metódustörzset. Módosítsuk az implementációt, implementálja mind a két interfészt:
public class LambdaImplementation implements LambdaInterface, LambdaInterfaceOther { public void oldMethod() { System.out.println("Implemented oldMethod"); } } |
A fordításnál kiderül, hogy ez a módszer így nem működik:
$ /opt/jdk1.8.0/bin/javac LambdaImplementation.java LambdaImplementation.java:1: error: class LambdaImplementation inherits unrelated defaults for newMethod() from types LambdaInterface and LambdaInterfaceOther public class LambdaImplementation implements LambdaInterface, LambdaInterfaceOther ^ 1 error |
A fenti példát továbbgondolva nézzünk meg egy olyan esetet, amikor egy interfészt két újabb interfész bővít ki, majd az implementáció megvalósítja ezen két új interfész összes metódusát. A próbához javítsuk ki a fent elrontott LambdaInterfaceOther interfészt:
interface LambdaInterfaceOther extends LambdaInterface { public void otherMethod(); } |
Majd hozzunk létre egy új interfészt:
interface LambdaInterfaceFoo extends LambdaInterface { public void fooMethod(); } |
Az interfészekkel készen is lennénk, már csak módosítani kell az implementációt:
public class LambdaImplementation implements LambdaInterfaceOther, LambdaInterfaceFoo { public void oldMethod() { System.out.println("Implemented oldMethod"); } public void otherMethod() { System.out.println("Implemented otherMethod"); } public void fooMethod() { System.out.println("Implemented fooMethod"); } } |
A LambdaRun osztály kicsit módosítanunk kell:
public class LambdaRun { public static void main(String[] args) { LambdaInterface li = new LambdaImplementation(); li.oldMethod(); li.newMethod(); ((LambdaInterfaceOther)li).otherMethod(); ((LambdaInterfaceFoo)li).fooMethod(); } } |
Az eredmény:
$ /opt/jdk1.8.0/bin/javac LambdaInterface.java LambdaInterfaceOther.java LambdaInterfaceFoo.java LambdaImplementation.java LambdaRun.java $ /opt/jdk1.8.0/bin/java LambdaRun Implemented oldMethod Default behaviour Implemented otherMethod Implemented fooMethod |
Ha egy meglévő interfész kibővítésére volt szükségünk, akkor két lehetőségünk volt:
Ez a megoldás hasznos dolognak tűnik... szerinted is?