java预处理_流形:Java的预处理器

Manifold预处理器是一个javac插件,专为条件编译设计,无宏。它提供类似C系列的预处理器指令,如#define,允许根据符号定义构建多个目标。预处理器能够引用和定义跨文件的符号,甚至可以从属性文件和环境设置中获取值。预处理器的使用可在IDEA中可视化,以直观展示代码如何响应预处理指令和符号变化。
摘要由CSDN通过智能技术生成

java预处理

预习

这是一个快速预览,可让您了解Manifold的预处理器。

我们将在本文后面深入探讨正在发生的事情。

基本原理

预处理器存在不可否认的污名,主要植根于C / C ++社区。 的确,从C ++过渡到Java的任何人都有他们最喜欢的涉及预处理器的恐怖故事。 故事中的对手总是《宏》 。 这个角色是一个恶魔般的骗子,诱使程序员认为较小等于更简单,因此更好。 但Macro的最终目标是迷惑,他非常擅长实现这一目标。 使用的所有其他C ++库都证明了这一点,但是我离题了。 因此,事不宜迟,我将最后指出指出将Macro保留 Java剧本之外的决定是有益而有效的。 结束。

等一下。 那么条件编译呢? 您知道,预处理器的另一半。 Java的设计师是否通过完全避免使用预处理器而将婴儿带走了洗澡水? 在C / C ++库中#ifdef大多数用法都与他们所针对的许多平台有关之后,大多数Java“历史学家”都会将Java的平台独立性作为设计者的理由。 没错,但是还有许多其他尺寸可以用来确定构建目标。 例如:

  • Java源版本(6 v。8 v。11)
  • 主机版本(正在运行什么版本的X?)
  • 生产v。开发v。测试
  • 许可v。免费
  • 新手诉专业版
  • 功能分组
  • 实验功能
  • 原型制作
  • 等等

虽然可以围绕这些维度对体系结构进行建模(例如使用依赖项注入),但有时这之间的桥梁太远了,尤其是当现有的体系结构出现新的目标维度时。 有时这不是一个选择,只要有选择,您的某些体系结构就可以合理地重构,而其他部分则可以使用预处理器更好。 在任何情况下,都可以使用预处理器是一个很好的便利,并且应该在Java工具箱中占有一席之地。 这就是Manifold项目中新预处理器背后的原理。

注意Java确实通过编译时常量条件提供了非常有限的条件编译版本,其中无法访问的代码分支从字节码中排除。 但是,这种类型的条件编译仅限于方法主体,只能引用静态最终变量,并且要求所有代码都在不考虑条件的情况下进行编译,这远非一个完整的解决方案。

总览

首先,预处理器是一个javac插件 ,这意味着它可以直接插入Java编译器中并作为javac的一部分运行-您无需添加中间构建步骤,管理源代码生成目标或任何其他操作。 这也意味着它运行Swift,并允许您从单个代码库轻松构建多个目标。

接下来,预处理器是专门为条件编译而设计的, 没有宏! 您仍然可以#define符号,但不能为其分配值-# #define符号始终为布尔值,其值始终为true ,除非当然未定义符号或未使用#undef定义符号。

正如您可能已经猜到的那样,预处理器不会尝试重塑任何东西。 这些指令直接来自预处理器的C系列。 这些包括:

我已经为这些家伙超链接了Manifold的文档。

一个非常有用的功能涉及可以从#if引用的符号。 您不仅可以引用使用#define定义的符号,还可以定义和使用来自其他所有项目文件可见的其他来源的符号。 这些文件包括build.properties文件和javac的-Akey[=value]编译器参数,您可以将其放置在从源根开始的父目录中。 此外,预处理器还提供反映环境设置的内置符号,例如JAVA_9_OR_LATERJPMS_NAMED

注意与#define符号不同,可以使用build.properties-Akey[=value]编译器参数来定义具有字符串值的符号。 在这种情况下,可以使用等于表达式==!=来测试值:

#if FOO_VERSION == "1.2.0"
  public void foo(Bar bar) {...}
#endif

build.properties:

FOO_VERSION=1.2.0
BAR_VERSION=2019.1.2
EXPERIMENTAL=

如果您针对多个Java版本,则环境设置符号可能会特别有用:

public class MyClass implements
#if JAVA_11_OR_LATER
  SomeJava11Interface
#elif JAVA_8_OR_LATER
  SomeJava8Interface
#else
  #error "Unexpected Java source version"
#endif
{
  ...
}

一个简单的例子

让我们从本文前面的预览中深入了解截屏视频。

这里的截屏视频使用Manifold插件通过IntelliJ IDEA演示了预处理器。 该示例使用#define定义MY_API_X符号,其中X有效值为12 。 注意,在现实生活中,我们会在build.properties文件中定义此符号,以便其他文件可以访问它,但是在这里,我们使用#define简化了演示。

#if语句使用该符号有条件地在编译中包含或排除代码。 随着符号值的更改,您可以看到启用/禁用代码以反映该值。 请注意,您可以从“歧管”部分的“ IntelliJ设置”视图关闭此功能,在这种模式下,仅对伪指令加阴影。 在这两种情况下,命令行编译器始终会遵守符号值。

注意,您可以将预处理器指令放置在类中的任何位置:围绕import语句,类,方法,字段,几乎可以放置在任何地方。 此功能是将预处理器与Java的基于编译时常量的条件编译区分开的众多功能之一。

在常规预处理器中找不到的另一个很酷的功能是在一行中使用多个指令。 您可以在implements子句中看到这一点。

还请参见:

您还可以注释掉指令,这是许多预处理器都不很好支持的功能。

如果您具有C ++背景,则可能想知道#ifdef#if defined哪里。 根本不需要它们,因为使用此预处理器,根据是否定义了符号,符号的计算结果为truefalse 。 只有使用==!=运算符,您才能访问符号的字符串值 ,如前所述,只能使用build.properties-Akey[=value]编译器参数进行定义。 因此, #if涵盖了所有基础。 阅读更多有关此文档

还要注意的是#elif指令。 这不是一个新概念,但是如果您没有C ++背景,这似乎很奇怪。 简单的解释是,没有简洁的方法可以像在Java中那样说else if

#if FOO
  out.println("FOO");
#else
  #if BAR
    out.println("BAR");
  #else
    #if BAZ
      out.println("BAZ");  
    #endif
  #endif    
#endif

使用#elif更为容易:

#if FOO
  out.println("FOO");
#elif BAR
  out.println("BAR");  
#elif BAZ
  out.println("BAZ");  
#endif

最后,请注意使用#error来响应有关MY_API_X的无效状态。 该指令在其使用位置会产生编译时错误。 非常适合在编译时检测和报告配置错误的构建。

结论

歧管将经过时间考验的C / C ++预处理器重新构想为满足当今条件编译需求的更有效方法。 它直接与Java编译器集成,因此您可以从单个代码库中快速轻松地构建多个目标。 您可以定义和使用来自各种源的符号,包括属性文件和环境设置,以有条件地编译源代码的各个方面。 使用对IntelliJ IDEA的插件支持,您可以准确地可视化代码对所使用的预处理程序指令和符号的React。 试试看让我们知道您的想法

查看Manifold项目以获得更多Java优势。

本文最初在Manifold网站发布

翻译自: https://jaxenter.com/manifold-preprocessor-for-java-160712.html

java预处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值