不可否认,未来的一到两年中,程序员的编码体验将会发生剧烈的变化。作为一名一线开发,要如何提前准备,来应对这种变化呢?

对于服务端而言,IDEA的Debugger几乎成为了调试代码的银弹。但是,笔者发现很多人在使用Debugger时,只使用了其中很小一部分功能。
在本文中,笔者将简要介绍一些自己整理的IDEA Debugger中一些鲜为人知,却能够在特定场景提升Debug效率的功能。
注意:本文不会涉及IDEA Debugger的基础操作,例如:
基本的Debug操作,包括但不限于:Step Over, Step Into, Step Out, Run to Cursor, Drop Frame等
基本的断点类型:条件断点、方法断点、线程/全局断点、字段断点、计数断点等
以上操作在各大论坛中均有优秀文章介绍。

▐ 不暂停断点
尽管很多文章已经提到过断点的非挂起功能,但是由于其太好用了,所以本文也单独列出,使用方法如下。
我们在创建断点时,进入断点配置界面后:
取消勾选Suspend,并填写Evaluate and log,此时,断点将会变为黄色。
当程序运行到断点时,代码不会中断执行,而是会直接在Debugger中打印出Evaluate and log中的信息:
▐ 异常断点
普通断点的不足
当代码产生异常时,我们可以通过log看到异常捕获信息,然而,异常的捕获位置很可能和异常真实发生的位置相距甚远。
例如以下代码,ExceptionPoint的process方法调用了innerProcess方法,并在innerProcess方法中会产生运行时异常:


可以发现,log并没有打印出异常的堆栈信息,一旦发生这种情况,尽管我们可以定位到异常是哪里被捕获的,却很难定位到异常是在哪里呗抛出的。
配置异常断点
为了获取异常被抛出的位置,我们可以使用IDEA中的异常断点,配置位置在断点面板的上面:
选择好需要捕获的异常类型后,需要配置断点过滤:Catch class filters

▐ 依赖断点
断点依赖的场景
有时,目标方法可能被多个方法调用,例如以下代码,work()方法同时被warmup和realWork方法调用。
前置条件断点

在目标方法work()中如下位置增加断点依赖:仅当选中断点执行后再启用
完成上述配置后,Debug时,则仅当realWork()的断点被激活后,第二个断点才会被启用。
调用过滤器

同时,对于非静态方法,还可以选择Instance filters和Class filters,原理相同。
▐ 断点后悔药
以下提供三种方法,也分别适用于不同场景。
标准的撤回操作
在如上位置,通过点击Restore Breakpoint,即可撤销删除最近删除的断点
原地复活

一劳永逸的方法

渲染
▐ 修改对象渲染器
使用场景
有时,IDEA自带的变量渲染器并不能满足我们的需要。例如,我们创建一个继承JSONObject的类:

可以看到Debugger将bizObject渲染为了:
可以看到,bizObject中的msg字段直接不见了,这当然不是我们想要的,为了获得真实的变量结果,我们可以手动修改IDEA的渲染方式,以下提供三种方法。
简单修改
直接将Map渲染器修改为toString渲染器即可
创建Class Level Watch


创建自定义渲染器
如果上述方案都不能满足我们花哨的需求,也可以自定义渲染器:在指定的对象上,选择Create Renderer

在渲染器创建页面中,我们可以自定义渲染方式:
当保存后,就可以看到IDEA按照我们想要的方式渲染对应类型变量了:
import org.jetbrains.annotations.Debug.Renderer;@Renderer(text = "name",childrenArray = "courses.toArray()",hasChildren = "courses.isEmpty()")public class Student {private String name;private ArrayList courses;Student(String name, ArrayList courses){this.name=name;this.courses=courses;}}
▐ 修改列表渲染器
当我们创建如下的列表时:


如何让IDEA显示为null的元素呢?方法如下:


定位
▐ 标记
例如,我们创建两个上下文,分别为InputContext和OutputContext,其中都包含user字段。
在一次处理中,代码从inputContex中获取user放到outputContext中


-
在任何debug页面,只要有引用指向这个对象,则会额外标记:
-
在任何线程,任何上下文中,我们都可以引用这个对象。
▐ 引用
在多线程环境下,如果一个对象同时被两个线程执行写操作,很可能会出现线程并发问题,如果我们定位到一个对象可能出现了多线程问题,要如何知道这个对象被哪些线程引用呢?

▐ 异步栈信息
当我们在同步代码中使用线程池来执行异步任务时,这个异步任务的栈和主线程是隔离的,此时,IDEA还可以看到主线程的栈信息么?

通过实践可以发现,虽然是有两层的异步调用,但是IDEA还是打印出了包括主线程在内的所有堆栈信息:

只是每个Stack Frame之间增加了Async stack trace的提示,这是由于IDEA默认开启了Async stack trace,如果不想要看到除当前栈外的信息,可以在此处关掉这一功能:

本文分享自微信公众号 - 大淘宝技术(AlibabaMTT)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。