9
votes

Équivalent de #define en Java?

J'écris une bibliothèque qui doit avoir un code si une bibliothèque particulière est incluse. Étant donné que ce code est dispersé tout autour du projet, ce serait bien si les utilisateurs n'avaient pas besoin de commenter / déformer tout.

en C, ce serait assez facile avec un #define dans une en-tête, puis des blocs de code entourés de #Ifdefs . Bien sûr, Java n'a pas le préprocesseur C ...

Pour clarifier - plusieurs bibliothèques externes seront distribuées avec la mine. Je ne veux pas avoir à les inclure tous pour minimiser ma taille exécutable. Si un développeur comprend une bibliothèque, j'ai besoin de pouvoir l'utiliser, et sinon, il peut simplement être ignoré.

Quelle est la meilleure façon de le faire en Java?


1 commentaires

13 Réponses :


2
votes

Utilisez un constante :

Cette semaine, nous créons des constantes qui ont tous les avantages de l'utilisation Les installations du préprocesseur C à Définir des constantes de compilation et Code compilé conditionnellement.

Java s'est débarrassé de l'ensemble de la notion d'un prétraiteur textuel (si Vous prenez Java comme un "descendant" de C / C ++). Nous pouvons cependant obtenir le meilleur avantages d'au moins une partie du c Caractéristiques du préprocesseur en Java: Constantes et compilation conditionnelle.


7 commentaires

Je ne pense pas que c'est ce qu'il cherche. Il ne veut pas que des constantes symboliques, mais un équivalent à la compilation conditionnelle. Ne sachant pas Java, je n'ai pas d'indication, cependant ...


Qu'en est-il de la compilation conditionnelle? Comment faites-vous cela en Java?


L'article que j'ai lié en discute.


En tant que note rapide sur l'article lié, l'ensemble "Faites une interface pour vos constantes et de la mise en œuvre" est obsolète et ridicule maintenant qu'il y a importation statique .


La compilée conditionnelle ne fonctionne toujours que si tout ce qui compile. Si, lorsque la branche de l'époque est vraie, la branche d'autre ne compile pas, car ces méthodes n'existent pas, ni quelque chose, il ne compilera pas. #si résout cela bien.


Ce que Brian a dit exactement le problème.


Oui, vous ne voulez vraiment pas de code non compilateur dans votre système. Utilisez la version de version pour cibler une version ou utiliser des talons de méthode. Le pire des cas si vous devez vraiment avoir du code qui relie une bibliothèque qui n'est pas disponible au moment de la compilation, vous pouvez utiliser la réflexion.



0
votes

Utilisez les propriétés pour faire ce genre de chose.

utiliser des choses comme classe.forname pour identifier la classe.

Ne pas utiliser si-énoncés lorsque vous pouvez traduire trivialement une propriété directement sur une classe.


0 commentaires

11
votes

Il n'y a aucun moyen de faire ce que vous voulez de Java. Vous pouvez prétraiter les fichiers source Java, mais c'est en dehors de la portée de Java.

Pouvez-vous ne pas résumer les différences, puis modifier la mise en œuvre?

En fonction de votre clarification, on dirait que vous pourrez peut-être créer une méthode d'usine qui retournera un objet de l'une des bibliothèques externes ou d'une classe "stub" dont les fonctions feront ce que vous auriez fait dans le " non disponible "Code conditionnel.


6 commentaires

+1: Ce problème semble pouvoir être (pourrait être) possible de modifier la conception de la solution d'architecture pour aider à cela.


Le compilateur Java optimisera les contrôles conditionnels basés sur des valeurs constantes. Ainsi, c'est certainement possible.


@Anon: Mais cela compile toujours les deux branches. Il optimise simplement le code inutilisé, non? En outre, beaucoup de temps, ré-structurant votre architecture pour éliminer ces problèmes peut être vraiment désordonné. Si vous avez un tas d'endroits aléatoires que vous voulez #Ifdefed ... vous vous retrouvez avec une classe de base, puis un tas de sous-classes, avec des fonctions d'assistance, et cela devient juste un gâchis.


Vous avez une classe, pas de fonctions d'assistance et un groupe de constantes symboliques. Je ne vois pas le besoin de sous-classement.


Nous avons besoin de plus de détails pour dire si une solution de conception existe.


@Anon, désolé, je vous confondçais avec le répondeur d'origine (Steve) et Russell, l'optimisation ne résout pas le problème "non compilant". Le sous-classement et les aides sont une réponse aux solutions architecturales / abstraction.



1
votes

Je ne crois pas qu'il y ait vraiment une telle chose. La plupart des vrais utilisateurs de Java vous diront que c'est une bonne chose, qui s'appuie sur la compilation conditionnelle devront être évitée à presque tous les coûts.

Je ne suis pas vraiment d'accord avec eux ...

Vous pouvez utiliser des constantes pouvant être définies de la ligne de compilation, ce qui aura une partie de l'effet, mais pas vraiment. (Par exemple, vous ne pouvez pas avoir de choses qui ne compilent pas, mais vous voulez toujours, à l'intérieur de #idif 0 ... (et non, les commentaires ne résolvent pas toujours ce problème, car la nidification commente peut être délicate ... )))).

Je pense que la plupart des gens vous diront d'utiliser une forme d'héritage pour le faire, mais cela peut aussi être très laid, avec beaucoup de code répété ...

Cela dit, vous pouvez toujours configurer votre IDE pour lancer votre Java à travers le pré-processeur avant de l'envoyer à Javac ...


0 commentaires

5
votes

En Java, on pourrait utiliser une variété d'approches pour obtenir le même résultat:


1 commentaires

+1 pour l'injection de dépendance. Imaginez de câbler vos objets via un fichier XML (à titre d'exemple), puis à l'aide d'un fichier XML différent pour vos différentes situations.



1
votes

"Pour minimiser ma taille exécutable"

Que voulez-vous dire par "taille exécutable"?

Si vous voulez dire la quantité de code chargée au moment de l'exécution, vous pouvez ensuite charger des classes de classe via le chargeur de classe. Donc, vous distribuez votre code alternatif, peu importe ce qu'il y a, mais il est uniquement chargé si la bibliothèque utilisée est manquante. Vous pouvez utiliser un adaptateur (ou similaire) pour encapsuler l'API, afin de vous assurer que presque tout votre code est exactement de la même manière, et l'une des deux classes d'emballage est chargée en fonction de votre cas. Le SPI de Security Java pourrait vous donner quelques idées comment cela peut être structuré et mis en œuvre.

Si vous voulez dire la taille de votre fichier .jar, vous pouvez faire ce qui précède, mais dites à vos développeurs comment éliminer les classes inutiles du pot, dans le cas où ils savent qu'ils ne seront pas nécessaires .


3 commentaires

La bibliothèque sera utilisée dans des applications Android. Je ne veux donc pas inclure quoi que ce soit inutile.


Cela ne répond pas aux paramètres de votre question initiale. Si vous reliez au moment de l'exécution, vous devez toujours avoir le code qui appelle la bibliothèque compilée dans SO #Ifdef ne vous aiderait pas de toute façon. Si vous ne reliez pas à l'heure d'exécution, mais la compilation de différentes cibles, alors si (constante) suffira. Lequel est le problème réel?


Non, la constante ne suffira pas. Par exemple, si (faux) {lobliacthave.action.action ();} ne compilera pas.



4
votes

Eh bien, la syntaxe Java est suffisamment proche pour laquelle vous pouvez simplement utiliser le prétraiteur C, qui est généralement expédié comme exécutable distinct.

Mais Java ne consiste pas vraiment à faire des choses à l'heure de la compilation de toute façon. La façon dont j'ai géré des situations similaires auparavant est avec une réflexion. Dans votre cas, étant donné que vos appels vers la bibliothèque éventuellement non présente sont dispersés dans tout le code, je ferais une classe wrapper, remplacez tous les appels à la bibliothèque avec des appels à la classe wrapper, puis utilisez la réflexion à l'intérieur de la classe wrapper. invoquer sur la bibliothèque s'il est présent.


0 commentaires

6
votes

Comme d'autres ont dit, il n'y a pas de # définir / # ifdef en Java. Mais en ce qui concerne votre problème d'avoir des bibliothèques externes facultatives, que vous utiliseriez, s'il est présent et que vous n'utilisez pas le cas échéant, l'utilisation de classes de proxy peut être une option (si les interfaces de la bibliothèque ne sont pas trop grandes).

Je devais faire Ceci une fois pour les extensions spécifiques de Mac OS X pour AWT / Swing (trouvée dans com.apple.ewt. *). Bien entendu, les classes ne sont bien sûr que sur la parcelle de classe si l'application est en cours d'exécution sur Mac OS. Pour pouvoir les utiliser mais permettent toujours à la même application d'être utilisée sur d'autres plates-formes, j'ai écrit des classes de proxy simples, qui viennent offrir les mêmes méthodes que les classes EAWT d'origine. En interne, les procurations utilisaient une certaine réflexion pour déterminer si les véritables classes étaient sur le chemin de classe et passeraient à travers tous les appels de méthode. En utilisant le java.lang.reflect.proxy classe, vous pouvez même créer et transmettre des objets d'un type défini dans la bibliothèque externe, sans qu'il soit disponible au moment de la compilation.

Par exemple, le proxy pour com.apple.ewt. ApplicationListener ressemblait à ceci: xxx

Tout cela n'a aucun sens, si vous n'avez besoin que de quelques classes d'une bibliothèque externe, car vous devez tout faire via une réflexion au moment de l'exécution. Pour les plus grandes bibliothèques, vous auriez probablement besoin d'un moyen d'automatiser la génération des proxies. Mais alors, si vous êtes vraiment aussi dépendant d'une grande bibliothèque externe, vous devriez juste l'exiger à la compilation.

Commentaire de Peter Lawrey: (Désolé de modifier, il est très difficile de mettre le code dans un commentaire )

L'exemple suivant est générique par méthode afin de ne pas avoir besoin de connaître toutes les méthodes impliquées. Vous pouvez également rendre cette classe générique par classe, de sorte que vous n'avez besoin que d'une classe d'invocalisation de la part de la classe pour couvrir tous les cas. xxx


1 commentaires

Il y a en effet une telle chose en Java via le Manifold Projejct. Il fournit un préprocesseur entièrement fonctionnel en termes de compilation conditionnelle I.E., #define , #if , #else , etc.



0
votes

Selon ce que vous faites (pas assez d'informations), vous pouvez faire quelque chose comme ceci: xxx pré>

puis fournir une classe à résumé l'instanciation: p>

class FooFactory
{
    public static Foo makeFoo()
    {
        final String   name;
        final FooClass fooClass;
        final Foo      foo;

        name     = System.getProperty("foo.class");
        fooClass = Class.forName(name);
        foo      = (Foo)fooClass.newInstance();

        return (foo);
    }
}


0 commentaires

0
votes

Je vois vous spécifier deux problèmes mutuellement exclusifs ici (ou plus probablement, vous avez choisi un et je ne comprends tout simplement pas quel choix que vous avez fait).

Vous devez faire un choix: Expédiez-vous Deux versions de votre code source (une si la bibliothèque existent, et une si elle ne le fait pas) ou expédiez-vous une seule version et attendez-vous qu'il fonctionne avec la bibliothèque si la bibliothèque existe. P>

Si vous Vous voulez une seule version pour détecter l'existence de la bibliothèque et l'utiliser si disponible, vous devez disposer de tout le code pour y accéder dans votre code distribué - vous ne pouvez pas le réduire. Puisque vous assimilez votre problème avec un #define, j'ai supposé que ce n'était pas votre objectif - vous souhaitez expédier 2 versions (le seul moyen #define peut fonctionner) p>

Donc, avec 2 versions que vous pouvez Définir une bibliothèque d'interface. Ceci peut être un objet qui envoie votre bibliothèque et transfère tous les appels à la bibliothèque pour vous ou une interface - dans les deux cas, cet objet doit exister à la date de compilation pour les deux modes. P>

if(LIBRARY_EXISTS)
    library.doFunc()


0 commentaires

0
votes

Si cela aide à jeter un coup d'œil à J2ME Polonais ou Directives de préprocesseur dans le plugin JDE BlackBerry pour Eclipse?

Ceci est pour l'application mobiles, mais cela peut être réutilisé non?


0 commentaires

1
votes

J'ai un meilleur moyen de dire.

Ce dont vous avez besoin est une variable finale. p> xxx pré>

puis à l'intérieur du code dire comme p>

if(LibraryIncluded){
    //do what you want to do if library is included
}
else
{
    //do if you want anything to do if the library is not included
}


0 commentaires

1
votes

Si vous recherchez un préprocesseur Java entièrement intégré, Chansifold a votre dos. Il se branche directement dans le compilateur - aucune étape de construction, aucune génération de code intermédiaire, c'est-à-dire que c'est rapide et sans tracas.

 préprocesseur Java de Manifold


0 commentaires