有没有办法在java中定义标志并仅在定义了这些标志时运行代码?

时间:2012-03-24 09:05:48

标签: java

c\c++中可以定义:

#ifndef <token>
    /* code */
#else
    /* code to include if the token is defined */
#endif

我的问题,有没有办法在java中做到这一点? (没有定义全局静态变量..) 例如,我想只在调试模式下运行一些代码..

谢谢!

6 个答案:

答案 0 :(得分:7)

答案是否定的。不是你的意思。

你在Java中做这种事情的方式如下:

private static final boolean flag = true;  /* or false :-) */

if (flag) {
   /* code */
} else {
   /* different code */
}

Java没有预处理器(比如C和C ++)。但是,编译器将优化掉if语句的未使用分支,如上所述,PROVIDED flag是编译时常量表达式。这是一种有限的条件编译形式。请注意,控制flag常量可以从其他类导入。

(IIRC,此行为在JLS中指定...这意味着您可以依赖任何符合规范的Java编译器来执行此操作。)


@Treebranch评论说“这个”会导致代码膨胀。

  1. 如果@Treebranch谈论的是对象代码膨胀,那不是这样。如果您使用由JLS定义的编译时常量表达式的flags /表达式执行此操作,则编译器不会为“有条件排除”的源代码发出任何字节码。请参阅@ edalorso的回答。

  2. 如果@Treebranch正在谈论源代码臃肿,我同意。但是你可以对#ifdef条件编译说同样的话。 (宏和#include可用于减少源代码膨胀......但仅以可读性,可维护性等为代价。这就是Java设计者拒绝支持任何源代码预处理的原因。 )

  3. Java有更好的方法来处理平台差异,功能变化等等:使用动态绑定。如果您的JAR中有许多不同的插件类是一个问题(字节码膨胀),请通过为每个平台创建不同的JAR文件来处理它。或者

答案 1 :(得分:4)

建议使用最终静态布尔变量的方法最接近于建议的特性,因为它甚至被编译器优化。如果该标志设置为false,则甚至不生成块中包含的字节码。

让我举个例子:

public class Optimized {

    private static final boolean DEBUG = true;

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

}

这会生成字节码

public class Optimized {
  public Optimized();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String DEBUG enabled
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

但是,如果我们关闭旗帜......

private static final boolean DEBUG = false;

字节码如下所示

public class Optimized {
  public Optimized();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: return
}

所以,AFAIK,这是你可以在Java中获得预编译指令的最接近的。

答案 2 :(得分:0)

上面粘贴的剪辑是conditional compilation macro,用于预编译器,在编译之前“转换”源代码。

Java没有等效的语言结构,所以anser是你不能那样做的。

编辑:然而,您可以使用常规条件来实现您的目标,因为这样编译器将以所需的方式优化字节码(感谢@StephenC指出这一点)。

但我个人更喜欢在需要的地方扩展API以进行调试,这将隐藏实现细节并可以更改运行时。当然这是特定于场景的。

例如,这与Log4j-s API类似,它可以让您检查代码是否处于调试模式。

我建议使用这种模式,因为这不会破坏(太多)我们心爱的面向对象的概念。

答案 3 :(得分:0)

在Java中没有像条件编译那样的东西。 (正如xea所说)

根据您要解决的问题,有各种方法可以做类似的事情。

一种是使用静态最终变量设置为编译时常量(正如Stephen所写)。编译器实际上不包含不可能路径的字节代码。但它仍然必须是合法的java,这意味着你不能在一个这样的块中声明一个变量并在另一个块中使用它。

到目前为止,我所见过的所有案例都可以使用OO结构来解决它。例如,您可以使用对抽象方法的调用替换if else,并提供调试和生产实现。

答案 4 :(得分:0)

Java作为一种语言没有类似的预处理或宏,如C或C ++,但有some 3rd party preprocessor - 工具,可以处理这些事情。为方便使用,您需要将它们连接到Maven或Ant构建中。

答案 5 :(得分:0)

我认为@StephenC提出的建议是个不错的选择。或者,您可以尝试使用 AspectJ 编织特定实现所需的代码。然后,当您不希望它作为实现的一部分时,您可以简单地删除方面(不要在代码中编织)。 AspectJ根据您指定的位置类型(称为切入点)修改字节码(已编译的Java代码)。这特别适合添加日志记录到程序中。

如果这是您感兴趣的方法,请查看:AspectJReference Guide