#ifdeF#ifndef в Java

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

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

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

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

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

9 ответов

Решение
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-компилятором. Накладные расходы для этого незначительны.

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

Я думаю, что я нашел решение, это намного проще.
Если я определю логические переменные с помощью "финального" модификатора, то сам 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++;
    }

Manifold предоставляет полностью интегрированный препроцессор Java (без шагов сборки или сгенерированного исходного кода). Он предназначен исключительно для условной компиляции и использует директивы в стиле C.

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

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

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

Если вы используете IntelliJ, есть плагин под названием Manifold, который, наряду со многими другими функциями, позволяет использовать #ifdefа также #defineв Яве.

Адрес плагина: https://manifold.systems/

Информация о препроцессоре:https://github.com/manifold-systems/manifold/tree/master/manifold-deps-parent/manifold-preprocessor

PS: я не связан с ними, мы просто используем его, и это очень помогает без рабочего процесса (что, вероятно, НЕ типично для разработки Java)

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

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

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

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

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

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

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

final static int appFlags = context.getApplicationInfo().flags;
final static boolean isDebug = (appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0
Другие вопросы по тегам