Abstrakte Klasse: vererbte Klasse; instance of?

Kababär

Top Contributor
Hi,

ich habe mir eine Abstrakte Klasse geschrieben

Code:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package financing.konto;

import financing.verwaltung.AuftragObject;
import java.util.ArrayList;
import java.util.List;

/**
*
* @author Blackace
*/
public abstract class AKonto {

    private String kontoName;
    private final String IBAN;
    private final String BIC;
    private double amount;
    private boolean allowsDisp;
    private double dispLimit;
    private List<AuftragObject> auftragList = new ArrayList<>();

    public AKonto(String IBAN, String BIC, double amount) {
        this.IBAN = IBAN;
        this.BIC = BIC;
        this.amount = amount;
    }

    public AKonto(String k, String IBAN, String BIC, double amount) {
        this.kontoName = k;
        this.IBAN = IBAN;
        this.BIC = BIC;
        this.amount = amount;
    }

    public AKonto(String k, String IBAN, String BIC, double amount,
            boolean canDispo) {
        this.kontoName = k;
        this.IBAN = IBAN;
        this.BIC = BIC;
        this.amount = amount;
        this.allowsDisp = canDispo;
    }

    public AKonto(String k, String IBAN, String BIC, double amount,
            boolean canDispo, double dispLimitation) {
        this.kontoName = k;
        this.IBAN = IBAN;
        this.BIC = BIC;
        this.amount = amount;
        this.allowsDisp = canDispo;
        this.dispLimit = dispLimitation;
    }

    public String getIBAN() {
        return IBAN;
    }

    public String getBIC() {
        return BIC;
    }

    public void pushAmount(AuftragObject i) {

        amount += i.getAmount();
    }

    public void popAmount(AuftragObject i) {
        amount -= i.getAmount();
    }

    public void transferAmount(AKonto from, AKonto to, AuftragObject a) {
        addAuftrag(a);
        from.popAmount(a);
        to.pushAmount(a);
    }

    public double getAmount() {
        return amount;
    }

    public String getKontoName() {
        return kontoName;
    }

    public void setKontoName(String k) {
        this.kontoName = k;
    }

    public boolean isAllowsDisp() {
        return allowsDisp;
    }

    public void setAllowsDisp(boolean allowsDisp) {
        this.allowsDisp = allowsDisp;
    }

    public double getDispLimit() {
        return dispLimit;
    }

    public void setDispLimit(double dispLimit) {
        this.dispLimit = dispLimit;
    }

    @Override
    public String toString() {
        return kontoName + "(" + IBAN + ")" + amount;
    }

    public List<AuftragObject> getAuftragList() {
        return auftragList;
    }

    public void setAuftragList(List<AuftragObject> auftragList) {
        this.auftragList = auftragList;
    }

    public void addAuftrag(AuftragObject a) {
        this.auftragList.add(a);
    }
}

und mehrere Klassen (Girokonto, Kreditkonto, Sparbuch), die von dieser Klasse erben.
Bei dem Konkreten Fall, dass ich ein Konto erstellen will, habe ich in meinem Model eine add-Methode.
Des Weiteren sind dort alle Listen für diese Konten gespeichert:

Code:
public class KontoModel {

    private List<Girokonto> giroList = new ArrayList<>();
    private List<Kreditkonto> kreditList = new ArrayList<>();
    private List<Sparbuch> sparList = new ArrayList<>();

    public List<Girokonto> getGiroList() {
        return giroList;
    }

    public void setGiroList(List<Girokonto> giroList) {
        this.giroList = giroList;
    }

    public List<Kreditkonto> getKreditList() {
        return kreditList;
    }

    public void setKreditList(List<Kreditkonto> kreditList) {
        this.kreditList = kreditList;
    }

    public List<Sparbuch> getSparList() {
        return sparList;
    }

    public void setSparList(List<Sparbuch> sparList) {
        this.sparList = sparList;
    }
   
   

    public void addKonto(AKonto konto) {
        switch () {
            case "Girokonto":

                break;
            case "Kreditkonto":

                break;
            case "Sparbuch":

                break;
            default:
                throw new AssertionError();
        }
    }

}

Bei dem unteren Teil hängt es nun, in der Add-Methode, denn ich weiß nicht wie ich herausfinden kann, welche Klasse AKonto nun explizit ist. Also ich gebe entweder im Parameter ein Girkonot, Sparbuch oder Kreditkonto mit.
Je nachdem welches Konto es ist, will ich es in die dementsprechende Liste packen.
Kann mir wer helfen?
Die Add-Methode ist noch unvollständig und fehlerhaft.
 
Du kannst dies entweder mit dem instanceof Operator oder per getClass machen. Schau dir diese zwei Möglichkeiten mal an, wenn du dann noch Fragen dazu hast frag ruhig nach.
 
Du kannst dies entweder mit dem instanceof Operator oder per getClass machen. Schau dir diese zwei Möglichkeiten mal an, wenn du dann noch Fragen dazu hast frag ruhig nach.
Instanceof bitte nicht und getClass() auf gar keinen Fall! Man sollte nie ein instanceof für Awnendungslogik brauchen, nie!

Die Klasse KontoModel ist absolut schlecht designed! Siehe dazu: sie macht das Open/Close- und das Liskovschke Substitutionsprinzip zunichte.

Mein Alternativvorschlag für ModelKonto, davon ausgehend, dass die Methodensignaturen von der Aufgabenstellung vorgeschrieben sind. (Denn die Methodensignaturen an sich verletzen die beiden oben genannten Gesetze):

Java:
public class KontoModel {

    private Set<AKonto> konten = new ArrayList<>();

    private Collection<T> <T extends AKonto> getAKontosOfType(Class<T> type) {
        return (Collection<T>) (konten.stream().filter(k -> k instanceof T).collect(Collectors.toCollection(ArrayList::new)));
    }
  
    private void <T extends AKonto> setTypeList(Collection<T> typedList) {
        Set<T> toBeRemoved = new HashSet<>();
        // entferne alle AKonto vom Typ T von konten, welche nicht in typedList sind
        for (AKonto k : konten) {
            if (k instanceof T && !typedList.contains(k)) {
                toBeRemoved.add(k);
            }
        }
        konten.removeAll(toBeRemoved);
      
        // die neuen konten hinzufügen
        konten.addAll(typedList);
    }
  
    public List<Girokonto> getGiroList() {
        return getAKontosOfType(Girokonto.class);
    }

    public void setGiroList(List<Girokonto> giroList) {
        setTypeList(giroList);
    }

    public List<Kreditkonto> getKreditList() {
        return getAKontosOfType(Kreditkonto.class);
    }

    public void setKreditList(List<Kreditkonto> kreditList) {
        setTypeList(kreditList);
    }

    public List<Sparbuch> getSparList() {
        return getAKontosOfType(Sparbuch.class);
    }

    public void setSparList(List<Sparbuch> sparList) {
        setTypeList(sparList);
    }
  
    public void addKonto(AKonto konto) {
        konten.add(konto);
    }
}

Mit dieser Version kann man mal zumindest neue Konten-Typen einführen, ohne KontoModel anfassen zu müssen. Aber instanceof ist immernoch in Verwendung, wenn auch die Vernwendung hier unkritisch ist.

Wenn die Methoden von KontoModel nicht vorgeschrieben sind, möchte ich diese Version vorschlagen:

Java:
public class KontoModel extends Set<AKonto> {
    public Collection<T> <T extends AKonto> getKontenVomTyp(Class<T> type) {
        return (Collection<T>) (stream().filter(k -> k instanceof T).collect(Collectors.toCollection(ArrayList::new)));
    }
}

Das kann imho genau die gleichen Anwendungsfälle abdecken und ist aus Design-Sicht (zwar nicht perfekt aber) deutlich besser als der Entwurf vom TE.

P.S.:
Es sieht so aus, als ob die Anwendung darauf angewiesen ist, die Konten nach Typ zu behandeln. Dort sitzt der Kern des Problems: Wenn man einmal eine Abstraktion einführt (in diesem Fall ist das die Methode addKonto(AKonto)), kann man sie an anderer Stelle nicht rückgängig machen, ohne sich tief ins eigene Fleisch zu schneiden. Die Abstraktion der Kontoarten zu AKonto sollte also an einer anderen Stelle stadtfinden.
 
Danke für deine ausführliche Antwort! Dass meine Designs von Projekten schlecht sind, merke ich selbst.. spätestens dann, wenn ich überlegen muss, wie ich nun an gewisse Objekte oder Klassen rankomme und wenn über zu viele Ecken geht oder wenn viele Klassen viele weitere Klassen importieren müssen, um an die Daten zu kommen..
Aber anders haben wir es bisher an der FH nicht gelernt. Model, Presenter (Controller), View.
Dabei war die Struktur jeweils so wie ich sie hatte.. immer ohne Generics. Wobei mir deine Version besser gefällt, auch wenn sie nicht durchsichtlich ist wie meine.

Also die Behandlung, um welchen Typ Konto es sich handelt, habe ich nun in meinen Controller gepackt und die jeweiligen Methoden in das Model gepackt:

Code:
public class KontoModel {

    private List<Girokonto> giroList = new ArrayList<>();
    private List<Kreditkonto> kreditList = new ArrayList<>();
    private List<Sparbuch> sparList = new ArrayList<>();
    private ListView giroLV, kreditLV, sparLV;

    public void addGiro(Girokonto g) {
        if (!giroList.contains(g)) {
            this.giroList.add(g);
            giroLV.getItems().setAll(giroList);
        }
    }

    public void addKredit(Kreditkonto k) {
        if (!kreditList.contains(k)) {
            this.kreditList.add(k);
            kreditLV.getItems().setAll(kreditList);
        }
    }

    public void addSpar(Sparbuch s) {
        if (!sparList.contains(s)) {
            this.sparList.add(s);
            sparLV.getItems().setAll(sparList);
        }
    }

    public List<Girokonto> getGiroList() {
        return giroList;
    }

    public void setGiroList(List<Girokonto> giroList) {
        this.giroList = giroList;
    }

    public List<Kreditkonto> getKreditList() {
        return kreditList;
    }

    public void setKreditList(List<Kreditkonto> kreditList) {
        this.kreditList = kreditList;
    }

    public List<Sparbuch> getSparList() {
        return sparList;
    }

    public void setSparList(List<Sparbuch> sparList) {
        this.sparList = sparList;
    }

    public ListView getGiroLV() {
        return giroLV;
    }

    public void setGiroLV(ListView giroLV) {
        this.giroLV = giroLV;
    }

    public ListView getKreditLV() {
        return kreditLV;
    }

    public void setKreditLV(ListView kreditLV) {
        this.kreditLV = kreditLV;
    }

    public ListView getSparLV() {
        return sparLV;
    }

    public void setSparLV(ListView sparLV) {
        this.sparLV = sparLV;
    }
}

Code:
@FXML
    public void createNewKonto() {
        if (createNewKontoNameFilled) {
            if (selectedDispoLimit == 0 && selectedIBAN.isEmpty()) {
                switch (createNewKontoArt) {
                    case "Girokonto":
                        kModel.addGiro(new Girokonto(selectedKontoname, selectedKap));
                        GUIUpdater.forceListRefreshOn(kModel.getGiroLV());
                        break;
                    case "Kreditkonto":
                        kModel.addKredit(new Kreditkonto(selectedKontoname, selectedKap));
                        GUIUpdater.forceListRefreshOn(kModel.getKreditLV());
                        break;
                    case "Sparbuch":
                        kModel.addSpar(new Sparbuch(selectedKontoname, selectedKap));
                        GUIUpdater.forceListRefreshOn(kModel.getSparLV());
                        break;
                }
            } else if (selectedDispoLimit == 0) {
                switch (createNewKontoArt) {
                    case "Girokonto":
                        kModel.addGiro(new Girokonto(selectedKontoname, selectedIBAN, selectedBIC, selectedKap));
                        GUIUpdater.forceListRefreshOn(kModel.getGiroLV());
                        break;
                    case "Kreditkonto":
                        kModel.addKredit(new Kreditkonto(selectedKontoname, selectedIBAN, selectedBIC, selectedKap));
                        GUIUpdater.forceListRefreshOn(kModel.getKreditLV());
                        break;
                    case "Sparbuch":
                        kModel.addSpar(new Sparbuch(selectedKontoname, selectedIBAN, selectedBIC, selectedKap));
                        GUIUpdater.forceListRefreshOn(kModel.getSparLV());
                        break;
                }
            } else if (selectedIBAN.isEmpty()) {
                switch (createNewKontoArt) {
                    case "Girokonto":
                        kModel.addGiro(new Girokonto(selectedKontoname, selectedKap, canDispo, selectedDispoLimit));
                        GUIUpdater.forceListRefreshOn(kModel.getGiroLV());
                        break;
                    case "Kreditkonto":
                        kModel.addKredit(new Kreditkonto(selectedKontoname, selectedKap, canDispo, selectedDispoLimit));
                        GUIUpdater.forceListRefreshOn(kModel.getKreditLV());
                        break;
                    case "Sparbuch":
                        kModel.addSpar(new Sparbuch(selectedKontoname, selectedKap, canDispo, selectedDispoLimit));
                        GUIUpdater.forceListRefreshOn(kModel.getSparLV());
                        break;
                }
            }
        }
    }

Das funktioniert zwar, gefällt mir aber auch nicht..
 
Dass meine Designs von Projekten schlecht sind, merke ich selbst. [...] Aber anders haben wir es bisher an der FH nicht gelernt. Model, Presenter (Controller), View.
Dass du es selbst merkst ist schon ein guter Anfang 😉 Und ich helfe dir auch gerne, das zu verbessern 🙂


Zu deinem Model:
Dass das Model an der View rumschraubt gefällt mir garnicht (siehe SRP = Single-Responsibility-Prinzip (aka SoC = Separation of Concerns Principle)). Wie geht das besser? Mein Vorschlag:

Im MVC ist das Model für die Datenhaltung zuständig. Und nach SRP sollte es nicht mit der View interagieren (denn die Haltung der Daten hat mit der Darstellung der selbigen erstmal nix zu tun). Das Model kann aber sehr wohl Listener aufrufen, wenn es sich ändert (Listener sind ja komplett unabhängig). Und das View kann darauf reagieren und sie Darstellung korrigieren:

Java:
/**
* Ersetzt KontoModel; in einer Enterprise-Anwendung passiert hier auch die DB-Kommunikation (und NUR hier, wieder SRP).
*/
class AccountRepository {
    private Set<Konto> accounts = new HashSet<>();

    private Set<Consumer<Konto>> accountAddedListeners = new HashSet<>();
    private Set<Consumer<Konto>> accountRemovedListeners = new HashSet<>();
  
    public void addAccount(AKonto konto) {
        if (accounts.add(konto)) {
            accountAddedListeners.forEach(c -> c.accept(konto));
        }
    }
  
    public void removeAccount(AKonto konto) {
        if (accounts.add(konto)) {
            accountRemovedListeners.forEach(c -> c.accept(konto));
        }
    }
  
    public void onAccountAdded(Consumer<AKonto> l) {
        accountAddedListeners.add(l);
    }
  
    public void onAccountRemoved(Consumer<AKonto> l) {
        accountRemovedListeners.add(l);
    }
  
    public Collection<T> <T extends AKonto> getAccountsOfType(Class<T> type) {
        return (Collection<T>) (accounts.stream().filter(k -> k instanceof T).collect(Collectors.toCollection(ArrayList::new)));
        // in einer enterprise anwendung würde hier ein HQL query stehen, etwa: FROM AKonto WHERE class = T.class
    }
}

Und dann kannst du in deiner View ganz bequem listener beim Repository registrieren:

Java:
accountRespository.onAccountAdded(konto -> {
    if (konto instanceof Girokonto) {
        giroLV.add(konto);
    }
    ... u.s.w.
});
Aber auch hier ist wieder das Problem mit der Abstraktion: wenn du im Model zu AKonto abstrahierst, musst du es im View wieder aufdröseln. Deswegen die Abstraktion komplett durchziehen (den Typ ggf. in der ListView erwähnen?) oder die Abstraktion entfernen.
 
@Tobse Mit Consumer hatte ich bisher noch nichts am Hut gehabt, aber werde mir mal angucken was diese Datenstruktur so drauf hat und wozu man die verwenden kann.
Dann werde ich mal deine Ratschläge in meinen Code einbauen und sehen, ob ich alles so geändert bekomme, dass noch alles läuft. Die Seite ooodesign scheint vernünftig zu sein, die kommt mal in meine Lesenzeichen-Liste 🙂

Eben. Warum dann nicht einfach subclassen ?

Ganz am Anfang hatte ich mir überlegt, ob es nicht einfach schon reicht, eine Klasse Konto zu erstellen und als Klassenattribut ein String zu definieren a la "Kontotyp". So hätte ich zwar keine 3 Klassen, aber das Design wäre auch nicht gerade gut. Du meinst also einfach das Abstract weglassen? Werde ich umsetzen, danke 🙂

Edit:
Code:
    public Collection<T> <T extends AKonto> getAccountsOfType(Class<T> type) {
        return (Collection<T>) (accounts.stream().filter(k -> k instanceof T).collect(Collectors.toCollection(ArrayList::new)));
        // in einer enterprise anwendung würde hier ein HQL query stehen, etwa: FROM AKonto WHERE class = T.class
    }
Da meint der Compiler: "unexcepted return value" :s
 
Zuletzt bearbeitet:
Code:
    public Collection<T> <T extends AKonto> getAccountsOfType(Class<T> type) {
        return (Collection<T>) (accounts.stream().filter(k -> k instanceof T).collect(Collectors.toCollection(ArrayList::new)));
        // in einer enterprise anwendung würde hier ein HQL query stehen, etwa: FROM AKonto WHERE class = T.class
    }
Da meint der Compiler: "unexcepted return value" :s
Versuch mal public <T extends AKonto> Collection<T> getAccountsOfType
 
Wenn die drei Klassen wirklich gleich sind, ist es sehr unnötig das mit Vererbung zu lösen. Da wäre es besser den Typ einfach als attribut anzugeben.
Java:
public enum KontoTyp {
  GIRO, KREDIT, SPAR
}
public class Konto {
  private final KontoTyp typ;
  public KonoTyp getTyp() { return typ; }
  public Konto(KontoTyp typ) {
    this.typ = typ;
  }
}
 
Auch nicht schlecht! So meinte ich das. Dann arbeite ich auch mal mit enums 😀 Wollte es schon ein paar Mal erzwingen, aber das war dann letztendlich nonsense (bei anderen Projekten).
 
Nur meckert er noch " illegal generic type for instanceof". Wenn ich type reinschreibe, ist die Sichtbarkeit weg (denke ich mal). Muss ich hier die drei Fälle "Girokonto", "Kreditkonto" und "Sparbuch" unterscheiden?
Die Methode ist ja genau deshalb generisch, weil sie für alle Unterklassen, bekannte und unbekannte, funktionieren soll.

Ich habe jetzt mal selber den Compiler bemüht und es sieht so aus, als ob man Generics nicht mit dem Instanceof verbinden kann. Daher muss man auf die java.lang.Class zurückgreiffenm und das ist eklig.... genau deshalb will man sowas ja eigentlich vermeiden :/
Dashier wird funktionieren:

Java:
public <T extends Super> Collection<T> getAccountsOfType(Class<T> type) {
    return (Collection<T>) (accounts.stream().filter(k -> type.isAssignableFrom(k.getClass())).collect(Collectors.toCollection(ArrayList::new)))
}
 
Nachdem ich den Vorschlag von InfectedBytes implementiert habe, muss ich statt

Code:
k -> k instanceof T
nur noch
Code:
 k-> k.getType().equals(type)
schreiben mit dem entsprechenden Parameter
Code:
 Konto.KontoTyp typ


Ich danke euch und werde mich bemühen, dieses Konzept beizubehalten 🙂
 
Da ich meine Liste, je nachdem welcher Kontotyp es ist, filtern will, um das Konto in die dementsprechende ListView einzutragen, wird das so nicht funktionieren denke ich..

Aber es passt ja alles so wie es ist 🙂

Was mir aber noch schleierhaft ist: mit Consumer kann ich mir quasi eigene Listener basteln? Immer wenn sich etwas an meiner Datenstruktur geändert, kann ich dazu ein geeignetes Event triggern? Das eröffnet ja ungeahnte Möglichkeiten.
Habe mich schon oft gefragt, ob so was nicht geht.. aber da fand ich nur so was wie "Ahja.. dann rufst du halt jedes mal die Methode auf".
 
Zuletzt bearbeitet:
du kannst direkt: if(k.getTyp() == KontoTyp.GIRO) ... verwenden
Und was genau ist daran jetzt besser als ein instanceof? Das Enum erfüllt das Substitutionsprinzip, das Open/Close-Prinzip bleibt aber weiterhin verletzt...


Was mir aber noch schleierhaft ist: mit Consumer kann ich mir quasi eigene Listener basteln? Immer wenn sich etwas an meiner Datenstruktur geändert, kann ich dazu ein geeignetes Event triggern? Das eröffnet ja ungeahnte Möglichkeiten.
Habe mich schon oft gefragt, ob so was nicht geht.. aber da fand ich nur so was wie "Ahja.. dann rufst du halt jedes mal die Methode auf".
Consumer ist eigentlich für etwas anderes gedacht; Ich habe es nur der Einfachheit her verwendet. Richtig wäre folgendes:

Java:
class AccountRepository {
  /* ... der ganze andere Code ... */

  interface AccountAddedListener {
    public void onAccountAdded(AKonto konto);
  }

  interface AccountRemovedListener {
    public void onAccountRemoved(AKonto konto);
  }
}

Und dann entsprechend diese Klassen anstatt Consumer<AKonto> verwenden.
In Java 8 bleibt aber der Code im View gleich:

Java:
AccountRepository accountRepository = new AccountRepository();
accountRepository.onAccountAdded(k -> System.out.println("Account " + k + " hinzugefügt"));
 
Also am besten statt dem Enum ein Interface beziehungsweise eine eigene Klasse implementieren?

Habe mir mal eben Consumer, Supplier etc angeguckt und verstehe nicht so wirklich wofür das gut sein soll.. Aber vielleicht stoße ich irgendwann nochmal drüber wo die Funktionalität klarer wird.
 
Also am besten statt dem Enum ein Interface beziehungsweise eine eigene Klasse implementieren?
Ich glaube du vermischt gerade die Listener mit den Kontotyp. Ich wollte das nicht in Bezug zueinander setzen, weils nix miteinander zu tun hat. Wenn du das anders meinst stehe ich ggf. bissl aufm Schlauch...

[OFFTOPIC]

Habe mir mal eben Consumer, Supplier etc angeguckt und verstehe nicht so wirklich wofür das gut sein soll.. Aber vielleicht stoße ich irgendwann nochmal drüber wo die Funktionalität klarer wird.
Das ist jetzt schon sehr Offtopic hier. Consumer sind für sowas gedacht:

Java:
// ausgangssituation:
List<String> liste = Arrays.asList("foo", "bar", "hanz", "peter", "javaforum");


liste.forEach(System.out::println);

// das ist gleichbedeutend mit
liste.forEach(e -> System.out.println(e));

// und auch gleichbedeutend mit
liste.forEach(e -> { 
    System.out.println(e);
});

// und gleichbedeutend mit
liste.forEach(new Consumer<String>() {
    @Override
    public void accept(String e) {
        System.out.println(e);
    }
});
Consumer<E> wurde für die Lambdas in Java 8 eingeführt; ist besonders bei Streams hifreich.


[/OFFTOPIC]
 
das Substitutionsprinzip sollte man doch auch auf Klassen anwenden, nicht nur auf Interfaces oder? Also so, dass eine Klasse genau eine Aufgabe hat.
Bspw würde ich eine Klasse IO in zwei Klassen Writer und Reader splitten.

Ich habe mir Consumer nochmal angeguckt und die sind, so wie es im Buch stand, quasi durch Function ersetzbar. Der Vorteil ist doch, dass ich im Block eines Consumers ja eine Reihe Anweisungen schreiben kann ähnliche einer Methode, aber den Consumer selbst, der die Anweisungen enthält, als Objekt verwalten kann so wie wir das oben bei unsrer Liste gemacht haben?
 
das Substitutionsprinzip sollte man doch auch auf Klassen anwenden, nicht nur auf Interfaces oder? Also so, dass eine Klasse genau eine Aufgabe hat.
Bspw würde ich eine Klasse IO in zwei Klassen Writer und Reader splitten.
Jetzt verwechselst du das Substitutionsprinzip mit dem Single-Responsibility-Prinzip :S Interfaces erleichtern die Anwendung des Substitutionsprinzips (weil man leichter ein Interface implementieren als von einer Klasse erben kann).

Ich habe mir Consumer nochmal angeguckt und die sind, so wie es im Buch stand, quasi durch Function ersetzbar. Der Vorteil ist doch, dass ich im Block eines Consumers ja eine Reihe Anweisungen schreiben kann ähnliche einer Methode, aber den Consumer selbst, der die Anweisungen enthält, als Objekt verwalten kann so wie wir das oben bei unsrer Liste gemacht haben?
Consumer<E> ist ein Interface wie jedes andere. Die Besonderheit daran ist, dass es ein SAM (Single Abstract Method)-Interface ist und damit Lambdas erlaubt. Lambdas sind nur eine hübschere Schreibweise für innere Klassen, mehr nicht.
 

Zurück
Oben