寻找一种用Java编写调试print语句的简单方法

时间:2009-08-06 14:12:58

标签: java debugging

编辑:我很想看看史蒂夫·里德的AOP方法的反应。鼓励回答他的回答!

我是新手,在某些时候我意识到在程序执行期间知道变量的内容会很有帮助。所以我开始这样做了:

编辑:解决了这个问题。曾经是:var +“:”+ var,这是完全错误的。愚蠢的错字。

System.err.println ( "var: " + var );

后来我了解到这是常见做法。至少,调试器不可用或不需要的地方。

我使用基本的文本编辑器,每次需要调试变量时输入print语句都很烦人,所以我想,为什么不是这样的:

void dbug ( Object obj )
{
    String variableName = obj.somehowGetVariableName();
    String variableContents = obj.toString();
    System.out.println ( variableName +": " + variableContents );
}

但显然获取变量名称说起来容易做起来难。

java-reflection-how-to-get-the-name-of-a-variable

我坚持:

System.err.println ( "var: " + var );

或者有一个流行的速记版本吗?

12 个答案:

答案 0 :(得分:9)

我不会尝试编写任何花哨的方法来打印出调试信息。如果您使用的是记录器,请坚持使用LOG.debug(...),否则请坚持使用System.err.println(...)

您可能希望使用String.format("var=%s val=%s", "VarName", val)而不是字符串连接。

确保覆盖每个类中的toString方法,以提供有意义的调试信息。

在一天结束时,通常更容易启动调试器并查看发生了什么,而不必跟踪已记录的调试行的负载。

我唯一一次使用你的调试方法就是我的应用程序在地图中维护了所有状态,我可以轻松地打印出键值对(例如Web应用程序中的会话映射)。

答案 1 :(得分:6)

看看Simple Logging Framework,它允许您输入:

class Example {
    static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Example.class);

    void doSomething(Object obj1, Object obj2) {
        LOG.debug("This is object 1: {}, and this is object 2: {}", obj1, obj2);
    }
}

答案 2 :(得分:4)

我认为System.err.format就是你想要的:

System.err.format("var: %s\n", var);

是:

的简写
System.err.println(String.format("var: %s", var));

答案 3 :(得分:2)

一些想法:

  1. 我会在感兴趣的对象上实现toString(),并以友好的方式打印成员(例如将时间戳转换为可读格式等)。我通常会选择以下格式:

    Object[member1=,member2=...]
    

    否则单独打印对象将为您提供类名加上身份哈希码,并且(正如您所发现的那样)并不是非常有用!

    Commons有do this automatically的设施。但这是一个简单的toString() tutorial我觉得更合适。

  2. 您可能会对将来感兴趣的日志框架感兴趣。例如看看Log4j。但是,目前我不担心这一点。

答案 4 :(得分:2)

我个人不建议在任何地方使用sysout语句。您应该始终使用调试器(使用某些IDE)。我无法想象不想要的地方。

否则我建议像log4j这样的日志记录框架,但是再一次,这已经变得更加复杂,我将再次使用调试器切换到真正的IDE。

答案 5 :(得分:1)

如果您使用IntelliJ IDEA,则可以使用" Live模板"打印到System.out的快捷方式,例如soutp (and then a TAB)以调试方法参数,soutv以跟踪变量的名称及其值等。

要阅读快捷方式列表\修改它,请转到文件 - >设置 - >动态模板 - >输出

答案 6 :(得分:1)

我的第一个建议是:坚持使用java.util.logging包。实际上不需要第三方日志库。

  1. 获取java.util.Logger的实例

    Logger logger = Logger.getLogger(" some.package.XyzClassName");

  2. 记录对象(使用占位符{N})

    logger.log(Level.INFO,"记录东西{0}和{1}",新对象[] {新字符串("测试"),1222})

  3. 如果是用户定义的类,则需要有一些合理的toString()重写实现,因为在消息{N}中替换占位符时会调用此方法。

答案 7 :(得分:0)

您可以使用AOP和编译时编织来访问变量名称。关于这一点的好处是,如果您不进行编织,则不会添加调试日志代码,因此您的运行时代码更精简,更快。

这是使用AspectJ在字段设置为null时抛出异常的示例。请注意使用“joinPoint.getSignature()”来访问代码元数据。

@Aspect
public class NotNullValidator {

   @Pointcut(value = "set(@com.acme.NotNull * *.*) && args(valueBeingSet)")
   private void setOfNonNullField(final Object valueBeingSet) { }

   @Before(value = "setOfNonNullField(valueBeingSet)")
   public void validate(final JoinPoint joinPoint, final Object valueBeingSet) {
      if (valueBeingSet == null) {
         throw new NullPointerException("Cannot set " + joinPoint.getSignature().getName() + " to null.");
      }
   }
}

请参阅JoinPoint Javadoc,了解您还可以获得的其他内容(行号,来源和目标对象等)。

答案 8 :(得分:0)

这是一段时间,但是......

您将获得使用IDE而不是简单文本编辑器的建议。我赞同这一点,100%。

您将获得使用日志框架或调试器而不是println()调用的建议。嗯,当然,但是......

更好的是单元测试。不要问它是什么 - 告诉它你的期望。然后,集成的单元测试框架(通常是junit)将验证您是否得到了您期望的结果。我使用单元测试越多,我需要的调试就越少,而且我需要的println就越少。当某些内容发生变化时,测试框架会告诉我 - 我不需要手动重新评估每个测试的输出,只需看看吧。

单元测试优于调试,优于日志记录。它们不是100%替代调试和日志记录,但是开始使用它们,你会发现对这些乏味活动的需求要少得多。

答案 9 :(得分:0)

我建议您正确配置和使用Apache Log4J。 System.out或System.err行导致程序执行延迟很多。 (您可以通过添加一些时间信息来确认这一点,这些信息表明您的程序在没有System.out等的情况下花费了多少时间以及没有这些行的时间。)

日志API使用单独的线程在日志文件中记录日志信息,这就是为什么它们在实际应用程序中更有用。此外,Log4J等日志记录API可以很好地控制如何配置和格式化日志。例如,在这里查看从Log4J生成的一些日志:

2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.IOUtil  - 
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.IOUtil  - Application Configs Loaded
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.Constants  - Running Application between dates.
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.Constants  - Sat Jan 01 00:00:00 GMT+05:00 2011 From Date 
2012-01-05 15:16:41,730 [main] 16   DEBUG dmfssecbuild.Constants  - Mon Dec 31 00:00:00 GMT+05:00 2012 To Date 

答案 10 :(得分:0)

你有没有尝试过DoodleDebug?它是一个Eclipse插件,意味着像System.out.println()一样简单但功能更强大。

可在此处找到:http://scg.unibe.ch/wiki/projects/DoodleDebug

答案 11 :(得分:0)

无论您走哪条路,我都建议您执行以下操作:

  1. 在“Util”或“Debug”类中创建自定义的 Debug.out(Object) 方法,因此无论您决定如何记录错误,都可以轻松地为整个程序更改它;
  2. 如果您使用 Eclipse、VSCode 或任何其他具有“模板”的 IDE,请制作一个只写 Debug.out("<method name> " + string) 的“调试”模板。至少使用 Eclipse,您可以让模板为您编写方法名称。