Java 8 fügte das Konzept der funktionalen Schnittstellen sowie zahlreiche neue Methoden hinzu, mit denen funktionale Schnittstellen verwendet werden können. Instanzen dieser Schnittstellen können mithilfe von Methodenreferenzausdrücken (z. B. SomeClass::someMethod
) und Lambda-Ausdrücken (z (x, y) -> x + y
. B. ) prägnant erstellt werden .
Ein Kollege und ich haben unterschiedliche Meinungen darüber, wann es am besten ist, das eine oder andere Formular zu verwenden (wobei "am besten" in diesem Fall wirklich auf "am besten lesbar" und "am besten im Einklang mit Standardpraktiken" hinausläuft, da sie im Grunde genommen anders sind Äquivalent). Dies betrifft insbesondere den Fall, dass alle der folgenden Punkte zutreffen:
- Die betreffende Funktion wird nicht außerhalb eines einzelnen Bereichs verwendet
- Wenn Sie der Instanz einen Namen geben, wird die Lesbarkeit verbessert (im Gegensatz dazu, dass die Logik einfach genug ist, um auf einen Blick zu sehen, was passiert).
- Es gibt keine anderen Programmiergründe, warum ein Formular dem anderen vorzuziehen wäre.
Meine derzeitige Meinung zu diesem Thema ist, dass das Hinzufügen einer privaten Methode und das Verweisen auf diese als Methodenreferenz der bessere Ansatz ist. Es sieht so aus, als ob die Funktion so konzipiert wurde, dass sie verwendet werden soll, und es scheint einfacher zu sein, über Methodennamen und Signaturen zu kommunizieren, was vor sich geht (z. B. "boolean isResultInFuture (Result result)" bedeutet eindeutig, dass es einen boolean zurückgibt). Dadurch wird die private Methode auch wiederverwendbarer, wenn eine zukünftige Erweiterung der Klasse dieselbe Prüfung verwenden möchte, jedoch den Wrapper für die funktionale Schnittstelle nicht benötigt.
Mein Kollege bevorzugt eine Methode, die die Instanz der Schnittstelle zurückgibt (z. B. "Predicate resultInFuture ()"). Für mich scheint es nicht ganz so zu sein, wie die Funktion verwendet werden sollte, es fühlt sich etwas klobiger an und es scheint schwieriger zu sein, Absichten wirklich durch Benennung zu kommunizieren.
Um dieses Beispiel konkret zu machen, ist hier derselbe Code, der in den verschiedenen Stilen geschrieben wurde:
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
results.filter(this::isResultInFuture).forEach({ result ->
// Do something important with each future result line
});
}
private boolean isResultInFuture(Result result) {
someOtherService.getResultDateFromDatabase(result).after(new Date());
}
}
vs.
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
results.filter(resultInFuture()).forEach({ result ->
// Do something important with each future result line
});
}
private Predicate<Result> resultInFuture() {
return result -> someOtherService.getResultDateFromDatabase(result).after(new Date());
}
}
vs.
public class ResultProcessor {
public void doSomethingImportant(List<Result> results) {
Predicate<Result> resultInFuture = result -> someOtherService.getResultDateFromDatabase(result).after(new Date());
results.filter(resultInFuture).forEach({ result ->
// Do something important with each future result line
});
}
}
Gibt es offizielle oder halboffizielle Dokumentationen oder Kommentare dazu, ob ein Ansatz bevorzugter, besser auf die Absichten der Sprachdesigner abgestimmt oder besser lesbar ist? Gibt es, abgesehen von einer offiziellen Quelle, klare Gründe, warum einer der bessere Ansatz wäre?
Object::toString
). Meine Frage ist also mehr, ob es in dieser bestimmten Art von Instanz, die ich hier darlege, besser ist, als ob es Instanzen gibt, in denen eine besser ist als die andere, oder umgekehrt.