Java Exception & Error

你没有看错,这篇文章的tags中有人生。又一次开始思考人生,总有Bug想害朕。

今天碰到了一个,算是一个BUG,跑出来是个ERROR,抛出了个Exception。讲道理,这些都是正常的,但是很不讲道理,这个错误报的我望而却步,这个异常更是一头雾水。Just A Fuck For You.

当我拿到这个集群巡检程序的时候,我认为应该是很简单的部署上服务器就可以了,因为这是一个已经在线上运行的包,我只要改改参数在日常环境跑起来就可以了。然而,真正的魔术开始了。日常环境与线上环境居然差异很大,包括巡检的目标集群、结果数据库机器等都要改。这个还算好,虽然我不知道,但是有师兄在搞搞还是比较简单的,然后就上线,运行。

第一个问题就是找不到主类。我懵逼,居然连启动都起不起来。好在还有进一步的报错信息,原来是找不到log的包。但是我在本地可以启动,我一直以为打jar包的时候会打依赖进去,结果是并不会打依赖包。这个是学艺不精,经验不足。于是把本地所有依赖包怼进服务器。这次顺利的启动起来了。

然后就开始报错,几乎所有集群都拒绝访问。这尼玛就很尴尬了,我对整个项目一无所知啊。那就去问一下呗:
“师兄,这个巡检被拒绝访问了,所有集群都访问不到。”
–“有点忙,你自己先看看。”
“我看不懂啊,先给我讲讲这个整体逻辑啊”
–“没空”

然后就开始了一下午的生不如死。哼,回家睡觉!不干了!
第二天来到,我决定再深入看一下代码,应该能从代码中找到问题。作为ACM选手,从来就没有机器DEBUG的习惯,眼爆bug在C++100多行的代码里还是很快的,但是在Java里就有点懵逼了。Java的代码你说长,其实也不长。但就是会让你抓狂,自己看自己写的Java项目那是怎么看怎么喜欢。去看看其他人的Java项目,呵呵。写一个大工程当然就是要功能块分拆,功能隔离,减少代码内耦合,利于修改调整,兼具灵活性与健壮性。所以Java代码的特点就是不断的继承,类间调用,流程拆分……有的时候一个很简单的功能可能要涉及7、8个类和接口,所以看代码,就要有个够大的脑内栈空间。但是,就算难看,也不机器DEBUG,手动DEBUG的基本功还是有的。

但凡报错靠谱点,都没有那么难,痛苦就在于,他报的错误与真正引起错误的地方相差太远,异常却又报的模模糊糊。首先是拒绝连接错误,现在代码里找到所有要访问的集群IP,打出来。然后找师兄去确认,集群是否在用,就这一个工作就前前后后搞了两个多小时,都在忙的不亦乐乎。集群有问题就好办多了,因为这锅就可以甩出去啦,偏偏机器没有问题。既然机器本身没有问题,那就只有代码的问题了。

坑就坑在这次抛出的异常居然没有抛出一场的地点信息。或者说异常信息说明的地点距离异常真正发生的位置也有一段距离。主异常是有连接器客户端抛出的,抛出信息就是链接失败啦。然而依靠其抛出的异常栈只能找到发出链接请求的这个类,再往下就没有栈内信息了。然后就去看调用的函数,结果一进去发现这个类没有抛出异常,而是自己处理掉了。这本应该是非常值得表扬的,因为捕获了异常意味着这个异常是可以被预料并处理的,所以优秀的程序员都会在能处理的情况下都处理掉,如果是一些不好处理的,或需要根据使用者的需求来处理就继续向上抛,抛给函数使用者去处理。很多初级的Java程序员最常见的做法就是捕获这个异常,然后打印出来,交给运维去发现异常再回来改代码。我手里的这个类并没有抛出异常,而是把一场catch下来自己处理掉了。但是他只处理了其中的IO异常,还有一个可抛出异常也被他catch下来了,并且仅仅是打印到了log里,所以我就只能从日志中追踪到这里了。然而由于没有抛出,所以也就没有信息表明这个一场出现在上面的哪个位置,只能手动二分位置查错了。这个的原理很简单,就是发生异常位置以后的代码都不会被执行,所以只要在其中夹杂一些输出语句,就可以定位到出错的那句了。接下来定位到一个新的类中,至于这个类是干什么的我也不清楚,但是可以找bug。而这个函数就完全没有抛出异常也没有捕获异常,所以这个就要对函数里所有代码都做二分定位,而不是像刚才一样只定位try代码块中的代码就可以了。几个过大概5轮定位,又定位到了一个新的类里,通过对新的这个类的定位,可以基本确定异常就来源于这个函数中的某一句。异常信息中有一个是数字格式错误,通过上面的分析,我也基本上确定在这里发生的就是这个格式错误的异常,由于函数参数中只有一个double的参数,就重点找他的问题。先输出了他的值,发现没有问题。然后发现代码中他与另外一个变量做了比较,而定位异常位置也就发生在这个比较代码块中,参与比较的另外一个是从配置文件中提取的数据。经过往回找这个配置文件的参数选项,发现问题竟然是因为拼写错误导致找不到这个配置选项,所以这条语句的值变成了if( double > null ) 然后就有了这个数字格式错误的异常了。

草泥马我的心好累。代码中写的是max_master_clients,然而配置文件中是master_max_clients,真不知道线上的那个代码是怎么跑的,害怕。

异常 Exception

通过上面的故事,你应该已经了解了Exception的一些特性了。下面具体的介绍一下,以及正确用法!

Talk is not cheap.