Java 8 – Default Method

Eine der wichtigen Erweiterungen in Java 8 werden die sogenannten „Default Methods“ sein. Diese werden in Interfaces definiert und sind nicht abstrakt, sie haben einen Methodenrumpf.
Im folgenden Beispiel hat die Methode isSquare des Interfaces Rectangle eine Default-Implementierung. Die Klassen, die Rectangle implementieren, müssen nicht isSquare implementieren, sondern können die Default-Implementierung erben.

public interface Rectangle {
    double getWidth();
    double getHeight();
    boolean isSquare() default {
        return getWidth() == getHeight();
    }
}

Die Klasse SimpleRectangle impentiert nicht isSquare, sondern erbt die Default-Implementierung.

public class SimpleRectangle implements Rectangle {
    private final double width;
    private final double height;
    public SimpleRectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    public double getHeight() {
        return height;
    }
    public double getWidth() {
        return width;
    }
}


Desweiteren können Default-Implementierung überschrieben werden.

public class Square implements Rectangle {
    private final double size;
    public Square(double size) {
        this.size = size;
    }
    public double getHeight() {
        return size;
    }
    public double getWidth() {
        return size;
    }
    public boolean isSquare() { // Redefinition der Default-Methode
        return true;
    }
}

Was geht nicht?

  • Default-Implementierungen haben keinen Zugriff auf Objektvariablen. (Daher kann durch die Anwendung von Default-Implementierungen nicht der Zustand der implementierenden Klasse verändert werden)
  • Wenn eine Klasse zwei Interfaces implementiert, die jeweils für die gleichen Methoden-Signaturen Default-Implementierungen enthalten, kommt es zum Compile-Error.

  • Die Methoden-Implementierung einer Klasse überlagert immer einer Default-Implementierung mit identischen Signatur.

Was bringt das Ganze?

  • Bislang mussten Methoden, die nicht von allen implementierenden Klasse verwendet wurden, von jeder Klassen implementiert werden. Hierzu ein Beispiel ohne Default-Implentierung:
public interface Transformer extends ContentHandler {
    /**
     * Initialize this component.
     * @param context The invocation context.
     * @param config The configuration for this component.
     */
    void init(ProcessingContext context, ProcessingComponentConfiguration config)
    throws IOException;
    ...
}
public abstract class AbstractTransformer implements Transformer {
    protected ContentHandler contentHandler;
    @Override
    public void init(final ProcessingContext context, final ProcessingComponentConfiguration config) throws IOException {
        // do nothing
    }
    ...
}

Und ein Beispiel mit Default Implementierung:

public interface Transformer extends ContentHandler {
    /**
     * Initialize this component.
     * @param context The invocation context.
     * @param config The configuration for this component.
     */
    void init(ProcessingContext context, ProcessingComponentConfiguration config)
    throws IOException default {}
    ...
}
public abstract class AbstractTransformer implements Transformer {
    protected ContentHandler contentHandler;
    ...
}
  • Bestehende Interfaces können um neue Methoden erweitert werden, ohne dass alle implementierenden Klassen die neuen Methoden implementieren müssen. Somit können sorgenfreier Interfaces erweitert und geändert werden. Die Java API kann erweitert werden, ohne dass existierender Code davon beeinflußt werden muss. Ein Beispiel ist das Interface Iterable, welches in Java 8 um weitere Methoden ergänzt wurde, die Default-Implementierungen enthalten. Bislang definiert das Interface nur eine Methode:
    • Iterator<T> iterator();
      In Java 8 werden folgende Methoden hinzukommen:
    • Iterable<T> filter(Predicate<T> predicate)
    • Iterable<T> forEach(Block<T> block)
    • <U> Iterable<U> map(Mapper<T, U> mapper)
    • T reduce(T base, Operator<T> reducer)
    • <U> U mapReduce(Mapper<T, U> mapper, U base, Operator<U> reducer)
    • boolean anyMatch(Predicate<T> filter)
    • boolean noneMatch(Predicate<T> filter)
    • boolean allMatch(Predicate<T> filter)

Ohne Default Implementierungen wären alle Implementierungen des Iterator Interfaces ungültig. Jede implementierende Klasse müsste alle im Interface definierten Methoden implementieren. Durch die Verwendung von Default-Implementierungen der neuen Methoden behalten die Iterator implementierenden Klassen ihre Gültigkeit.

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s