#ifdef #ifndef в Java

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

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

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

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

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


person jutky    schedule 28.11.2009    source источник


Ответы (8)


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

person Mark Thornton    schedule 28.11.2009
comment
Это решение лучше моего. Когда я попытался инициализировать переменные заданным внешним значением, время работы вернулось к 3 секундам. Но когда я определил переменные как статические переменные класса (а не как локальную переменную функции), время работы вернулось к 1 секунде. Спасибо за помощь. - person jutky; 29.11.2009
comment
IIRC, это работало даже до того, как в Java появился JIT-компилятор. Код был удален javac Я думаю. Это работало, только если выражение для (скажем) enableFast было выражением константы времени компиляции. - person Stephen C; 29.11.2009
comment
Да, но это условие должно находиться в методе, верно? Как насчет случая, когда у нас есть набор частных статических final Strings, которые мы хотели бы установить. (например, набор URL-адресов серверов, которые настроены по-разному для производства и подготовки) - person tomwhipple; 19.11.2011
comment
@tomwhipple: правда, плюс это не позволяет делать что-то вроде: private void foo(#ifdef DEBUG DebugClass obj #else ReleaseClass obj #endif ) - person Zonko; 04.12.2011
comment
как насчет импорта (например, относительно пути к классам)? - person n611x007; 12.03.2014
comment
@Mark, JLS гарантирует такое поведение? - person Pacerier; 25.06.2014
comment
@tomwhipple, тернарный оператор или блоки статической инициализации, вам просто нужно разделить определение и инициализацию. - person HopefullyHelpful; 26.01.2017

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
person Phil Ross    schedule 28.11.2009
comment
Это конкретный javac или такое поведение действительно гарантируется JLS? - person Pacerier; 25.06.2014
comment
@pacerier, я понятия не имею, гарантировано ли это JLS, но это было верно для каждого компилятора java, с которым я сталкивался с 90-х годов, за возможным исключением до 1.1.7, и только потому, что я не тогда проверьте это. - person ; 27.10.2015

Я думаю, что нашел решение, оно намного проще.
Если я определю логические переменные с помощью модификатора final, компилятор 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++;
    }
person jutky    schedule 28.11.2009
comment
Это интересно. Похоже, JIT уже поддерживает условную компиляцию! Работает ли это, если эти финалы проходят в другом классе или другом пакете? - person joeytwiddle; 21.01.2013
comment
Здорово! Тогда я считаю, что это должна быть оптимизация времени выполнения, код фактически не удаляется во время компиляции. Это нормально, если вы используете зрелую виртуальную машину. - person joeytwiddle; 24.01.2013
comment
@joeytwiddle, ключевое слово до тех пор, пока вы используете зрелую виртуальную машину. - person Pacerier; 25.06.2014

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

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

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

person Tom    schedule 28.11.2009
comment
Я не уверен, что это соответствует моим потребностям. Мой код написан на Java. Может быть, вы предлагаете мне получить их исходники и использовать их для предварительной обработки моего кода? - person jutky; 29.11.2009

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

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

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

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

person rustyx    schedule 13.07.2012

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

Препроцессор Java от Manifold

person Scott    schedule 30.07.2019

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

URL плагина: https://manifold.systems/

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

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

person denmike    schedule 17.12.2020

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

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

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

person jldupont    schedule 28.11.2009
comment
Изменения очень незначительные. Это похоже на тестирование некоторых условий, чтобы заранее знать запрошенный результат, а не пересчитывать его. Так что накладные расходы на вызов функции могут мне не подходить. - person jutky; 29.11.2009