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.

Az interfész

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

Az üres implementáció

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áció egy metódussal

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.

Implementáció két metódussal

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

Két interfészben azonos alapértelmezett metódus?

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

Két leszármazott interfész implementálása

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

Vélemény?

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? (smile)