#ifdef #ifndef в Java - PullRequest
       43

#ifdef #ifndef в Java

100 голосов
/ 29 ноября 2009

Я сомневаюсь, есть ли способ сделать условия времени компиляции в Java, такие как #ifdef #ifndef в C ++.

Моя проблема в том, что у меня есть алгоритм, написанный на Java, и у меня есть другое время выполнения, улучшающее этот алгоритм. Поэтому я хочу измерить, сколько времени я экономлю при использовании каждого улучшения.

Прямо сейчас у меня есть набор логических переменных, которые используются для определения во время работы, какие улучшения следует использовать, а какие нет. Но даже тестирование этих переменных влияет на общее время работы.

Итак, я хочу найти способ решить, во время компиляции, какие части программы следует компилировать и использовать.

Кто-нибудь знает способ сделать это на Java. Или, может быть, кто-то знает, что такого пути нет (это тоже было бы полезно).

Ответы [ 7 ]

120 голосов
/ 29 ноября 2009
private static final boolean enableFast = false;

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

Условия, подобные показанным выше, оцениваются во время компиляции. Если вместо этого вы используете это

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

Тогда все условия, зависящие от enableFast, будут оцениваться JIT-компилятором. Накладные расходы для этого незначительны.

43 голосов
/ 29 ноября 2009

javac не будет выводить скомпилированный код, который недоступен. Используйте конечную переменную, установленную на постоянное значение для #define, и обычный оператор if для #ifdef.

Вы можете использовать javap, чтобы доказать, что недоступный код не включен в выходной файл класса. Например, рассмотрим следующий код:

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 дает следующий вывод, указывая на то, что только один из двух путей был скомпилирован (а оператор if не был):

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
11 голосов
/ 29 ноября 2009

Я думаю, что нашел решение, оно намного проще.
Если я определю булевы переменные с помощью «финального» модификатора, то сам компилятор Java решит проблему. Потому что он заранее знает, что будет результатом проверки этого условия. Например этот код:

    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++;
    }

работает около 3 секунд на моем компьютере.
И этот

    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++;
    }

работает около 1 секунды. В то же время этот код занимает

    int j=0;
    for(int i=0;i<1000000000;i++){
        j++;
    }
2 голосов
/ 13 июля 2012

Если вам действительно нужна условная компиляция и вы используете Ant , вы можете отфильтровать код и выполнить поиск и замену в нем.

Например: http://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

Таким же образом вы можете, например, написать фильтр для замены LOG.debug(...); на /*LOG.debug(...);*/. Это все равно будет выполняться быстрее, чем if (LOG.isDebugEnabled()) { ... }, не говоря уже о том, чтобы быть в то же время более кратким.

Если вы используете Maven , здесь описана похожая функция здесь .

2 голосов
/ 29 ноября 2009

Никогда не использовал, но это существует

JCPP является полным, совместимым, автономная, чистая реализация Java препроцессора C Предназначен быть полезным людям, пишущим в стиле C компиляторы в Java с использованием таких инструментов, как sablecc, antlr, JLex, CUP и т. д. вперед. Этот проект был использован успешно предварительно обработать большую часть исходный код библиотеки GNU C. Как версии 1.2.5, он также может Предварительная обработка Apple Objective C библиотека.

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

1 голос
/ 29 ноября 2009

Использовать шаблон фабрики для переключения между реализациями класса?

Время создания объекта не может быть проблемой сейчас, не так ли? При усреднении за длительный период времени самая большая составляющая затраченного времени должна быть в основном алгоритме, не так ли?

Строго говоря, вам не нужен препроцессор, чтобы делать то, что вы хотите достичь. Скорее всего, есть и другие способы удовлетворения ваших требований, помимо предложенного мною.

0 голосов
/ 21 сентября 2015
final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
...