3

我正在编写一个从文件中读取结构的程序。出于调试目的,如果我可以有一个编译时切换来打印读取的所有内容的名称和值,这将是非常方便的,可以在生产版本中禁用它们以获得更好的性能/代码大小。在 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");
}

但是,这需要我输入所有变量的名称两次,并且即使在发布版本上也要存储与所有名称对应的字符串。有更好的方法吗?

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

4

2 回答 2

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 这样的面向方面的编程框架。

于 2013-08-23T23:49:52.020 回答
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 个日志文件。”
于 2013-08-23T23:35:00.977 回答