FindBugs错误分析说明 - 图文 下载本文

Bug: Computation of average could overflow

Pattern id: IM_AVERAGE_COMPUTATION_COULD_OVERFLOW, type: IM, category: STYLE 解释:

参照了Findbugs的解释,(low+high)/2当平均数过大的时候(难道是超过了int最大值?) 会溢出,会出现一个负值,此问题出现在早期实现的二进制搜索和归并排序,但是已经被修

复了。参见Joshua Bloch(google首席java架构师)widely publicized the bug pattern(需翻 墙).

解决方法:

建议使用无符号右移位运算符:use (low+high) >>> 1

22. SC_START_IN_CTOR

Bug: new AsyncCentral() invokes AsyncCentral$FireThread.start() Pattern id: SC_START_IN_CTOR, type: SC, category: MT_CORRECTNESS 解释:

构造方法里重启新的线程,我还是第一次见过这样写的。 首先说明三点:

1. 对象的创建一般分两步走,在堆上new对象操作,执行方法(包含构造方法),为

什么我们开发人员看见的只有一步,那是因为JVM不想让开发人员在这个过程中插上一 脚,破坏对象的初始化流程。

2. 类的加载和初始化是由虚拟机保证同步的,但是对象的生成和初始化就没有任何同步机

制来保证了。

3. 构造器不能加synchronized,是一项程序语言设计上的选择(见:JLS 8.8.3 Constructor

Modifiers),正常情况下,是不需要加上synchronized,但不代表所有的情况都不要加上 synchronized,更不能认为一个构造器隐含的就是一个synchronized。

那什么时候构造方法需要同步呢?通常来说,方法在生成对象的时候只被执行一次, 一般new对象的操作可能因为JVM自身的关系保证原子性操作(自己臆测的,没有任何根

据),所以我们经常不用关心构造方法同步的问题。但是上述情况就不一样了,在构造方法 中新启线程,如果AsyncCentral是一个状态类,FireThread线程极有可能对AsyncCentral的 状态进行反复读取和写入,更严重的一种情况是,AsyncCentral有父类,极有可能在父类的 构造方法还没开始前,FireThread线程就已经开始执行并对AsyncCentral的状态进行“破坏” 了。这个时候,就有两个线程来对AsyncCentral的状态进行操作了(一个是执行方法 的线程,一个是FireThread线程),自然而然,就会存在同步的问题了。

多数时候,我们没有发现,可能是AsyncCentral类没有状态,或者是时候未到,我想说的是, 我们写的大部分程序都存在同步的问题,本例子就是其中一个,值得我们好好思考。

另一种理解(觉得更靠谱,来自于Java.Concurrency.in.Practice)叫做“对象逃逸”,意思就 是说在构造方法里,this是可以访问的到的,同一时间,FireThread线程而是可以访问到this 对象的,所以这时候this就从方法线程逃逸到了FireThread线程中,这时候初始化就 会存在并发问题。 解决方法:

不要再构造方法中新启线程,可以提供init方法,其他方法根据实际情况而定。

23. EQ_SELF_USE_OBJECT

Bug: ManageItem defines equals(ManageItem) method and uses Object.equals(Object) Pattern id: EQ_SELF_USE_OBJECT, type: Eq, category: CORRECTNESS 解释:

这是重载,不是覆盖,除非你能保证其他人调用这个方法传入的参数都是ManageItem 的,

否则会调用Object的boolean equals(Object)方法,这样的话根本就不会跑到这个方法里来!!很多所谓的大牛都会犯这么一个错误,我坚信这是你手滑了。 解决方法:

如果你想覆盖父类的方法,请在上面加上@Override注解,它会防止这种错误的出现(透露 一个小细节,JDK1.5覆盖接口方法时加上@Override编译器会报错,JDK1.6修正,这可能是 当初实现者对@Override注解理解的问题)。

24.DLS_DEAD_LOCAL_STORE

案例二:

Bug: Dead store to date

Pattern id: DLS_DEAD_LOCAL_STORE, type: DLS, category: STYLE 解释:

先看看,我们的程序有多少个这样的例子:

真是伤不起啊,不知道当时的作者这是神马意图?手滑?还是眼花?虽然说这不是神马问题, 也不会对程序性能造成多大的影响,但是这就像一颗沙子,我们每个程序员对待程序都应该 是眼里不能进沙子的态度,当然,你非要这么写,我也没神马可说的。 By the way:

对本地变量定义了之后未使用到,编译器能够做优化处理,也就是在编译之后的class文件 中删除这些本地变量。方法是在eclipse的Preferences里将以下的钩去除:

解决方法:

大胆的去掉或者注释掉。 误报的案例:

上述案例二种:

IntegralItemDO integralItem = new IntegralItemDO();

是一个局部的变量,不需要定义到外部去,定义在外部,可能会变成一个无效的变量。

25.FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER