侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 352 篇文章
  • 累计创建 135 个标签
  • 累计收到 10 条评论

目 录CONTENT

文章目录

IDEA检查bug插件 FindBugs 的安装配置与使用

孔子说JAVA
2022-11-05 / 0 评论 / 0 点赞 / 245 阅读 / 8,136 字 / 正在检测是否收录...
广告 广告

FindBugs 插件是Java的缺陷检测工具,可以提供静态字节代码分析,以便从IntelliJ IDEA中查找Java代码中的错误。FindBugs 使用静态分析可以识别数百种严重缺陷(查找200多种错误模式),例如空指针取消引用,无限递归循环,对Java库的错误使用和死锁等。据统计在大型应用程序中通常每1000-2000行非注释源语句中大约有1个缺陷。

1、FindBugs-IDEA 和 QAPlug-FindBugs 插件

常用的 FindBugs 插件有2种,分别为 FindBugs-IDEA 和 QAPlug-FindBugs。

1.1 FindBugs-IDEA

FindBugs 是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题。有了静态分析工具,就可以在不实际运行程序的情况对软件进行分析。

  • FindBugs 用来查找Java代码中的程序错误,它使用静态分析来识别Java程序中上百种不同类型的潜在错误。潜在错误可分为四个等级:恐怖的、吓人的、令人困扰的和值得关注的,这是根据其可能产生的影响或严重程度,而对开发者的提示。

Find-Sec-Bugs 是扫描插件 FindBugs 的 Java 安全漏洞规则扩展库,它支持在多种主流 IDE 环境进行安装:Eclipse, IntelliJ, Android Studio 和 NetBeans。只扫描 Java 代码,支持主流的 Java 开发框架,比如 Spring-MVC, Struts 等。通过扫描源代码,能够发现131种(version 1.9.0)不同的安全漏洞类型。

注意:idea2020版本后就不支持 FindBugs-IDEA 插件了。

image-1667352785664

1.2 QAPlug-FindBugs

在IDEA中搜索会发现有四种QAPlug,包含了PMD、FindBugs、CheckStyle和QAPlug。QAPlug 是一个 Intellij IDEA 插件,用于管理代码质量,它集成了 PMD、Checkstyle 和 Findbugs 等工具。

1.2.1 QAPlug-FindBugs

是一个静态分析工具,基于 bug patterns 缺陷模式概念,将字节码与一组缺陷模式进行对比以发现可能的问题。

  • 查找字节码文件中的潜在bug。只寻找可能存在bug的地方,不注重样式或者格式,它试图只寻找真正的缺陷或者潜在的性能问题。主要包括:
    • 空指针;
    • 没有合理关闭资源;
    • 字符串相等判断错(用了==而没用equals)等。

1.2.2 QAPlug-CheckStyle

代码样式风格检查,专门check代码规范风格的,比如缩进,换行操作等。

  • 检查源文件是否与代码编程规范相符。主要包括:

    • Javadoc注释;
    • 命令规范;
    • 多余没用的imports;
    • 长度度量,如过长的方法;
    • 必要空格的缺失;
    • 重复代码等;
  • 大项目往往是有很多人一起完成的,然而每个人都有自己的style,导致整个项目的代码不仅存在不符合语言规范的情况,而且读起来非常困难。因此,这样的项目中都会引入Checkstyle 来规范大家的编码风格,尽量做到统一和合理。

1.2.3 QAPlug-PMD

检查源文件中的潜在问题。主要包括:

  • 空的try/catch/finally/switch语句块;
  • 程序中定义而未使用的变量、private方法;
  • 空的if/while语句;
  • 过于复杂的表达式,如不必要的if语句等;
  • 复杂类;
  • 不必要的对象创建等;

1.2.4 QAPlug

这个插件集成了 PMD、Checkstyle 和 Findbugs 工具,1键运行3个插件并同时汇总整合,非常方便,需要注意的是若只安装QAPlug,会提示错误消息,请至少安装一个QAPlug子模块,你可以先安装FindBugs子模块后再安装QAPlug。

2、安装方式

2.1 在线安装方式

第一种方式,是在IDEA上搜索插件进行安装,会适配当前IDEA的版本。打开File -> Settings 界面,在左侧列表中找到 Plugins 菜单,在右侧的 Marketplace 页签下,搜索 “findbugs”,可以找到对应的插件,如下图所示,点击 Install 进行安装即可。

  • 可以看到,在idea中只搜索到了 QAPlug-FindBugs 插件,所以如果我们想要安装 FindBugs-IDEA 插件,可以使用离线方式安装。
  • 注意:若只安装QAPlug,会提示错误消息,请至少安装一个QAPlug子模块,你可以先安装FindBugs子模块进行使用。

image-1667348062385

2.2 离线安装方式

第二种安装方式是使用离线插件进行安装。插件下载页面:https://plugins.jetbrains.com/idea ,在搜索框中输入插件名称 findbugs 搜索,点击出现的下拉提示或搜索按钮,即可进入插件下载页面,选择对应安装版本下载即可。

image-1667348714127

可以看到在官网上可以搜索到 FindBugs-IDEA 和 QAPlug-FindBugs 两种插件,选择我们需要的下载即可。

1)FindBugs-IDEA下载安装

通过前述搜索结果进入下载下面,或直接点击下面的连接进入下载。

image-1667348655570

下载完成后,进入插件市场,选择本地安装

同样是在 Settings 界面,在左侧列表中找到 Plugins 菜单,在右侧的 Installed 页签右方有个齿轮图标,点击展开菜单后选择 “Install Plugin from Disk…”,此时会打开本地文件选择框,选择你下载的插件包 FindBugs-IDEA-1.0.1.zip 安装即可。

image-1667349028517

image-1667350694410

安装完成后重启IDEA,会发现左下角会出现 FindBugs-IDEA 的图标。

find-sec-bugs安全规则组件的应用

Find-Sec-Bugs 是扫描插件 FindBugs 的 Java 安全漏洞规则扩展库,可选择使用。

File->Setting->FindBugs-IDEA->plugins的±>选择4,选择组件的路径,导入

image-1667353000519

导入完成效果图:

image-1667353012800

至此需要导入的步骤均已完成,可以进行代码走查操作了。

2)QAPlug-FindBugs下载安装

通过前述搜索结果进入下载下面,或直接点击下面的连接进入下载。

image-1667350227985

下载完成后,进入插件市场,选择本地安装

同样是在 Settings 界面,在左侧列表中找到 Plugins 菜单,在右侧的 Installed 页签右方有个齿轮图标,点击展开菜单后选择 “Install Plugin from Disk…”,此时会打开本地文件选择框,选择你下载的插件包安装即可。安装完成后重启IDEA。

3、插件使用

3.1 FindBugs-IDEA 使用方式

FindBugs-IDEA 插件可以分析单个文件,一个包下面的所有文件,整个module下的文件,整个project下的文件,鼠标右键想要分析的文件名/包名/module名/project。

分析选中的文件

image-1667351207447

结果显示:

image-1667351257875

除了分析单个文件之外,还可以分析整个项目,module等。

image-1667351286810

  • Analyze Selected File(s)————分析单个文件
  • Analyze Package(s) Files————分析包下文件
  • Analyze Module Files————分析整个module
  • Analyze Project Files————分析整个工程
  • Analyze Scope Files————分析某个范围的文件

项目代码分析详情

下图中左下方红框代表安装完成,左侧中间红框代表运行,右测上方显示项目代码分析详情。

image-1667351536628

  • Bad pratice: 编程的坏习惯,主要是命名问题,比如类名最好以大写开头,字符串不要使用等号不等号进行比较,可能会有异常最好用try-catch包裹的代码,方法有返回值但被忽略等等,这些如果不想改可以直接忽略。

  • Malicious code vulnerability: 恶意代码漏洞,主要是一些属性直接使用public让别的类来获取,建议改为private并为其提供get/set方法。还有一些public的静态字段,可能会被别的包获取之类的。这些也需要根据项目具体情况来,个人意见,在有的不重要类,有时直接公开使用属性,可能更为便捷。如果你认为这些不需要修改,完全可以忽略。

  • Dodgy code: 糟糕的代码,比如一个double/float被强制转换成int/long可能会导致精度损失,一些接近零的浮点数会被直接截断,事实上我们应该保留。在类型转换的时候,我们应该为类型转换提供一个安全的转换方法。比如使用switch的时候没有提供default。多余的空检查,就是不可能为空的值,增加了不为空判断,这是没有必要的。属于代码冗余不安全的类型转换等等。

  • performance: 性能,主要是一些无用的代码,比如声明了没有用到的属性等等。

  • correctness: 代码的正确性,主要是没有对变量进行不为空判定,在特殊情况可能发生空指针异常。

3.2 QAPlug-FindBugs 使用方式

选择项目,点击Analyze,再点击Analyze Code。

image-1667351887112

选中整个项目:

image-1667351929999

运行后可看到左下角多了一个“Analysis”的工具标识,点击可看到历史的分析记录:

image-1667351946445

项目代码分析详情

  • Efficiency: 效能。主要从 “Performance” 性能角度给出指导意见。
  • Maintainability: 可维护性。主要从 “Bad practice” 不良实践角度给出指导意见。
  • Reliability: 可靠性。从 “Correctness” 正确性、“Malicious code vulnerability” 恶意代码漏洞等角度给出指导意见。
  • Usability: 可用性。主要从 “Dodgy” 狡猾的角度给出指导意见。

检测之后的提示实例

左侧显示结果以及对应类的所在位置,右侧显示详细的问题描述。

image-1667352141007

4、常见的错误信息

4.1 Bad practice 代码坏习惯

错误信息 说明
Class names should start with an upper case letter 主要包括类名的命名,以大写字母开头
Method names should start with a lower case letter 方法名以小写字母开头
Field names should start with a lower case letter 字段名以小写字母开头
equals()method does not check for null argument equals()方法应该检查非空
Class defines equals() and uses Object.hashCode() 一个类重写了equals方法,但没有重写hashCode方法,使用了Object对象的hashCode方法
Method ignores exceptional return value 方法忽略返回值的异常信息
Equals method should not assume anything about the type of its argument equals(Object o)方法不能对参数o的类型做任何的假设。比较此对象与指定的对象,当且仅当该参数不为 null,并且是表示与此对象相同的类型的对象时,结果才为 true。
Comparison of String objects using == or != 用==或者!=去比较String类型的对象
Method might ignore exception 方法可能忽略异常
Method invokes System.exit() 在方法中调用System.exit(…)语句,考虑用RuntimeException来代替
Method ignores result of InputStream.read() InputStream.read 方法忽略返回的多个字符,如果对结果没有检查就没法正确处理用户读取少量字符请求的情况

4.2 Dodgy code 糟糕的代码

错误信息 说明
Switch statement found where default case is missing Switch没有默认情况下执行的case语句
Switch statement found where one case falls through to the next case Switch语句中一个分支执行后又执行了下一个分支。通常case后面要跟break 或者return语句来跳出
Dead store to local variable 该指令为局部变量赋值,但在其后的没有对它做任何使用。
Write to static field from instance method 在实例方法写入静态字段
Redundant nullcheck of value known to be non-null 方法中对不为空的值进行为空的判断
Method uses the same code for two branches 此方法使用相同的代码,以实现两个有条件的分支。检查以确保这是不是一个编码错误
Exception is caught when Exception is not thrown 在try/catch块中捕获异常,但是异常没有在try语句中抛出而RuntimeException又没有明确的被捕获
Integral division result cast to double or float 整形数除法强制转换为double或者float类型
Possible null pointer dereference due to return value of called method 方法的返回值没有进行是否为空的检查就重新赋值,这样可能会出现空指针异常
Useless object created 对象创建了,但并没有使用
Unread public/protected field 没有用到的字段

4.3 Internationalization 代码国际化相关

错误信息 说明
Consider using Locale parameterized version of invoked method 使用平台默认的编码格式对字符串进行大小写转换,这可能导致国际字符的转换不当。使用以下方式对字符进行转换

4.4 Performance 代码性能相关

错误信息 说明
Boxing/unboxing to parse a primitive 类型转换,比如字符串转换成int,应该使用 Integer.parseInt(“”) 代替 Integer.valueOf(“”)
Method concatenates string using + in aloop 每次循环里的字符串+连接,都会新产生一个string对象,在java中,新建一个对象的代价是很昂贵的,特别是在循环语句中,效率较低。解决办法:使用StringBuffer或者StringBuilder重用对象
Private method is never called 私有方法没有被调用
Explicit garbage collection;extremely dubious except in benchmarking code 在代码中显式的调用垃圾回收方法,这样做并不能起作用。关闭操作或者finalize方法中调用垃圾回收方法会导致很多的性能浪费,这样大规模回收对象时会造成处理器运行缓慢。
Unread field:should this field be static? 没有用到的static 字段
should be a static inner class 此内部类应该使用static修饰

4.5 Experimental 可能的错误

错误信息 说明
Method may fail to clean up stream or resource on checked exception 这种方法可能无法清除(关闭,处置)一个流,数据库对象,或其他资源需要一个明确的清理行动,解决方法:流的关闭都写在finally里面

4.6 Malicious code vulnerability 恶意破坏代码相关

错误信息 说明
May expose internal representation by incorporating reference to mutable object 此代码把外部可变对象引用存储到对象的内部表示。如果实例受到不信任的代码的访问和没有检查变化,将危及对象和重要属性的安全。解决方式:存储一个对象的副本,在很多情况下是更好的办法。
Field isn’t final but should be 此字段前应该加final
Field isn’t final and can’t be protected from malicious code 一个静态字段是可以被恶意代码或其他的包访问修改。可以把这种类型的字段声明为final类型的以防止这种错误
Field should be package protected 此字段前应该加protected

4.7 Multithreaded correctness 多线程代码正确性相关

错误信息 说明
Static DateFormat DateFormat 在多线程中本身就是不安全的,如果在线程范围中共享一个DateFormat的实例,而不使用一个同步的方法在应用中就会出现一些奇怪的行为
Call to static DateFormat DateFormats 多线程使用本就是不安全的,改进方法:需要创建多实例或线程同步

4.8 Correctness 代码正确性相关

错误信息 说明
Nullcheck of value previously dereferenced 此代码之前没有进行null值检查,解决办法:进行null检查
Possible null pointer dereference 可能为null
Null pointer dereference 对象赋为null值后,没有被重新赋值
Possible null pointer dereference in method on exception path 在异常null值处理分支调用的方法上,可能存在对象去除引用操作
value is null and guaranteed to be dereferenced on exception path exception 分支上,存在引用一个null对象的方法,引发空指针异常
Self comparison of value with itself 方法中对一个局部变量自身进行比较运算,并可说明错误或逻辑错误。请确保您是比较正确的事情
An apparent infinite recursive loop 明显的无限迭代循环,将导致堆栈溢出

5、安装错误解决方案

5.1 make错误

引入插件QAPlug - FindBugs后,make的时候经常会报这个错误:

Malformed argument has embedded quote: -Djava.endorsed.dirs=\"\"

解决方案一:

  1. 找到idea的安装目录 -> …\JetBrains\IntelliJ IDEA版本号\bin\idea64.exe.vmoptions
  2. 将下面的配置加到文件末尾
-Djdk.lang.Process.allowAmbiguousCommands=true

重启IDEA,再次扫描的时候就可以了。findBugs的问题解决了,但是引入了其他问题,每次 Open In -> Explorer 的时候都无法正确打开文件所在目录。

image-1667353597769

解决方案二:

如果对Open In -> Explorer使用频率比较高的朋友,可以考虑另外一种比较笨拙的方法。

  1. 去掉复选框Other Settings -> QAPlug -> FindBugs -> Make before analysis

image-1667353682926

  1. 每次findBugs之前先手动编译
0

评论区