web-dev-qa-db-fra.com

#ifdef #ifndef dans Java

Je doute qu'il existe un moyen de créer des conditions de compilation dans Java comme #ifdef #ifndef en C++.

Mon problème est que j'ai un algorithme écrit en Java et que le temps d'exécution est amélioré par rapport à cet algorithme. Je veux donc mesurer combien de temps j'ai économisé lorsque chaque amélioration est utilisée.

À l'heure actuelle, j'ai un ensemble de variables booléennes qui sont utilisées pour décider pendant le temps d'exécution quelles améliorations doivent être utilisées et celles qui ne le sont pas. Mais même tester ces variables influence le temps total d'exécution.

Je souhaite donc trouver un moyen de décider pendant la compilation quelles parties du programme doivent être compilées et utilisées.

Est-ce que quelqu'un connaît un moyen de le faire en Java. Ou peut-être que quelqu'un sait qu'il n'y en a pas (ce serait également utile).

102
jutky
private static final boolean enableFast = false;

// ...
if (enableFast) {
  // This is removed at compile time
}

Les conditions comme celles présentées ci-dessus sont évaluées au moment de la compilation. Si vous utilisez plutôt cette

private static final boolean enableFast = "true".equals(System.getProperty("fast"));

Ensuite, toutes les conditions dépendant de enableFast seront évaluées par le compilateur JIT. Les frais généraux pour cela est négligeable.

120
Mark Thornton

javac ne générera pas de code compilé inaccessible. Utilisez une variable finale définie sur une valeur constante pour votre #define et une instruction normale if pour le #ifdef.

Vous pouvez utiliser javap pour prouver que le code inaccessible n'est pas inclus dans le fichier de classe en sortie. Par exemple, considérons le code suivant:

public class Test
{
   private static final boolean debug = false;

   public static void main(String[] args)
   {
       if (debug) 
       {
           System.out.println("debug was enabled");
       }
       else
       {
           System.out.println("debug was not enabled");
       }
   }
}

javap -c Test donne le résultat suivant, indiquant que seul l'un des deux chemins a été compilé (et que l'instruction if ne l'était pas):

public static void main(Java.lang.String[]);
  Code:
   0:   getstatic       #2; //Field Java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #3; //String debug was not enabled
   5:   invokevirtual   #4; //Method Java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return
43
Phil Ross

Je pense avoir trouvé la solution, c'est beaucoup plus simple.
Si je définis les variables booléennes avec le modificateur "final" Java lui-même résout le problème. Parce qu'il sait à l'avance quel serait le résultat du test de cette condition. Par exemple, code:

    boolean flag1 = true;
    boolean flag2 = false;
    int j=0;
    for(int i=0;i<1000000000;i++){
        if(flag1)
            if(flag2)
                j++;
            else
                j++;
        else
            if(flag2)
                j++;
            else
                j++;
    }

fonctionne environ 3 secondes sur mon ordinateur.
Et celui-là

    final boolean flag1 = true;
    final boolean flag2 = false;
    int j=0;
    for(int i=0;i<1000000000;i++){
        if(flag1)
            if(flag2)
                j++;
            else
                j++;
        else
            if(flag2)
                j++;
            else
                j++;
    }

court environ 1 seconde. En même temps, ce code prend

    int j=0;
    for(int i=0;i<1000000000;i++){
        j++;
    }
11
jutky

Jamais utilisé, mais cela existe

JCPP est une implémentation complète, conforme, autonome, pure Java du préprocesseur C.). Elle est utile aux utilisateurs qui écrivent des compilateurs de style C dans Java = en utilisant des outils tels que sablecc, antlr, JLex, CUP, etc. Ce projet a été utilisé pour prétraiter avec succès une grande partie du code source de la bibliothèque GNU C. À partir de la version 1.2.5 , il peut également prétraiter la bibliothèque Apple Objective C).

http://www.anarres.org/projects/jcpp/

2
Tom

Si vous avez vraiment besoin d'une compilation conditionnelle et que vous utilisez Ant , vous pourrez peut-être filtrer votre code et y effectuer une recherche-remplacement.

Par exemple: http://weblogs.Java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

De la même manière, vous pouvez, par exemple, écrire un filtre pour remplacer LOG.debug(...); par /*LOG.debug(...);*/. Cela exécuterait quand même plus vite que if (LOG.isDebugEnabled()) { ... }, sans parler d'être plus concis en même temps.

Si vous utilisez Maven , une fonctionnalité similaire est décrite ici.

2
rustyx

Collecteur fournit un préprocesseur Java totalement intégré (pas d'étapes de construction ni de source générée). Il cible exclusivement la compilation conditionnelle et utilise des directives de style C.

Manifold's Java Preprocessor

1
Scott

Utilisez le modèle d'usine pour basculer entre les implémentations d'une classe?

Le moment de la création de l'objet ne peut pas être une préoccupation maintenant, n'est-ce pas? En moyenne, sur une longue période, la plus grande partie du temps passé devrait être dans l'algorithme principal, n'est-ce pas?

Strictement parlant, vous n'avez pas vraiment besoin d'un pré-processeur pour faire ce que vous cherchez. Il y a très probablement d'autres moyens de répondre à vos besoins que celui que j'ai proposé bien sûr.

1
jldupont
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
0
alicanbatur