Ich entwickle eine Open-Source-Bibliothek in Java und möchte sicherstellen, dass sie für Java-8-Benutzer geeignet ist, und nutzt wo immer möglich neue Konzepte in Java 8 (Lambdas usw.)
Gleichzeitig muss ich unbedingt die Abwärtskompatibilität beibehalten (die Bibliothek muss immer noch für Leute nutzbar sein, die Java 6 oder 7 benutzen).
Welche nützlichen Funktionen von Java 8 kann ich verwenden, die für Bibliotheksbenutzer von Vorteil wären, ohne die Bibliothekskompatibilität für Benutzer älterer Java-Versionen zu unterbrechen?
Ich weiß nichts über Ihre Bibliothek, dieser Hinweis könnte etwas abweichen .
Lambdas : Mach dir keine Sorgen. Jede funktionale Schnittstelle kann mit einem Lambda-Ausdruck implementiert werden.
Methodenreferenzen : Wie lambdas, sollten sie nur verwendbar sein.
Streams : Wenn dies zu Ihrer Bibliothek passt, sollten Sie sie verwenden, aber die Kompatibilität ist hier schwieriger. Die Abwärtskompatibilität könnte durch Verwendung eines zweiten Bibliotheksteils, Umwickeln der Basisbibliothek und Einhängen in die öffentliche API davon erreicht werden. Es könnte daher zusätzliche Zucker / Funktionalität bereitstellen, ohne Java 6/7 aufzugeben.
Standardmethoden : Verwenden Sie diese auf jeden Fall! Sie sind eine schnelle / billige / gute Möglichkeit, bestehende Implementierungen zu verbessern, ohne sie zu brechen. Alle von Ihnen hinzugefügten Standardmethoden stehen automatisch für die Implementierung von Klassen zur Verfügung. Diese benötigen jedoch auch den zweiten Bibliotheksteil, daher sollten Sie die Basisschnittstellen in Ihrer Basisbibliothek bereitstellen und die Schnittstellen von der Begleitbibliothek erweitern.
Nicht verzweigen die Bibliothek, die alte nicht verlassen, da es noch viele Entwickler gibt, die nicht Java 8 oder sogar Java 7 verwenden können. Wenn Ihre Bibliothek sinnvoll ist, z. Android, bitte behalte diese Kompatibilität.
Wenn Sie möchten, dass Ihr Code von Java 6-VMs verwendet werden kann, müssen Sie mit Java 6-Sprachkompatibilität schreiben. Ach. Das Bytecode-Format hat sich kritisch von 6 auf 7 geändert, also wird der Code für 7 und 8 nicht in 6 geladen. (Ich fand das mit meinem eigenen Code auf 7 migriert; auch wenn ich nur multi- catch
benutzte - was sollte im 6 Bytecode beschreibbar sein - ich konnte es nicht für ein 6 Ziel erstellen. Der Compiler wurde abgelehnt.
Ich habe noch mit 8 experimentiert, aber Sie müssen vorsichtig sein, denn wenn Sie von neuen Java-Paketen oder -Klassen abhängig sind, können Sie immer noch nicht mit älteren Versionen arbeiten . Die alten verbrauchenden VMs haben einfach keinen Zugriff auf die relevanten Klassen und können den Code nicht laden. Insbesondere Lambdas wird definitiv nicht funktionieren .
Nun, können wir eine andere Classfile-Version verwenden? Es gibt keine Kombination aus Quelle und Ziel, die Javac glücklich macht.
%Vor%Es gibt also einfach keine Möglichkeit, Java-Quelldateien mit Lambdas in eine Pre-Java-8-Klassendateiversion zu kompilieren.
Wenn Sie ältere Java-Versionen unterstützen wollen, müssen Sie dazu alte Java-Versionen verwenden. Sie können eine Java 8-Toolchain verwenden, benötigen aber Java 7 oder Java 6 Source. Sie können dies tun, indem Sie den Code fälschen und Versionen für alle Java-Versionen beibehalten, die Sie unterstützen möchten, aber das ist viel mehr Arbeit, als Sie jemals als einzelner Entwickler rechtfertigen könnten. Wählen Sie die minimale Version und gehen Sie damit (und küssen Sie diese saftigen neuen Funktionen auf Wiedersehen für jetzt, leider).
Wenn Sie in Java 8 neue Sprachfunktionen verwenden, müssen Sie auch Java 8-Bytecode verwenden.
%Vor%Das bedeutet, dass Ihre Möglichkeiten ziemlich begrenzt sind. Sie können keine Lambdas, Methodenreferenzen, Standardmethoden, Streams usw. verwenden und Rückwärtskompatibilität beibehalten.
Es gibt noch zwei Dinge, die Sie tun können, von denen Benutzer von Java 8 profitieren werden. Der erste verwendet funktionale Schnittstellen in Ihrer öffentlichen API. Wenn Ihre Methoden Runnables, Callables, Comparators usw. als Parameter verwenden, können Benutzer von Java 8 Lambdas übergeben. Vielleicht möchten Sie auch Ihre eigenen Single-Abstract-Methode-Schnittstellen erstellen. Wenn du feststellst, dass du Funktionen und Prädikate benötigst, würde ich empfehlen, diejenigen, die mit GS-Sammlungen oder Guava ausgeliefert werden, nicht zu schreiben dein eigenes.
Das zweite, was Sie tun können, ist ein reiches Auflistungs-API, das von der Verwendung von funktionalen Schnittstellen profitiert. Dies bedeutet wiederum, GS Collections oder Guava zu verwenden. Wenn Sie beispielsweise über eine Methode verfügen, die List zurückgibt, geben Sie MutableList oder ImmutableList stattdessen. Auf diese Weise können Anrufer der Methode die Nutzungen der reichhaltigen API ketten, die durch diese Schnittstellen offengelegt werden.
Wie bereits von anderen erwähnt, bietet die Bereitstellung und Verwendung von Interfaces mit einer einzigen Methode, die mithilfe von lambdas oder Methodenverweisen implementiert werden kann, Java 8 ohne Java 7-Kompatibilität zu beeinträchtigen.
Dies kann durch die Bereitstellung von Methoden durch Ihre Bibliothek ergänzt werden, die in einen der Standardfunktionstypen von Java 8 passen (zB Supplier
, (Bi)Consumer
, (Bi)Function
), so dass Java 8 Entwickler können Methodenreferenzen für Java-8-API-Methoden erstellen. Dies bedeutet, dass ihre Signatur mit einer dieser funktionalen Schnittstellen übereinstimmt und keine geprüften Ausnahmen auslöst. Dies kommt oft natürlich vor, z.B. getFoo()
kann als Function
und isBar()
als Predicate
fungieren, aber manchmal ist es auch möglich, Methoden zu verbessern, indem Sie über mögliche Java 8-Szenarien nachdenken.
Wenn Sie beispielsweise eine Methode angeben, die zwei Parameter verwendet, ist es sinnvoll, die Reihenfolge zu wählen, in der der erste Parameter derjenige ist, bei dem es sich eher um einen Schlüssel in Map
handelt. Daher ist es wahrscheinlich hilfreicher für Map.forEach
mit einer Methodenreferenz.
Und vermeiden Sie die Methode mit mehrdeutigen Signaturen. Z.B. Wenn Sie eine Klasse Foo
mit einer Instanzmethode ReturnType bar()
und einer static
Methode ReturnType bar(Foo)
haben, können beide Methoden nicht mehr als Methodenreferenz verwendet werden, da Foo::bar
mehrdeutig wäre. Beseitigen oder benennen Sie eine dieser Methoden um.
Es ist wichtig, dass solche Methoden keinen undokumentierten internen Status haben, der bei Verwendung mehrerer Threads zu einem überraschenden Verhalten führt. Andernfalls können sie nicht von parallelen Streams verwendet werden.
Eine weitere nicht zu unterschätzende Möglichkeit ist die Verwendung von Namen für Klassen, Schnittstellen und Member, die den Mustern entsprechen, die von der Java 8-API eingeführt wurden. Z.B. Wenn Sie eine Filterschnittstelle mit einer Testmethode für Ihre Bibliothek einführen müssen, die auch mit Java 7 arbeiten soll, sollten Sie die Schnittstelle Predicate
und die Methode test
benennen, um sie der ähnlich benannten funktionalen Schnittstelle zuzuordnen von Java 8.
Tags und Links java java-8 backwards-compatibility