9
votes

Comment puis-je implémenter une interface Java 8 mais courir sur Java 6?

J'ai une bibliothèque, Fakir voir comme vous le demandez, que je voudrais rester compatible avec Java 6. au même Il serait vraiment agréable que son abstraction clé, le Faker , devait être capable de mettre en œuvre java.util.function.supplier .

J'ai fait des choses moulées en mettant les choses en implémentant ma propre copie du fournisseur, de sorte qu'au moins Lambdas puisse être utilisée, mais à l'expédition de deux fichiers JAR différents (AH Scala, comment vous manquez vos multiples versions pour différentes spécifications de langues) Toute façon d'avoir mes principales abstraction d'abstraction compatibles?


4 commentaires

Vous avez besoin de quelque chose de similaire comme retrolambda.


Comme je l'ai lu, mes clients sur Java 6 auraient besoin de retrolambda, pas de moi?


Même si vous n'êtes pas implémenter fournisseur , il est suffisamment facile d'utiliser une instance de votre classe en tant que fournisseur à l'aide de références de méthode, par exemple. fournisseur sup = faker :: get; .


C'est un bon point fabian. Le problème est que je veux accepter un fournisseur au même endroit, bien que je suppose que le même tour fonctionnera en sens inverse


4 Réponses :


4
votes

Je ne pense pas que ce soit possible. À un moment donné, vous devez faire un saut et votre bibliothèque ne fonctionne plus avec Pre-8 Java. Vous pouvez le faire maintenant avec Pro et Inconvénients; inconvénient qu'il n'y a pas beaucoup de programmateur familiarisé avec Java8 à ce moment-là.

Il existe de nouvelles fonctionnalités de Java8, telles que LAMBDA, la méthode par défaut, la méthode d'interface statique, le nouveau système d'inférence de type, les nouveaux utilitaires tels que le flux, qui aura un impact important sur la conception des API; ils ne sont pas disponibles pour Java plus âgés; et rester compatible avec l'aîné Java est un menotte aux designers de l'API.

Le pro avec sauter sur Java8 Wagon est maintenant que votre API serait plus moderne, sans les bagages de Java plus âgés. Cela va payer dans l'avenir (à la fois très loin).


8 commentaires

Peut-être que de plus près, les changements de la future version Java 9 peuvent également aider à décider quand "couper" les anciennes versions Java. Personnellement, j'attendrais Java 9 car il y aura des changements plus importants en raison du concept de module.


@ Mschenk74 - Bien Java8 a beaucoup à digérer, il vaut mieux commencer tôt. Je ne pense pas que Java9 aura trop d'impact sur la conception de l'API.


Étant donné que Java9 brisera probablement beaucoup de code ancien qui utilise des API internes qui ne seront plus accessibles, il y aura des changements que je parie. Cela dépend du type de bibliothèque offrant: s'il s'agit d'une bibliothèque à long terme stable et complète qu'il n'a probablement aucun sens d'attendre qu'il n'y ait pas d'autre moyen, mais s'il s'agit d'une bibliothèque dynamique qui doit réagir sur les idées actuelles et Des problèmes qu'il vaut mieux passer à Java 8 dès que possible.


En fait, l'API est tout à fait bien avec Java 6, c'est juste que j'aimerais être en avant compatible via des interfaces réelles si possible.


@DuncanmcGregor - C'est bien de définir votre propre interface fonctionnelle. Mais il est mauvais d'utiliser le même nom que JDK (futur ou courant). C'est agaçant envers l'utilisateur, car il est très facile d'importer le mauvais, puis il est perplexe pourquoi il ne compile pas.


@ bayou.io: je suis en désaccord. Si l'interface est un miroir d'un autre, l'utilisation du même nom est bien. Surtout que vous n'avez pas besoin d'importer l'interface dans Java 8 lors de la mise en œuvre via une expression Lambda ou une référence de méthode.


@Holger - Oui, en Java8, nous n'avons pas besoin de mentionner autant le nom de l'interface. Néanmoins, parfois, nous faisons dans le code de l'utilisateur, par ex. Nous pourrions avoir besoin de fournisseur variable local, variable d'instance ou paramètre de méthode. Importer accidentellement le mauvais est gênant au moins.


@Holger - Si le nom de l'interface fonctionnelle n'a pas d'importance pour votre code utilisateur, c'est plus la raison de proposer un nom différent.



0
votes

échoue de ma part - cela ne fonctionne pas pour "Java". Forfaits

Une astuce sale serait de fournir à l'interface fournisseur, telle que définie dans Java 8, vous devez donc expédier un "java.util.function.supplier".

Si le client n'est pas pré-java 8, cela peut donc satisfaire aux dépendances de votre implémentation.

Lorsque le client est sur Java 8, les pots JRE priment sur la classe de classe et la mise en œuvre «réelle» sera utilisée.

Si c'était plus qu'une interface que vous avez une interface, je serais tenté de faire en sorte que la classe d'espace réservé ait une erreur si elle a été utilisée.

Vous auriez besoin de tester pour sceller des colis sur Pre-Java 8 JRES. Je ne pense pas que c'est le cas.

J'ai vu cette approche se produire par un accident dans certains grands projets, où des pots ont été ajoutés contenant 'Java. ' ou 'Javax. ' packages avant d'être incorporés dans le JRE (par exemple, Jars JSR). Ceux-ci ont couru longtemps après que la fonctionnalité faisait partie de la JRE.

mise à jour:

Comme indiqué ci-dessous, le chargeur de classe baulks sur des packages de «Java» non Jre », je dois donc me demander mal les débris hérités (sauf si la règle n'était pas associée avant 1,3 / 1,4?).

Peut-être un travail en désordre avec 'java.lang.reflect.proxy' pourrait atteindre des résultats - mais à peine une solution transparente.


1 commentaires

Les chargeuses de classe d'application ne sont pas autorisées à définir des classes dont le nom commence par Java. . Semble que vous le confondez avec le Javax. Prefix. Ces deux préfixes différents existent pour exactement cette raison.



0
votes

Je ne vois aucune autre façon que de navire 2 versions de la bibliothèque.

Je vois que vous utilisez Maven. Vous pouvez jouer avec la gestion de la dépendance et avoir 3 projets comme ceci:

  • fakir-commun : (en Java 6)
  • fakir-java8 : (en Java 8, dépend de Fakir-Common)
  • fakir-java6 : (en Java 6, dépend de Fakir-Common)

    Procinez le maximum de votre code qui ne nécessitent pas d'utiliser l'interface fournisseur dans la partie fakir-commune .

    puis implémentez les aspects spécifiques du fournisseur dans les deux autres parties.

    Vous pouvez utiliser Projet StreamSupport comme une dépendance pour fakir-java6 :

    streamsupport est une backport du Java 8 Java.Util.function (fonctionnel interfaces) et java.util.stream (flux) API pour les utilisateurs de Java 6 ou 7

    Grâce à cela, les deux projets Fakir-Javan auront presque le même code. Il peut être même possible d'utiliser la génération de code pour l'écrire une seule fois.


3 commentaires

Expédition Deux versions différentes de la bibliothèque sont exactement ce que le questionneur veut éviter.


En fait, StreamSupport ne semble pas nécessiter d'expédier deux versions différentes. Il évite de nuire.


@Holger, tu as raison. Cependant, je voulais fournir une alternative à la réponse «Ce n'est pas possible» avec lequel je suis d'accord.



1
votes

comme java.util.function inclut uniquement des interfaces fonctionnelles que vous pouvez utiliser un "BackPort" de celui-ci. Le Backport ne pourrait bien sûr pas fournir les fonctions par défaut, définissez uniquement les interfaces, mais les interfaces sont tout ce dont vous avez besoin pour ajouter une compatibilité avec Java 8.

streamsupport est un backport qui ajoute un peu plus que les interfaces, mais cela évite les affrontements de nom et ne pas nécessiter de vous obliger Pour faire deux versions distinctes.

Pour utiliser cette méthode, si vous utilisez StreamSupport, écrivez simplement xxx

au lieu de xxx

Edit: mmm-util-backport-java.util.function nécessite l'utilisation de -xclassbootpath tel qu'il définit java.util.function de la même chose avec un nom différent, donc streamsupport est la meilleure option.


0 commentaires