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

c\c++可以定义:

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

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

谢谢!

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

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

 private static final boolean flag = true; /* or false :-) */ if (flag) { /* code */ } else { /* different code */ } 

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

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


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

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

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

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

建议使用最终静态布尔变量的方法最接近于建议的特性,因为它甚至被编译器优化。 如果该标志设置为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."":()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."":()V 4: return public static void main(java.lang.String[]); Code: 0: return } 

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

没有什么比Java中的条件编译更好的了。 (正如xea所说)

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

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

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

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

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

如果这是您感兴趣的方法,请查看: AspectJ和参考指南 。

你在上面粘贴的剪辑是一个条件编译宏 ,用于预处理器,它在编译之前“转换”你的源代码。

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

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

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

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

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