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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9850445/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 08:35:58  来源:igfitidea点击:

is there a way to define flags in java and run code only if those flags are defined?

java

提问by Asher Saban

In c\c++can define:

c\c++可以定义:

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

my question, is there a way to do it in java? (which is not defining a global static variable..) for example i want to run some code only in debug mode..

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

thanks!

谢谢!

采纳答案by Stephen C

The answer is No. Not in the sense that you mean.

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

The way you do this kind of thing in Java as follows:

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

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

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

Java doesn't have a preprocessor (like C and C++ do). However, the compiler will optimize away the unused branch of an ifstatement like the above, PROVIDED that flagis a compile-time constant expression. This is a limited form of conditional compilation. Note that the controlling flagconstant can be imported from a different class.

Java 没有预处理器(就像 C 和 C++ 那样)。但是,编译器会优化掉if像上面这样的语句的未使用分支,PROVIDEDflag是编译时常量表达式。这是条件编译的一种有限形式。请注意,flag可以从不同的类导入控制常量。

(IIRC, this behaviour is specified in the JLS ... which means that you can rely on any conforming Java compiler to do it.)

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



@Treebranch comments that "this" can cause code bloat.

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

  1. If @Treebranch is talking about object code bloat, this is not true. If you do this right with flags/expressions that are compile-time constant expressions as defined by the JLS, then the compiler does not emit any bytecodes for the "conditionally excluded" source code. See @edalorso's answer.

  2. If @Treebranch is are talking about source-code bloat, I agree. But you can say the same thing for #ifdefconditional compilation. (Macros and #includecan be used to reduce source-code bloat ... but only at the cost of readability, maintainability, etc. And that was the reason that the Java designers refused to support any source-code preprocessing.)

  3. Java has a better way of dealing with platform differences, functionality variations and so on: use dynamic binding. If having lots of different plugin classes in your JAR is a concern (bytecode bloat), deal with it by creating a different JAR file for each platform, or whatever.

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

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

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

回答by xea

The snipped you pasted above was a conditional compilation macromeant for the preprocessor which "transforms" your source code before compilation.

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

Java does not have the equivalent language construct, so the anser is you can not do that.

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

Edit:You can do however use regular conditions to achieve your goal, since this way the compiler will optimize the bytecode in such way as desired (thanks for @StephenC for pointing this out).

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

But I personally prefer extending the API for debugging where needed which will hide the implementation details and can be changed runtime. Of course this is scenario-specific.

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

For example this would be similar to Log4j-s API, which lets you check if your code is in debug mode or not.

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

I would recommend the use of this pattern because that doesn't break (too much :) our beloved object oriented concepts.

我会推荐使用这种模式,因为它不会破坏(太多:) 我们钟爱的面向对象的概念。

回答by Jens Schauder

There is nothing like conditional compilation in Java. (as xea said)

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

Depending on the problem you want to solve there a various ways to do something similar.

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

One is to use a static final variable set to a compile time constant (as Stephen writes). The compiler will actually not include the byte code for the impossible path. But it still has to be legal java, which means you can't declare a variable in one such block and use it in another.

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

I all the cases I have seen so far one could solve it using OO constructs. For example you can replace your if else with a call to an abstract method and provide a debug and a production implementation.

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

回答by esaj

Java as a language has no similar preprocessing or macros like C or C++, however, there are some3rd partypreprocessor-tools, which can handle things like these. For handy usage, you'd need to wire them up into a Maven- or Ant-build.

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

回答by jbranchaud

I think what @StephenC has proposed is a good option. Alternatively, you can try using AspectJto weave in code that you want for a particular implementation. You can then simply remove the aspect (don't weave in the code) when you don't want it as part of the implementation. AspectJ modifies the bytecode (compiled Java code) based on the types of locations (called pointcuts) that you specify. This is particularly well suited for things like adding logging to your program.

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

If this is an approach you are interested in, check out: AspectJand Reference Guide.

如果您对这种方法感兴趣,请查看:AspectJ参考指南

回答by Edwin Dalorzo

The approach that suggest that use of final static boolean variable is the closest to that suggested feature because it is even optimized by the compiler. If the flag is set to false the bytecodes contained in the block are not even generated.

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

Let me show an example:

让我举个例子:

public class Optimized {

    private static final boolean DEBUG = true;

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

}

This generates the bytecodes

这将生成字节码

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
}

But if we turn the flag off...

但是如果我们关掉旗帜......

private static final boolean DEBUG = false;

The bytecodes look as follows

字节码如下所示

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
}

So, AFAIK, this is the closest you can get to a precompile directive in Java.

所以,AFAIK,这是最接近 Java 中预编译指令的方法。