Findbugs安装使用说明
Findbugs安装使用说明
1用途
1. FindBugs 是一个java bytecode静态分析工具,它可以帮助java工程师提高代码质量以及排除隐含的缺陷。
例如:未关闭的数据库连接,缺少必要的null check,多余的 null check,多余的if后置条件,相同的条件分支,重复的代码块,错误的使用了"==",建议使用StringBuffer代替字符串连加等等。而且我们还可以自己配置检查规则(做哪些检查,不做哪些检查),也可以自己来实现独有的校验规则(用户自定义特定的bug模式需要继承它的接口,编写自己的校验类,属于高级技巧)。
2. FindBugs检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题。Findbugs自带检测器,其中有60余种Bad practice,80余种Correctness,1种 Internationalization,12种Malicious code vulnerability,27种Multithreaded correctness,23种Performance,43种Dodgy。
2 安装
1. 解压缩 findbugs.zip到 eclipse下的dropins目录
2、重启eclipse,选中项目,右键会出现一个Find Bugs菜单。至此,findbugs插件安装完毕。
然后在Package Explorer或Navigator视图中,选中你的Java项目,点击右键,可以看到“Find Bugs”菜单项,子菜单项里有“Find Bugs”和“Clear Bug Markers”两项内容。
3 使用
启动
选中java工程,点击鼠标右键,选择名为“Find Bugs”的菜单,点击FindBugs,开始运行,问题指示器将指向根据bug模式识别出来的潜在问题代码位置。
我们点中“Find Bugs”,运行结束后可以在Problems中看到增加了如下的警告信息内容。
也可以添加findbugs的视图,里面有错误详细分类
FindBugs运行后的警告信息内容不仅在Problems视图中显示,而且将标记在源代码标记框中,在源代码编辑器中我们可以看到警告标识, 当光标指向你的警告信息的代码上面时,就会有相应的错误提示信息,与Eclipse本身的错误或警告信息提示类似。
选中Problems视图里出现的相应问题,就会在代码编辑器里切换到相应的代码上去,方便根据相应的提示信息进行代码的修改。
在Problems视图里,选中相应的问题条目,右键,在弹出的菜单中,可以看到“Show Bug info”。
点中它,会切换到Bug Details视图上去,显示更加详细的提示信息。当然,在代码编辑窗口中,点击带有警告提示信息的图标时,也会自动切换到Bug Details窗口去,查看详细的警告信息。
可选项定制
你还可以通过java工程的属性对话框来定制findbugs的运行方式,选择你的项目,右键点击 Properties,可选项包括:
a. 控制"Run FindBugs Automatically" 开关的checkbox。 选中时, FindBugs 将在每次修改java类后启动运行。
b.选择最小告警优先级和Bug类别。这些选项将选择哪些警告被显示。例如,如果你选择"Medium",只有Medium 和 High priority 警告将被显示。近似地,如果你未选中 "Style" checkbox,Style类的警告信息将不会被显示。
c.选择探测器。这个列表允许你选择你想在工程中使用的探测器。
4 配套的Bug模式解释
为了有针对性的使用这个工具,减少bug的误报,提高使用效率,我们选择了10个左右的bug模式,下面就是对这10个模式的解释。
这些bug可能会引起程序的性能或逻辑问题.
需要说明的是,findbugs能检测的bug pattern远不仅于此,甚至可以定制自己的探测器,因此,这个文档会不断扩充,同时,也欢迎大家不断探索和分享使用实践.
4.1 ES_COMPARING_PARAMETER_STRING_WITH_EQ
ES: Comparison of String parameter using == or != (ES_COMPARING_PARAMETER_STRING_WITH_EQ)
This code compares a java.lang.String parameter for reference equality using the == or != operators. Requiring callers to pass only String constants or interned strings to a method is unnecessarily fragile, and rarely leads to measurable performance gains. Consider using the equals(Object) method instead.
使用 == 或者 != 来比较字符串或interned字符串,不会获得显著的性能提升,同时并不可靠,请考虑使用equals()方法。
4.2 HE_EQUALS_NO_HASHCODE
HE: Class defines equals() but not hashCode() (HE_EQUALS_NO_HASHCODE)
This class overrides equals(Object), but does not override hashCode(). Therefore, the class may violate the invariant that equal objects must have equal hashcodes.
类定义了equals()方法但没有重写hashCode()方法,这样违背了相同对象必须具有相同的hashcodes的原则
4.3 IT_NO_SUCH_ELEMENT
It: Iterator next() method can't throw NoSuchElement exception (IT_NO_SUCH_ELEMENT)
This class implements the java.util.Iterator interface. However, its next() method is not capable of throwing java.util.NoSuchElementException. The next() method should be changed so it throws NoSuchElementException if is called when there are no more elements to return.
迭代器Iterator无法抛出NoSuchElement异常,类实现了java.util.Iterator接口,但是next()方法无法抛出java.util.NoSuchElementException异常,因此,next()方法应该做如此修改,当被调用时,如果没有element返回,则抛出NoSuchElementException异常
4.4 J2EE_STORE_OF_NON_SERIALIZABLE_OBJECT_INTO_SESSION
J2EE: Store of non serializable object into HttpSession (J2EE_STORE_OF_NON_SERIALIZABLE_OBJECT_INTO_SESSION)
This code seems to be storing a non-serializable object into an HttpSession. If this session is passivated or migrated, an error will result.
将没有实现serializable的对象放到HttpSession中,当这个session被钝化和迁移时,将会产生错误,建议放到HttpSession中的对象都实现serializable接口。
4.5 ODR_OPEN_DATABASE_RESOURCE
ODR: Method may fail to close database resource (ODR_OPEN_DATABASE_RESOURCE)
The method creates a database resource (such as a database connection or row set), does not assign it to any fields, pass it to other methods, or return it, and does not appear to close the object on all paths out of the method. Failure to close database resources on all paths out of a method may result in poor performance, and could cause the application to have problems communicating with the database.
方法可能未关闭数据库资源,未关闭数据库资源将会导致性能变差,还可能引起应用与服务器间的通讯问题。
4.6 OS_OPEN_STREAM
OS: Method may fail to close stream (OS_OPEN_STREAM)
The method creates an IO stream object, does not assign it to any fields, pass it to other methods that might close it, or return it, and does not appear to close the stream on all paths out of the method. This may result in a file descriptor leak. It is generally a good idea to use a finally block to ensure that streams are closed.
方法可能未关闭stream,方法产生了一个IO流,却未关闭,将会导致文件描绘符的泄漏,建议使用finally block来确保io stream被关闭。
4.7 DMI_CALLING_NEXT_FROM_HASNEXT
DMI: hasNext method invokes next (DMI_CALLING_NEXT_FROM_HASNEXT)
The hasNext() method invokes the next() method. This is almost certainly wrong, since the hasNext() method is not supposed to change the state of the iterator, and the next method is supposed to change the state of the iterator.
4.8 IL_INFINITE_LOOP
IL: An apparent infinite loop (IL_INFINITE_LOOP)
This loop doesn't seem to have a way to terminate (other than by perhaps throwing an exception).
明显的无限循环.
4.9 IL_INFINITE_RECURSIVE_LOOP
IL: An apparent infinite recursive loop (IL_INFINITE_RECURSIVE_LOOP)
This method unconditionally invokes itself. This would seem to indicate an infinite recursive loop that will result in a stack overflow.
明显的无限迭代循环,将导致堆栈溢出.
4.10 WMI_WRONG_MAP_ITERATOR
WMI: Inefficient use of keySet iterator instead of entrySet iterator (WMI_WRONG_MAP_ITERATOR)
This method accesses the value of a Map entry, using a key that was retrieved from a keySet iterator. It is more efficient to use an iterator on the entrySet of the map, to avoid the Map.get(key) lookup.
使用了keySet iterator和Map.get(key)来获取Map值,这种方式效率低,建议使用entrySet的iterator效率更高.
4.11 IM_BAD_CHECK_FOR_ODD
IM: Check for oddness that won't work for negative numbers (IM_BAD_CHECK_FOR_ODD)
The code uses x % 2 == 1 to check to see if a value is odd, but this won't work for negative numbers (e.g., (-5) % 2 == -1). If this code is intending to check for oddness, consider using x & 1 == 1, or x % 2 != 0.
奇偶检测逻辑,未考虑负数情况.
5 eclipse自带告警工具
在包管理器界面
带有感叹号的包和类 就是含有告警
在问题视图也可以看到所有的告警
双击就能看到具体错误的地方,使用和findbugs类似
6安卓自带告警工具
点击运行后会自动弹出
双击就能看到具体错误的地方,使用和findbugs类似
7附录
Bad practice 坏的实践
一些不好的实践,下面列举几个:
HE : 类定义了equals() ,却没有hashCode() ;或类定义了equals() ,却使用Object.hashCode() ;或类定义了hashCode() ,却没有equals() ;或类定义了hashCode() ,却使用Object.equals() ;类继承了equals() ,却使用Object.hashCode() 。
SQL : Statement 的execute 方法调用了非常量的字符串;或Prepared Statement 是由一个非常量的字符串产生。
DE : 方法终止或不处理异常,一般情况下,异常应该被处理或报告,或被方法抛出。
Correctness 一般的正确性问题
可能导致错误的代码,下面列举几个:
NP : 空指针被引用;在方法的异常路径里,空指针被引用;方法没有检查参数是否null ;null 值产生并被引用;null 值产生并在方法的异常路径被引用;传给方法一个声明为@NonNull 的null 参数;方法的返回值声明为@NonNull 实际是null 。
Nm : 类定义了hashcode() 方法,但实际上并未覆盖父类Object 的hashCode() ;类定义了tostring() 方法,但实际上并未覆盖父类Object 的toString() ;很明显的方法和构造器混淆;方法名容易混淆。
SQL : 方法尝试访问一个Prepared Statement 的0 索引;方法尝试访问一个ResultSet 的0 索引。
UwF : 所有的write 都把属性置成null ,这样所有的读取都是null ,这样这个属性是否有必要存在;或属性从没有被write 。
Internationalization 国际化
当对字符串使用upper 或lowercase 方法,如果是国际的字符串,可能会不恰当的转换。
Malicious code vulnerability 可能受到的恶意攻击
如果代码公开,可能受到恶意攻击的代码,下面列举几个:
FI : 一个类的finalize() 应该是protected ,而不是public 的。
MS : 属性是可变的数组;属性是可变的Hashtable ;属性应该是package protected 的。
Multithreaded correctness 多线程的正确性
多线程编程时,可能导致错误的代码,下面列举几个:
ESync : 空的同步块,很难被正确使用。
MWN : 错误使用notify() ,可能导致IllegalMonitorStateException 异常;或错误的
使用wait() 。
No : 使用notify() 而不是notifyAll() ,只是唤醒一个线程而不是所有等待的线程。
SC : 构造器调用了Thread.start() ,当该类被继承可能会导致错误。
Performance 性能问题
可能导致性能不佳的代码,下面列举几个:
DM : 方法调用了低效的Boolean 的构造器,而应该用Boolean.valueOf( …) ;用类似
Integer.toString(1) 代替new Integer(1).toString() ;方法调用了低效的float 的构造器,应该用静态的valueOf 方法。
SIC : 如果一个内部类想在更广泛的地方被引用,它应该声明为static 。
SS : 如果一个实例属性不被读取,考虑声明为static 。
UrF : 如果一个属性从没有被read ,考虑从类中去掉。
UuF : 如果一个属性从没有被使用,考虑从类中去掉。
Dodgy 危险的
具有潜在危险的代码,可能运行期产生错误,下面列举几个:
CI : 类声明为final 但声明了protected 的属性。
DLS : 对一个本地变量赋值,但却没有读取该本地变量;本地变量赋值成null ,却没有读取该本地变量。
ICAST : 整型数字相乘结果转化为长整型数字,应该将整型先转化为长整型数字再相乘。
INT : 没必要的整型数字比较,如X <= Integer.MAX_VALUE 。
NP : 对readline() 的直接引用,而没有判断是否null ;对方法调用的直接引用,而方法可能返回null 。
REC : 直接捕获Exception ,而实际上可能是RuntimeException 。
ST: 从实例方法里直接修改类变量,即static属性。