Java条件编译:如何防止代码块被编译?

kha*_*hik 50 java conditional-compilation

我的项目需要Java 1.6进行编译和运行.现在我需要使用Java 1.5(来自营销方面).我想替换方法体(返回类型和参数保持不变),以使其使用Java 1.5进行编译而不会出现错误.

详细信息:我有一个实用程序类OS,它封装了所有特定于操作系统的东西.它有一种方法

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...
}
Run Code Online (Sandbox Code Playgroud)

打开文件,如双击(startWindows命令或openMac OS X命令等效).由于无法使用Java 1.5进行编译,因此我希望在编译期间将其排除,并替换为另一种调用run32dllWindows或openMac OS X的方法Runtime.exec.

问题:我该怎么办?注释可以帮到这里吗?

注意:我使用ant,我可以制作两个java文件OS4J5.java,OS4J6.java它们将包含OS带有Java 1.5和1.6所需代码的类,并OS.java在编译之前复制其中一个(或者一种丑陋的方式 - OS.java根据java有条件地替换内容如果有另一种方式,我不想这样做.

详细说明:在CI中可以使用ifdef, ifndef,在Python中没有编译,我可以hasattr在Common Lisp中使用或其他东西检查功能,我可以使用#+feature.Java有类似的东西吗?

发现这篇文章,但它似乎没有帮助.

任何帮助是极大的赞赏.KH.

Gar*_*vis 43

不,Java中没有任何对条件编译的支持.

通常的计划是隐藏应用程序的操作系统特定位,Interface然后在运行时检测操作系统类型并使用加载实现Class.forName(String).

在你的情况下,没有理由你不能OS*使用Java 1.6 编译两者(以及你的整个应用程序)-source 1.5 -target 1.5然后在工厂方法中获取OS类(现在是一个接口)检测java.awt.Desktop 该类是否可用加载正确的版本.

就像是:

 public interface OS {
     void openFile(java.io.File file) throws java.io.IOException;
 }

 public class OSFactory {
     public static OS create(){
         try{
             Class.forName("java.awt.Desktop");
             return new OSJ6();
         }catch(Exception e){
             //fall back
             return new OSJ5();
         }
     }
 }
Run Code Online (Sandbox Code Playgroud)


rsp*_*rsp 18

隐藏像Gareth这样的接口背后的两个实现类可能是最好的方法.

也就是说,您可以在ant构建脚本中使用replace任务引入一种条件编译.诀窍是在代码中使用注释,这些注释在编译源代码之前由文本替换打开/关闭,例如:

/*{{ Block visible when compiling for Java 6: IFDEF6

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5: IFDEF5

  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */
Run Code Online (Sandbox Code Playgroud)

现在在ant中,当您为Java 6编译时,将"IFDEF6"替换为"*/",给出:

/*{{ Block visible when compiling for Java 6: */

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using java.awt.Desktop
  ...

/*}} end of Java 6 code. */

/*{{ Block visible when compiling for Java 5, IFDEF5

public static void openFile(java.io.File file) throws java.io.IOException {
  // open the file using alternative methods
  ...

/*}} end of Java 5 code. */
Run Code Online (Sandbox Code Playgroud)

在编译Java 5时,替换"IFDEF5".请注意,您需要小心使用// comments里面/*{{,/*}}块.


You*_*jae 7

下面介绍的Ant脚本提供了很好的清洁技巧.

链接:https://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

在例如,

//[ifdef]
public byte[] getBytes(String parameterName)
        throws SQLException {
    ...
}
//[enddef]
Run Code Online (Sandbox Code Playgroud)

用Ant脚本

        <filterset begintoken="//[" endtoken="]">
            <filter token="ifdef" value="${ifdef.token}"/>
            <filter token="enddef" value="${enddef.token}"/>
        </filterset>
Run Code Online (Sandbox Code Playgroud)

请转到上面的链接了解更多详情.


Pet*_*rey 5

您可以使用反射进行调用,并使用Java 5编译代码.

例如

Class clazz = Class.forName("java.package.ClassNotFoundInJavav5");
Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class);
method.invoke(args1);
Run Code Online (Sandbox Code Playgroud)

您可以捕获任何异常并回退到适用于Java 5的内容.


Igo*_*tsa 5

如果你不想在你的应用程序中有条件地启用代码块,那么预处理器是唯一的方法,你可以看看java-comment-preprocessor可以用于 maven 和 ant 项目
ps
我也做了一些例子如何使用 Maven 预处理构建 JEP-238 多版本 JAR,无需重复源代码


gre*_*gko 5

我不是一个优秀的Java专家,但似乎支持Java中的条件编译并且很容易.请阅读:

http://www.javapractices.com/topic/TopicAction.do?Id=64

引用要点:

条件编译实践用于可选地从类的编译版本中删除代码块.它使用编译器将忽略任何无法访问的代码分支的事实.要实现条件编译,

  • 将静态最终布尔值定义为某个类的非私有成员
  • 在if块中有条件地编译的地方代码,用于计算布尔值
  • 将boolean的值设置为false以使编译器忽略if块; 否则,保持其值为真

当然,这让我们可以在任何方法中"编译"代码块.要删除类成员,方法甚至整个类(可能只留下存根),您仍然需要预处理器.

  • 仅当您具有可编译的代码时,此处指定的方法才有效。 (2认同)

bvd*_*vdb 5

java 9中,可以创建多版本jar文件.本质上,它意味着您创建相同java文件的多个版本.

编译它们时,使用所需的jdk版本编译每个版本的java文件.接下来,您需要将它们打包在如下所示的结构中:

+ com
  + mypackage
    + Main.class
    + Utils.class
+ META-INF
  + versions
    + 9
      + com
        + mypackage
          + Utils.class
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,代码的主要部分是在java 8中编译的,但是对于java 9,还有一个类的其他(但不同)版本Utils.

当您在java 8 JVM上运行此代码时,它甚至不会检查META-INF文件夹中的类.但是在java 9中它会发现并使用更新版本的类.


Sco*_*ott 5

Manifold 框架中有一个新的 Java预处理器。它是一个 javac插件,这意味着它直接与 Java 编译器集成——没有构建步骤,没有代码生成目标等需要管理。

在此处输入图片说明