Java中的#ifdef #ifndef

时间:2009-11-28 21:38:28

标签: java compilation conditional conditional-compilation

我怀疑是否有办法在Java中创建编译时条件,如C ++中的#ifdef #ifndef。

我的问题是有一个用Java编写的算法,并且我有不同的运行时间改进了该算法。因此,我想测量每次使用每次改进时节省的时间。

现在我有一组布尔变量,用于在运行时决定应该使用哪些改进,哪些不使用。但即使测试这些变量也会影响总运行时间。

所以我想找到一种方法来在编译期间决定编译和使用程序的哪些部分。

有人知道在Java中使用它的方法。或者也许有人知道没有这样的方式(它也会有用)。

9 个答案:

答案 0 :(得分:120)

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编译器进行评估。这个开销可以忽略不计。

答案 1 :(得分:43)

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

答案 2 :(得分:11)

我认为我找到了解决方案,它更加简单 如果我使用“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++;
    }

答案 3 :(得分:2)

从未使用它,但存在

  

JCPP是完整的,合规的,   独立的纯Java实现   C预处理器。它的目的是   对于写C风格的人有用   Java中的编译器使用类似的工具   sablecc,antlr,JLex,CUP等   向前。该项目已被使用   成功预处理了大部分内容   GNU C库的源代码。如   版本1.2.5,它也可以   预处理Apple Objective C   库。

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

答案 4 :(得分:2)

如果您确实需要条件编译并使用 Ant ,则可以过滤代码并在其中进行搜索和替换。

例如:http://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

例如,您可以使用相同的方式编写过滤器,将LOG.debug(...);替换为/*LOG.debug(...);*/。这仍然会比if (LOG.isDebugEnabled()) { ... }更快地执行,更不用说同时更简洁了。

如果您使用 Maven ,则会有类似的功能 here

答案 5 :(得分:1)

使用工厂模式在类的实现之间切换?

对象创建时间现在不能关注吗?当在很长的运行时间段内平均时,花费的时间的最大部分应该是在主算法中现在不是吗?

严格来说,您并不需要预处理器来实现您想要实现的目标。当然,最有可能是满足您要求的其他方式。

答案 6 :(得分:1)

Manifold提供了完全集成的Java预处理器(没有构建步骤或生成的源代码)。它专门针对条件编译,并使用C风格的指令。

Manifold's Java Preprocessor

答案 7 :(得分:0)

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

答案 8 :(得分:0)

如果您使用IntelliJ,则有一个名为Manifold的插件,它与许多其他功能一起,允许一个人在Java中使用#ifdef#define

插件网址: https://manifold.systems/

预处理器信息: https://github.com/manifold-systems/manifold/tree/master/manifold-deps-parent/manifold-preprocessor

PS:我不隶属于他们,我们只是偶然使用它,它在没有工作流的情况下有很大帮助(这对于Java开发而言可能不常见)