Advertisement
  1. Code
  2. Java 8

Java 8 für Android-Entwicklung: Standard- und statische Methoden

by
Read Time:11 minsLanguages:
This post is part of a series called Java 8 for Android Development.
Java 8 for Android: Cleaner Code With Lambda Expressions
Java 8 for Android Development: Stream API and Date & Time Libraries

German (Deutsch) translation by Federicco Ancie (you can also view the original English article)

Java 8 war ein großer Fortschritt für die Programmiersprache und jetzt, mit der Veröffentlichung von Android Studio 3.0, haben Android-Entwickler endlich Zugriff auf die integrierte Unterstützung für einige der wichtigsten Funktionen von Java 8.

In dieser dreiteiligen Serie haben wir die Java 8-Funktionen untersucht, die Sie heute in Ihren Android-Projekten verwenden können. In Cleaner Code With Lambda Expressions haben wir unsere Entwicklung so eingerichtet, dass die Java 8-Unterstützung der Standard-Toolchain von Android verwendet wird, bevor wir uns eingehend mit Lambda-Ausdrücken befassen.

In diesem Beitrag werden zwei verschiedene Möglichkeiten untersucht, wie Sie nicht abstrakte Methoden in Ihren Schnittstellen deklarieren können (was in früheren Java-Versionen nicht möglich war). Wir werden auch die Frage beantworten, was genau der Unterschied zwischen abstrakten Klassen und Schnittstellen ist, nachdem Schnittstellen Methoden implementieren können.

Wir werden auch eine Java 8-Funktion behandeln, mit der Sie die gleiche Anmerkung so oft verwenden können, wie Sie möchten, und gleichzeitig mit früheren Android-Versionen abwärtskompatibel bleiben.

Schauen wir uns zunächst eine Java 8-Funktion an, die in Kombination mit den Lambda-Ausdrücken verwendet werden kann, die wir im vorherigen Beitrag gesehen haben.

Schreiben Sie cleanere Lambda-Ausdrücke mit Methodenreferenzen

Im letzten Beitrag haben Sie gesehen, wie Sie Lambda-Ausdrücke verwenden können, um viel Boilerplate-Code aus Ihren Android-Anwendungen zu entfernen. Wenn ein Lambda-Ausdruck jedoch einfach eine einzelne Methode aufruft, die bereits einen Namen hat, können Sie mithilfe einer Methodenreferenz noch mehr Code aus Ihrem Projekt herausschneiden.

Zum Beispiel leitet dieser Lambda-Ausdruck die Arbeit nur an eine vorhandene handleViewClick-Methode um:

In diesem Szenario können wir mit dem Referenzoperator :: method auf diese Methode namentlich verweisen. Sie erstellen diese Art von Methodenreferenz im folgenden Format:

In unserem Beispiel für den Floating Action Button können wir eine Methodenreferenz als Hauptteil unseres Lambda-Ausdrucks verwenden:

Beachten Sie, dass die referenzierte Methode dieselben Parameter wie die Schnittstelle annehmen muss - in diesem Fall ist dies View.

Sie können den Methodenreferenzoperator (::) verwenden, um auf Folgendes zu verweisen:

Eine statische Methode

Wenn Sie einen Lambda-Ausdruck haben, der eine statische Methode aufruft:

Dann können Sie daraus eine Methodenreferenz machen:

Wenn Sie beispielsweise eine statische Methode PrintMessage in einer MyClass-Klasse hätten, würde Ihre Methodenreferenz ungefähr so aussehen:

Eine Instanzmethode eines bestimmten Objekts

Dies ist eine Instanzmethode eines Objekts, die im Voraus bekannt ist. Sie können Folgendes ersetzen:

Mit:

Wenn Sie also den folgenden Lambda-Ausdruck hätten:

Wenn Sie dann eine Methodenreferenz einführen, erhalten Sie Folgendes:

Eine Instanzmethode eines beliebigen Objekts eines bestimmten Typs

Dies ist eine Instanzmethode eines beliebigen Objekts, das später bereitgestellt und im folgenden Format geschrieben wird:

Konstruktorreferenzen

Konstruktorreferenzen ähneln Methodenreferenzen, außer dass Sie das Schlüsselwort new verwenden, um den Konstruktor aufzurufen. Beispielsweise ist Button::new eine Konstruktorreferenz für die Klasse Button, obwohl der genaue aufgerufene Konstruktor vom Kontext abhängt.

Mithilfe von Konstruktorreferenzen können Sie Folgendes ändern:

In:

Wenn Sie die folgende MyInterface-Oberfläche hatten:

Dann können Sie Konstruktorreferenzen verwenden, um neue Student-Instanzen zu erstellen:

Es ist auch möglich, Konstruktorreferenzen für Array-Typen zu erstellen. Eine Konstruktorreferenz für ein Array von int lautet beispielsweise int[]::new.

Fügen Sie Ihren Schnittstellen Standardmethoden hinzu

Vor Java 8 konnten Sie nur abstrakte Methoden in Ihre Schnittstellen aufnehmen (d.h. Methoden ohne Body), was die Entwicklung von Schnittstellen nach der Veröffentlichung erschwerte.

Jedes Mal, wenn Sie einer Schnittstellendefinition eine Methode hinzufügen, fehlt allen Klassen, die diese Schnittstelle implementiert haben, plötzlich eine Implementierung. Wenn Sie beispielsweise eine Schnittstelle(MyInterface) hatten, die von MyClass verwendet wurde, würde das Hinzufügen einer Methode zu MyInterface die Kompatibilität mit MyClass beeinträchtigen.

Im besten Fall, in dem Sie für die geringe Anzahl von Klassen verantwortlich waren, die MyInterface verwendeten, wäre dieses Verhalten ärgerlich, aber überschaubar. Sie müssten nur einige Zeit einplanen, um Ihre Klassen mit der neuen Implementierung zu aktualisieren. Es könnte jedoch viel komplizierter werden, wenn eine große Anzahl von Klassen MyInterface implementiert oder wenn die Schnittstelle in Klassen verwendet wird, für die Sie nicht verantwortlich sind.

Obwohl es eine Reihe von Problemumgehungen für dieses Problem gab, war keine davon ideal. Sie könnten beispielsweise neue Methoden in eine abstrakte Klasse aufnehmen, dies würde jedoch weiterhin erfordern, dass jeder seinen Code aktualisiert, um diese abstrakte Klasse zu erweitern. Während Sie die ursprüngliche Schnittstelle um eine neue Schnittstelle erweitern könnten, müsste jeder, der diese neuen Methoden verwenden möchte, alle vorhandenen Schnittstellenreferenzen neu schreiben.

Mit der Einführung von Standardmethoden in Java 8 ist es jetzt möglich, nicht abstrakte Methoden (d.h. Methoden mit einem Body) in Ihren Schnittstellen zu deklarieren, sodass Sie endlich Standardimplementierungen für Ihre Methoden erstellen können.

Wenn Sie Ihrer Schnittstelle standardmäßig eine Methode hinzufügen, muss für jede Klasse, die diese Schnittstelle implementiert, nicht unbedingt eine eigene Implementierung bereitgestellt werden. Auf diese Weise können Sie Ihre Schnittstellen aktualisieren, ohne die Kompatibilität zu beeinträchtigen. Wenn Sie einer Schnittstelle als Standardmethode eine neue Methode hinzufügen, erbt jede Klasse, die diese Schnittstelle verwendet, aber keine eigene Implementierung bereitstellt, einfach die Standardimplementierung der Methode. Da der Klasse keine Implementierung fehlt, funktioniert sie weiterhin wie gewohnt.

Tatsächlich war die Einführung von Standardmethoden der Grund dafür, dass Oracle in Java 8 eine so große Anzahl von Ergänzungen zur Collections-API vornehmen konnte.

Collection ist eine generische Schnittstelle, die in vielen verschiedenen Klassen verwendet wird. Das Hinzufügen neuer Methoden zu dieser Schnittstelle kann daher unzählige Codezeilen beschädigen. Anstatt der Collection-Schnittstelle neue Methoden hinzuzufügen und jede von dieser Schnittstelle abgeleitete Klasse zu unterbrechen, hat Oracle die Standardmethodenfunktion erstellt und diese neuen Methoden dann als Standardmethoden hinzugefügt. Wenn Sie sich die neue Collection.Stream() -Methode ansehen (die wir in Teil 3 ausführlich untersuchen werden), werden Sie feststellen, dass sie als Standardmethode hinzugefügt wurde:

Das Erstellen einer Standardmethode ist einfach: Fügen Sie Ihrer Methodensignatur einfach den default modifikator hinzu:

Wenn MyClass MyInterface verwendet, aber keine eigene Implementierung von defaultMethod bereitstellt, erbt es nur die von MyInterface bereitgestellte Standardimplementierung. Die folgende Klasse wird beispielsweise weiterhin kompiliert:

Eine implementierende Klasse kann die von der Schnittstelle bereitgestellte Standardimplementierung überschreiben, sodass Klassen weiterhin die vollständige Kontrolle über ihre Implementierungen haben.

Standardmethoden sind zwar eine willkommene Ergänzung für API-Designer, können jedoch gelegentlich zu Problemen für Entwickler führen, die versuchen, mehrere Schnittstellen in derselben Klasse zu verwenden.

Stellen Sie sich vor, Sie haben zusätzlich zu MyInterface Folgendes:

Sowohl MyInterface als auch SecondInterface enthalten eine Standardmethode mit genau derselben Signatur(defaultMethod). Stellen Sie sich nun vor, Sie versuchen, beide Schnittstellen in derselben Klasse zu verwenden:

Zu diesem Zeitpunkt haben Sie zwei widersprüchliche Implementierungen von defaultMethod, und der Compiler hat keine Ahnung, welche Methode er verwenden soll. Daher tritt ein Compilerfehler auf.

Eine Möglichkeit, dieses Problem zu beheben, besteht darin, die widersprüchliche Methode mit Ihrer eigenen Implementierung zu überschreiben:

Die andere Lösung besteht darin, anzugeben, welche Version von defaultMethod Sie im folgenden Format implementieren möchten:

Wenn Sie also die Implementierung von MyInterface#defaultMethod() aufrufen möchten, verwenden Sie Folgendes:

Verwenden statischer Methoden in Ihren Java 8-Schnittstellen

Ähnlich wie bei Standardmethoden können Sie mit statischen Schnittstellenmethoden Methoden innerhalb einer Schnittstelle definieren. Im Gegensatz zu Standardmethoden kann eine implementierende Klasse die statischen Methoden einer Schnittstelle jedoch nicht überschreiben.

Wenn Sie über statische Methoden verfügen, die für eine Schnittstelle spezifisch sind, können Sie diese Methoden mit den statischen Schnittstellenmethoden von Java 8 in die entsprechende Schnittstelle einfügen, anstatt sie in einer separaten Klasse speichern zu müssen.

Sie erstellen eine statische Methode, indem Sie das Schlüsselwort static am Anfang der Methodensignatur platzieren. Beispiel:

Wenn Sie eine Schnittstelle implementieren, die eine statische Schnittstellenmethode enthält, ist diese statische Methode immer noch Teil der Schnittstelle und wird von der Klasse, die sie implementiert, nicht geerbt. Daher müssen Sie der Methode den Schnittstellennamen voranstellen, z. B.:

Dies bedeutet auch, dass eine Klasse und eine Schnittstelle eine statische Methode mit derselben Signatur haben können. Die Verwendung von MyClass.staticMethod und MyInterface.staticMethod in derselben Klasse führt beispielsweise nicht zu einem Fehler bei der Kompilierung.

Sind Schnittstellen im Wesentlichen nur abstrakte Klassen?

Das Hinzufügen statischer Schnittstellenmethoden und Standardmethoden hat einige Entwickler dazu veranlasst, sich zu fragen, ob Java-Schnittstellen mehr zu abstrakten Klassen werden. Selbst wenn Standard- und statische Schnittstellenmethoden hinzugefügt werden, gibt es dennoch einige bemerkenswerte Unterschiede zwischen Schnittstellen und abstrakten Klassen:

  • Abstrakte Klassen können endgültige, nicht endgültige, statische und nicht statische Variablen haben, während eine Schnittstelle nur statische und endgültige Variablen haben kann.
  • Mit abstrakten Klassen können Sie Felder deklarieren, die nicht statisch und endgültig sind, während die Felder einer Schnittstelle von Natur aus statisch und endgültig sind.
  • In Schnittstellen sind alle Methoden, die Sie als Standardmethoden deklarieren oder definieren, von Natur aus öffentlich, während Sie in abstrakten Klassen öffentliche, geschützte und private konkrete Methoden definieren können.
  • Abstrakte Klassen sind Klassen und können daher einen Zustand haben. Schnittstellen können keinen Status zugeordnet haben.
  • Sie können Konstruktoren innerhalb einer abstrakten Klasse definieren, was in Java-Schnittstellen nicht möglich ist.
  • Mit Java können Sie nur eine Klasse erweitern (unabhängig davon, ob sie abstrakt ist). Sie können jedoch beliebig viele Schnittstellen implementieren. Dies bedeutet, dass Schnittstellen normalerweise den Vorteil haben, wenn Sie eine Mehrfachvererbung benötigen, obwohl Sie sich vor dem tödlichen Diamanten des Todes hüten müssen!

Wenden Sie dieselbe Anmerkung so oft an, wie Sie möchten

Traditionell bestand eine der Einschränkungen von Java-Annotationen darin, dass Sie dieselbe Annotation nicht mehr als einmal am selben Speicherort anwenden können. Versuchen Sie, dieselbe Anmerkung mehrmals zu verwenden, und es tritt ein Fehler beim Kompilieren auf.

Mit der Einführung der sich wiederholenden Anmerkungen von Java 8 können Sie jetzt dieselbe Anmerkung so oft verwenden, wie Sie möchten, und zwar am selben Ort.

Um sicherzustellen, dass Ihr Code mit früheren Java-Versionen kompatibel bleibt, müssen Sie Ihre sich wiederholenden Anmerkungen in einer Containeranmerkung speichern.

Sie können den Compiler anweisen, diesen Container zu generieren, indem Sie die folgenden Schritte ausführen:

  • Markieren Sie die betreffende Anmerkung mit der @Repeatable Meta-Anmerkung (eine Anmerkung, die zum Kommentieren einer Anmerkung verwendet wird). Wenn Sie beispielsweise die @ToDo-Annotation wiederholbar machen möchten, verwenden Sie: @Repeatable(ToDos.class). Der Wert in Klammern ist die Art der Containeranmerkung, die der Compiler eventuell generiert.
  • Deklarieren Sie den enthaltenen Annotationstyp. Dies muss ein Attribut haben, das ein Array des sich wiederholenden Anmerkungstyps ist, zum Beispiel:

Der Versuch, dieselbe Anmerkung mehrmals anzuwenden, ohne zuvor zu erklären, dass sie wiederholbar ist, führt beim Kompilieren zu einem Fehler. Sobald Sie jedoch angegeben haben, dass dies eine wiederholbare Anmerkung ist, können Sie diese Anmerkung an jedem Ort, an dem Sie eine Standardanmerkung verwenden möchten, mehrmals verwenden.

Abschluss

In diesem zweiten Teil unserer Serie zu Java 8 haben wir gesehen, wie Sie durch die Kombination von Lambda-Ausdrücken mit Methodenreferenzen noch mehr Code aus Ihren Android-Projekten herausschneiden und Ihre Schnittstellen mit Standard- und statischen Methoden verbessern können.

In der dritten und letzten Ausgabe sehen wir uns eine neue Java 8-API an, mit der Sie große Datenmengen effizienter und deklarativer verarbeiten können, ohne sich um Parallelität und Thread-Verwaltung kümmern zu müssen. Wir werden auch einige der verschiedenen Funktionen zusammenfassen, die wir in dieser Reihe besprochen haben, indem wir die Rolle untersuchen, die funktionale Schnittstellen in Lambda-Ausdrücken, statischen Schnittstellenmethoden, Standardmethoden und mehr spielen müssen.

Und schließlich, obwohl wir immer noch darauf warten, dass die neue Datums- und Uhrzeit-API von Java 8 offiziell auf Android verfügbar ist, werde ich zeigen, wie Sie diese neue API heute mithilfe von Drittanbietern in Ihren Android-Projekten verwenden können Bibliotheken.

In der Zwischenzeit lesen Sie einige unserer anderen Beiträge zur Entwicklung von Java- und Android-Apps!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.