Java条件编译

21

我是一名长期从事C++编程的程序员,对Java还不太熟悉。 我正在使用Eclipse开发Java Blackberry项目。 问题是 - 是否有一种方法在项目内引入不同的配置集,然后根据这些集合编译稍微不同的代码?

在Visual Studio中,我们有项目配置和 #ifdef; 我知道Java中没有 #ifdef,但也许可以在文件级别上做些什么吗?


2
如果你只关心进入你的 jar 文件的内容(即生产,而不是开发),你的构建系统(例如 Ant)是你可以控制哪些文件被构建的地方。 - jdigital
谢谢大家,我明白了。条件编译(某种意义上)还是比较容易的,但显然在Eclipse项目中没有本地支持多个目标。我会去看看Ant的相关资料。 - Seva Alekseyev
11个回答

17
你可以设置'final'字段和条件语句,以便编译器优化编译后的字节码。
...
public static final boolean myFinalVar=false;
...
if (myFinalVar) { 
 do something ....
 ....
}

如果代码编译时'myFinalVar'为false,则编译类中的'do something....'部分将被省略。如果您有多个条件,可以将它们全部移到另一个类(例如'Config.myFinalVar'),然后所有条件就可以集中在一个整洁的地方。
这种机制在'Hardcore Java'中有描述。
[实际上,我认为这与先前发布的“穷人的ifdef”机制相同。]

1
@Pacerier - 感谢提供链接 - 根据评论,我也发现我购买的书籍版本存在一些需要纠正的问题(例如,一些代码示例是“无序”的)- 我认为人们应该查看书评 - 但我只想指出,阅读此帖子的任何人都应该知道,“条件编译”描述的具体机制(事实上,书中的很多内容)仍然是可靠的。 - monojohnny

6

您可以管理不同的类路径,例如,在一组不同的目录中实现每个“Action”:

dir1/Main.java
dir2/Action.java
dir3/Action.java

然后为每个版本使用不同的类路径。

javac -sourcepath dir1 -cp dir2 dir1/Main.java

或者

javac -sourcepath dir1 -cp dir3 dir1/Main.java

但这是否意味着我们需要维护多个源代码副本? - Pacerier
我写这段代码已经五年了。如果现在的话,我会使用一个好老式的“if”语句。 - Pierre
嗯,但是为了使其工作,条件部分也需要与源代码混合在一起,这样我们实际上会有两份源代码? - Pacerier
是的,但你应该只编写小型代码,例如class Log { public void log(String s) { System.err.println(s);}}class Log { public void log(String s) {}} - Pierre

6
在JDK6中,你可以通过使用Java的ServiceLoader接口来实现。 在这里查看:这里

这是一个很好的功能,直到现在我都没有听说过。 - Joel
1
这个编程工具并不是很出名,因为在开源市场上存在着许多占主导地位的竞争者。但是考虑到您不想使用完整的IOC容器,只想加载相同接口的不同实现时,我发现它非常有用。 - Shamik
1
这对他来说行不通,因为他的目标是J2ME的BlackBerry。 - Jeremy Raymond

6
如果你想要特别针对黑莓设备进行编程,BlackBerry JDE有一个预处理器

您可以通过更新Eclipse™配置文件来启用应用程序的预处理。

在C:\Program Files\Eclipse\configuration\config.ini中添加以下行:osgi.framework.extensions=net.rim.eide.preprocessing.hook。如果在构建后启用了预处理,必须从“项目”菜单中清除项目,然后再次构建项目。

然后你可以在代码中做一些事情,比如:
//#ifdef SOMETHING
// do something here
//#else
// do something else
//#endif

有关详细信息,请参见指定预处理器定义


4

3
不,Java没有完全匹配该功能的方法。你可以使用切面或使用IOC容器注入不同的实现类。

1
你可以使用Maven的资源过滤功能,结合公共静态常量字段,这将在编译时进行条件编译。
private static final int MODE = ${mode};

...

if (MODE == ANDROID) {
    //android specific code here
} else {

}

现在您需要向Maven pom添加一个名为“mode”的属性,其值应与您的ANDROID常量相同。

Java编译器应该(!)删除if和else块,从而留下您的Android代码。

未经测试,因此不能保证,我更喜欢配置而不是条件编译。


3
这并不适合大量的代码。Java 有接口、实现和继承,专门用于解决这种问题。 - extraneon
同意。这就是为什么我说我更喜欢配置的原因。 - whiskeysierra

1

您可以将m4集成到构建过程中,有效地在Java编译器前面添加一个类似于C预处理器的模拟器。"集成"步骤需要一些技巧,但m4是处理文本的正确技术。


2
Java有其他解决相同问题的方法。如果您必须为这种最常见的问题而纠结于文件,那么您在设计方面确实做错了什么。 - extraneon
1
请注意OP的请求:“是否有一种方法可以在项目中引入不同的配置集,然后根据这些编译略有不同的代码?”要“编译略有不同的代码”,必须向编译器提供不同的源代码。是的,我已经了解了静态最终布尔技巧,但我认为那不是OP想要的。 - seh

1
除了Maven、Ant和其他提供类似功能的构建工具之外,更好的方法是在Java中构建接口并在运行时切换实现。
有关详细信息,请参见策略模式
与C/C++相反,这不会带来大的性能惩罚,因为Java的JIT编译器可以在运行时进行优化,并且在大多数情况下能够内联这些模式。
这种模式的最大优点是灵活性-您可以更改底层实现而不触及核心类。
您还应该查看IoC观察者模式以获取更多详细信息。

1

有几个项目为Java带来了基于注释的条件编译支持:

JPSG中的示例:

/* with Android|Iphone platform */
class AndroidFoo {
  void bar() {
    /* if Android platform */
    doSomething();
    /* elif Iphone platform */
    doSomethingElse();
    /* endif */
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接