[英]Looking for an easier way to write debugging print statements in Java
编辑:我很想看看史蒂夫里德的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 );
}
但显然得到变量名称说起来容易做起来难。
我坚持:
System.err.println ( "var: " + var );
或者有一个流行的速记版本?
我不会尝试编写任何花哨的方法来打印出调试信息。 如果您使用的是记录器,请坚持使用LOG.debug(...)
否则请坚持使用System.err.println(...)
。
您可能希望使用String.format("var=%s val=%s", "VarName", val)
而不是String连接。
确保在每个类中重写toString
方法以提供有意义的调试信息。
在一天结束时,通常更容易启动调试器并查看正在进行的操作,而不必跟踪已记录的调试行的负载。
我使用您的调试方法的唯一时间是,如果我的应用程序在地图中维护了所有状态,我可以轻松地打印出键值对(例如,Web应用程序中的会话映射)。
看看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);
}
}
我认为System.err.format就是你想要的:
System.err.format("var: %s\n", var);
是一个简写:
System.err.println(String.format("var: %s", var));
我个人并不建议在任何地方使用sysout语句。 您应该始终使用调试器(使用某些IDE)。 我无法想象这不会被通缉的地方。
否则我建议像log4j这样的日志记录框架,但是再次,这已经变得更加复杂,我将再次使用调试器切换到真正的IDE。
如果使用IntelliJ IDEA,可以使用“实时模板”快捷方式打印到System.out,例如soutp (and then a TAB)
来调试方法参数, soutv
用于跟踪变量的名称及其值,等等。
要读取快捷方式列表\\修改它,请转到文件 - >设置 - >实时模板 - >输出
我的第一个建议是:坚持使用java.util.logging包。 实际上不需要第三方日志库。
获取java.util.Logger的实例
Logger logger = Logger.getLogger(“some.package.XyzClassName”);
记录对象(使用占位符{N})
logger.log(Level.INFO,“logging stuff {0} and {1}”,new Object [] {new String(“Test”),1222});
在用户定义的类的情况下,您需要有一些明智的toString()重写实现,因为在消息{N}中替换占位符时会调用此方法。
您可以使用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以查看您还可以获得的其他内容(行号,源和目标对象等)。
这是一段时间,但......
您将获得使用IDE而不是简单文本编辑器的建议。 100%,我赞同这一点。
您将获得使用日志框架或调试器而不是println()调用的建议。 嗯,当然,但......
更好的是单元测试。 不要问它是什么 - 告诉它你的期望。 然后,集成的单元测试框架(通常是junit)将验证您是否得到了您期望的结果。 我使用单元测试越多,我需要的调试就越少,而且我需要的println就越少。 当一些事情发生变化时,测试框架告诉我 - 我不需要手动重新评估每个测试的输出,只需看一下吧。
单元测试比调试好,比记录更好。 它们不是100%替代调试和日志记录,但是开始使用它们,你会发现对这些乏味活动的需求要少得多。
你试过DoodleDebug吗? 它是一个Eclipse插件,意味着像System.out.println()
一样简单但功能更强大。
它可以在这里找到: http : //scg.unibe.ch/wiki/projects/DoodleDebug
我建议你正确配置和使用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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.