简体   繁体   English

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

[英]Looking for an easier way to write debugging print statements in Java

EDIT: I would love to read reactions to Steve Reed's AOP approach. 编辑:我很想看看史蒂夫里德的AOP方法的反应。 Comments to his answer are encouraged! 鼓励回答他的回答!

I'm a novice, and at some point I realized it would be helpful to know the contents of a variable during program execution. 我是新手,在某些时候我意识到在程序执行期间知道变量的内容会很有帮助。 So I started doing this: 所以我开始这样做:

EDIT: fixed this. 编辑:修复此问题。 Used to be: var + ": " + var, which was totally wrong. 曾经是:var +“:”+ var,这是完全错误的。 Dumb typo. 愚蠢的错字。

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

Later I learned that this was common practice. 后来我才知道这是常见的做法。 At least, where a debugger was unavailable or unwanted. 至少,调试器不可用或不需要的地方。

I use a basic text editor, and typing the print statement every time I need to debug a variable is pretty tiresome, so I thought, why not something like this: 我使用基本的文本编辑器,每次需要调试变量时键入print语句都很烦人,所以我想,为什么不是这样的:

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

But apparently getting the variable name is easier said than done. 但显然得到变量名称说起来容易做起来难。

java-reflection-how-to-get-the-name-of-a-variable Java的反射如何对获得最名称对的一变量

Am I stuck with: 我坚持:

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

Or is there a popular shorthand version of this? 或者有一个流行的速记版本?

I wouldn't try and write any fancy methods around printing out debugging info. 我不会尝试编写任何花哨的方法来打印出调试信息。 Just stick with either LOG.debug(...) if you are using a logger or System.err.println(...) otherwise. 如果您使用的是记录器,请坚持使用LOG.debug(...)否则请坚持使用System.err.println(...)

You may wish to use String.format("var=%s val=%s", "VarName", val) instead of the String concatenation. 您可能希望使用String.format("var=%s val=%s", "VarName", val)而不是String连接。

Make sure that you override the toString method in each of your classes to provide meaningful debug info. 确保在每个类中重写toString方法以提供有意义的调试信息。

At the end of the day it's often easier to fire up the debugger and take a look to see what's going on instead of having to trace through loads of logged debug lines. 在一天结束时,通常更容易启动调试器并查看正在进行的操作,而不必跟踪已记录的调试行的负载。

The only time when i'd use your kind of debug method would be if my application maintained all of the state inside a map which I could easily print out the key value pairs (eg the session map in a web application). 我使用您的调试方法的唯一时间是,如果我的应用程序在地图中维护了所有状态,我可以轻松地打印出键值对(例如,Web应用程序中的会话映射)。

Have a look at Simple Logging Framework , it allows you to type: 看看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);
    }
}

I think that System.err.format is what you want: 我认为System.err.format就是你想要的:

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

is a shorthand for: 是一个简写:

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

Some thoughts: 一些想法:

  1. I would implement toString() on objects of interest, and in that print out the members in a friendly fashion (eg convert timestamps to a readable format etc.). 我会在感兴趣的对象上实现toString() ,并以友好的方式打印成员(例如将时间戳转换为可读格式等)。 I usually choose a format like: 我通常会选择以下格式:

     Object[member1=,member2=...] 

    Otherwise printing the object alone will give you the classname plus the identity hash code, and (as you've discovered) that's not hugely useful! 否则单独打印对象将为您提供类名加上身份哈希码,并且(正如您所发现的那样)并不是非常有用!

    Commons has a facility to do this automatically . Commons有自动执行此操作的工具。 But here's a simple toString() tutorial which I think is more appropriate. 但这是一个简单的toString() 教程 ,我觉得更合适。

  2. There are logging frameworks that you may be interested in in the future. 您可能会对将来感兴趣的日志框架有所了解。 eg check out Log4j . 例如,查看Log4j At the moment, however, I wouldn't worry about that. 但是,目前我不担心这一点。

Personally I don't suggest to use sysout statements anywhere. 我个人并不建议在任何地方使用sysout语句。 You should always use a debugger (using some IDE). 您应该始终使用调试器(使用某些IDE)。 I cannot imagine where this wouldn't be wanted. 我无法想象这不会被通缉的地方。

Otherwise I'm suggesting logging frameworks like log4j, but again, this already gets more complicated where I would again then switch to a real IDE with debugger. 否则我建议像log4j这样的日志记录框架,但是再次,这已经变得更加复杂,我将再次使用调试器切换到真正的IDE。

If you use IntelliJ IDEA, you can use the "Live template" shortcut for printing to System.out such as soutp (and then a TAB) to debug the method parameters, soutv to trace the name of a variable along with it's value, etc. 如果使用IntelliJ IDEA,可以使用“实时模板”快捷方式打印到System.out,例如soutp (and then a TAB)来调试方法参数, soutv用于跟踪变量的名称及其值,等等。

To read the list of shortcuts\\modify it, go to File->Settings->Live Templates->Output 要读取快捷方式列表\\修改它,请转到文件 - >设置 - >实时模板 - >输出

My first advice is: stick to java.util.logging package. 我的第一个建议是:坚持使用java.util.logging包。 There is really no need for 3rd party logging libraries. 实际上不需要第三方日志库。

  1. Get instance of java.util.Logger 获取java.util.Logger的实例

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

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

    logger.log(Level.INFO, "logging stuff {0} and {1}", new Object[]{new String("Test"), 1222}); logger.log(Level.INFO,“logging stuff {0} and {1}”,new Object [] {new String(“Test”),1222});

In case of user defined classes you need to have some sensible toString() override implementation, because this method is called when replacing placeholder in message {N}. 在用户定义的类的情况下,您需要有一些明智的toString()重写实现,因为在消息{N}中替换占位符时会调用此方法。

You can get access to the variable names with AOP and compile-time weaving. 您可以使用AOP和编译时编织来访问变量名称。 The nice thing about this is that if you don't do the weaving, you don't add the debug logging code and your runtime code is leaner and quicker as a result. 关于这一点的好处是,如果您不进行编织,则不会添加调试日志记录代码,因此您的运行时代码更精简,更快捷。

Here's an example of using AspectJ to throw an exception when a field is set to null. 下面是一个使用AspectJ在字段设置为null时抛出异常的示例。 Note the usage of " joinPoint.getSignature() " to get access to the code metadata. 请注意使用“ 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.");
      }
   }
}

See JoinPoint Javadoc to see what else you can get (line numbers, source and target objects, etc). 请参阅JoinPoint Javadoc以查看您还可以获得的其他内容(行号,源和目标对象等)。

It's a stretch, but... 这是一段时间,但......

You're getting advice to use an IDE instead of a simple text editor. 您将获得使用IDE而不是简单文本编辑器的建议。 I'd go along with that, 100%. 100%,我赞同这一点。

You're getting advice to use a logging framework or a debugger instead of println() calls. 您将获得使用日志框架或调试器而不是println()调用的建议。 Well, sure, but... 嗯,当然,但......

Better yet is unit tests. 更好的是单元测试。 Don't ask what it is - tell it what you expect. 不要问它是什么 - 告诉它你的期望。 Then, the integrated unit-testing framework (junit, typically) will verify that you're getting what you expect. 然后,集成的单元测试框架(通常是junit)将验证您是否得到了您期望的结果。 The more I use unit tests, the less I need debugging and the less I need println's. 我使用单元测试越多,我需要的调试就越少,而且我需要的println就越少。 And when something changes, the testing framework tells me - I don't need to manually re-evaluate every test's output, just watch the bar. 当一些事情发生变化时,测试框架告诉我 - 我不需要手动重新评估每个测试的输出,只需看一下吧。

Unit tests are better than debugging, better than logging. 单元测试比调试好,比记录更好。 They're not a 100% replacement for debugging and logging, but start using them and you'll find much less need for those tedious activities. 它们不是100%替代调试和日志记录,但是开始使用它们,你会发现对这些乏味活动的需求要少得多。

Have you tried DoodleDebug? 你试过DoodleDebug吗? It's an Eclipse plugin and meant to be as easy as System.out.println() but much more powerful. 它是一个Eclipse插件,意味着像System.out.println()一样简单但功能更强大。

It can be found here: http://scg.unibe.ch/wiki/projects/DoodleDebug 它可以在这里找到: http//scg.unibe.ch/wiki/projects/DoodleDebug

I would recommend you to properly configure and use Apache Log4J. 我建议你正确配置和使用Apache Log4J。 System.out or System.err lines cause a lot of delay in execution of program. System.out或System.err行导致程序执行延迟很多。 (You can confirm this by adding some time info that how much time your program takes without System.out etc and how much without these lines.) (您可以通过添加一些时间信息来确认这一点,这些信息表明您的程序在没有System.out等的情况下需要多长时间以及没有这些行的情况。

Logging APIs use separate threads to log your logging info in log files, thats why they are more useful in realistic applications. 日志API使用单独的线程在日志文件中记录日志信息,这就是为什么它们在实际应用程序中更有用。 Also logging APIs like Log4J give a lot of control over how to configure and format your logs. 此外,Log4J等日志记录API可以很好地控制如何配置和格式化日志。 For example look here a few logs generated from Log4J: 例如,在这里查看从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 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM