相当于Java中的调试宏

时间:2013-08-23 23:32:35

标签: java debugging conditional-compilation

我正在编写一个从文件中读取结构的程序。出于调试目的,如果我可以使用编译时切换来打印所有读取的名称和值,这可以被禁用,以便在生产版本中获得更好的性能/代码大小,这将非常方便。在C中,我可以像这样使用预处理器来实现这个目的:

#ifdef DEBUG
  #define READ(name, in) { name = read(in); printf("#name: %d\n", name); }
#else
  #define READ(name, in) { name = read(in); }
#endif

void myreader(mystream_t *in)
{
    int a, b, c;

    READ(a, in);
    READ(b, in);
    READ(c, in);
}

有什么方法可以重现这个结构吗?我想到了这个:

private static final boolean DEBUG_ENABLED = true;

private int debugRead(MyInputStream in, String name) {
    int val = in.read();

    if (DEBUG_ENABLED) {
        System.out.println(String.format("%s: %d", name, val));
    }
    return val;
}

public MyReader(MyInputStream in) {
    int a, b, c;

    a = debugRead(in, "a");
    b = debugRead(in, "b");
    c = debugRead(in, "c");
}

但是,这要求我输入两次所有变量的名称,以及存储与发布版本相对应的所有名称的字符串。有更好的方法吗?

编辑:我最担心的是代码冗长。我想要的最后一件事就是让我的代码混乱,调试/打印/跟踪语句会掩盖实际的读取逻辑。

2 个答案:

答案 0 :(得分:0)

我不确定这是否是苹果对苹果解决方案,但Java中惯用的一件事是使用日志框架。有了它,您可以在需要调试的任何地方执行log.debug。 SLF4j是日志框架的通用外观。您可以将它与JUL日志记录一起使用。

通常您将日志记录代码留在那里,并在外部配置记录器以打印或不打印消息。

如果您正在使用SLF4j,则调试消息将如下所示:

log.debug("Setting the creation timestamp to {}", timestamp);

大多数记录器可以配置为告诉您日志消息来自哪个时间,类和方法。

与您习惯的相比,这有一些优点和缺点。

缺点

  • 我必须承认,如果你现在真正想要的只是一个System.out.println,这需要付出很多努力。
    • 大多数记录器都在类路径上配置。类路径是要学习的java的一个重要部分,但是 最终还是必须学习它。理解这一点非常重要。
  • 它不会自动打印出传入的变量的名称.AFAIK,你必须自己写这个细节

赞成

  • 使用记录器非常强大。您可以将代码保留在生产和开发模式中,只需适当地配置详细程度
  • 它可以自动打印出类/方法的上下文和消息的日期以及其他类似的内容
  • 您可以通过多种不同方式配置输出。例如,“输出到控制台 log.txt但当该文件变为> 100mb时,将旧数据翻转为log2.txt并保留最多5个日志文件。”

答案 1 :(得分:0)

对于在Java中模拟C / C ++宏的一般问题,有几种解决方案。记录的特殊情况通常以更简单的方式解决。最简单,概念最接近,最纯粹的形式是在界面中抽象宏并产生替代实现:

public class Sample {

    class mystream_t {
    }
    public int read(mystream_t is) {
        return 0 ;
    }
    static final boolean DEBUG= false ; 

    interface ReadType {
        public void apply(int[] name,mystream_t in);
    }
    ReadType READ; {
        if( DEBUG ) {
            READ= new ReadType(){
                public void apply(int[] name,mystream_t in) {
                    name[0]= read(in) ; System.out.printf("#name: %d\n",name);
                }
            };
        } else {
            READ= new ReadType(){
                public void apply(int[] name,mystream_t in) {
                    name[0]= read(in) ;
                }
            };
        }
    }
    void myreader(mystream_t in) {
        int[] a= new int[1], b= new int[1], c= new int[1];
        READ.apply(a, in);
        READ.apply(b, in);
        READ.apply(c, in);
    }
}

这使用了一种简单的静态代码注入形式。我试图使代码尽可能接近原始代码。

在Java中模拟C / C ++宏的第二个最相关的方法需要注释和注释处理。它更接近C / C ++宏,但需要更多的努力,并采用一种不能被视为语言纯粹部分的机制。

第三个是使用AspectJ等面向方面的编程框架。