一、前言
目前已验证缺陷检查规则24条。其中不良习惯(Bad practice)14条,正确性(Correctness)3条,
糟糕的代码(Dodgy code)3条,性能(Performance)1条,安全(Security)2条,多线程的正确(Multithreaded correctness)1条;
其中ODR_OPEN_DATABASE_RESOURCE_EXCEPTION_PATH、
OS_OPEN_STREAM_EXCEPTION_PATH、DE_MIGHT_IGNORE这三个检查点存在缺陷,代码进行变更修改后检查点无法检测到错误异常。其余可正常进行逻辑检查。
二、缺陷集合
1、CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE
1.1 缺陷说明
这个检测器会检查编写的可克隆类是否违反惯用语法。类定义了clone()方法,但是没有实现Cloneable接口。
如果不继承自Cloneable接口,当调用clone()时会抛出CloneNotSupportedException异常。
1.2 代码示例
public class CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE{
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
1.3 解决方式
public class CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE_U implements Cloneable{
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
2、DMI_RANDOM_USED_ONLY_ONCE
2.1 缺陷说明
代码中调用无意义方法的地方;由于java.util.Random是一个伪随机函数,如果传入的参数相同的话,
返回的随机数就是相同的。因此没必要每次都new一个新的random出来计算随机数,建议使用
java.security.SecureRandom,该类继承自Random,是一个强随机数生成器。
2.2 代码示例
public class DMI_RANDOM_USED_ONLY_ONCE{
public static int getRandom(int seed){
return new Random(seed).nextInt();
}
}
2.3 解决方式
public class DMI_RANDOM_USED_ONLY_ONCE_U{
public static int getRandom(int seed){
SecureRandom SR = new SecureRandom();
return SR.nextInt();
}
}
3、DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION
3.1 缺陷说明
建议不要使用 collection.removeAll(collection)方法来删除 collection中的所有元素,而使用
collection.clear()。removeAll是比较参数中的collection和要移除元素的collection中是否有交集,
然后将交集元素删除;clear()是直接将collenction中的元素删除,后者要比前者高效。
3.2 代码示例
public class DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION {
public void collClear(){
List list = new ArrayList<>();
list.add(ddd);
list.removeAll(list);
}
}
3.3 解决方式
public class DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION_U{
public void collClear(){
Collection coll = new ArrayList();
coll.clear();
}
}
4、ICAST_INTEGER_MULTIPLY_CAST_TO_LONG
4.1 缺陷说明
将整数乘法运算的结果转换为long型,结果可能会因为超出整形的范围而出错。
4.2 代码示例
public class ICAST_INTEGER_MULTIPLY_CAST_TO_LONG{
static final long MILLISECONDS_PER_DAY = 24L * 3600 * 1000;
long convertDaysToMilliseconds(int days){
return 1000 * 3600 * 24 * days;
}
}
4.3 解决方式
public class ICAST_INTEGER_MULTIPLY_CAST_TO_LONG_U{
static final long MILLISECONDS_PER_DAY = 24L * 3600 * 1000;
long convertDaysToMilliseconds(int days){
return 1000L * 3600 * 24 * days;
}
}
5、ODR_OPEN_DATABASE_RESOURCE
5.1 缺陷说明
这个检测器会找出退出方法时没有及时关闭的I/O流对象。方法未能成功关闭数据库资源。
5.2 代码示例
public void exec(){
try {
Class.forName(oracle.jdbc.driver.OracleDriver);
Connection conn = DriverManager.getConnection(Config.par.get(url),Config.par.get(userName),Config.par.get(passWord));
conn.clearWarnings();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
5.3 解决方式
public void exec() throws SQLException{
Connection conn = null;
try {
Class.forName(oracle.jdbc.driver.OracleDriver);
conn = DriverManager.getConnection(Config.par.get(url), Config.par.get(userName),Config.par.get(passWord));
conn.clearWarnings();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
6、OS_OPEN_STREAM
6.1 缺陷说明
这个检测器会找出退出方法时没有及时关闭的I/O流对象。方法未能成功关闭流。
6.2 代码示例
public static void exec(String path){
try {
File f = new File(path);
FileWriter fw = new FileWriter(f);
fw.write(xxxxx);
fw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
6.3 解决方式
public static void exec(String path) throws IOException{
FileWriter fw = null;
try {
File f = new File(path);
fw = new FileWriter(f);
fw.write(xxxxx);
fw.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(fw!=null) fw.close();
}
}
7、RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN
7.1 缺陷说明
使用== 或者 !=操作符来比较两个Boolean类型的对象,可能会产生错误,建议使用equals方法。
(如下所示,缺陷实例方法返回值为false,解决实例返回值为true)
7.2 代码示例
public boolean exec() {
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean(true);
return b1==b2;
}
7.3 解决方式
public boolean exec() {
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean(true);
return b1.equals(b2);
}
8、RV_RETURN_VALUE_IGNORED
8.1 缺陷说明
这个检测器会找出代码中调用带有返回值的方法,但是可疑地忽略掉方法返回值的地方。
8.2 代码示例
public static String getHeaderField(String name) {
return “”;
}
public String exec() {
String dateString = getHeaderField();
dateString.trim();
return dateString;
}
8.3 解决方式
public static String getHeaderField(String name) {
return "";
}
public String exec() {
String dateString = getHeaderField();
dateString = dateString.trim();
return dateString;
}
9、ODR_OPEN_DATABASE_RESOURCE_EXCEPTION_PATH
9.1 缺陷说明
这个检测器会找出退出方法时没有及时关闭的I/O流对象。异常发生时,方法未能成功关闭数据库资源。
【未对数据库连接资源进行关闭操作,检查点无法检查到异常点】
9.2 代码示例
public void exec(){
try {
Class.forName(oracle.jdbc.driver.OracleDriver);
String url = jdbc:oracle:thin:@127.0.0.1:1521:ORCL;
Connection conn = DriverManager.getConnection(url, Config.par.get(userName),Config.par.get(passWord));
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
9.3 解决方式
public void exec() throws SQLException{
Connection conn = null;
try {
Class.forName(oracle.jdbc.driver.OracleDriver);
String url = jdbc:oracle:thin:@127.0.0.1:1521:ORCL;
conn = DriverManager.getConnection(url, Config.par.get(userName),Config.par.get(passWord));
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
if(conn!=null) conn.close();
}
}
10、OS_OPEN_STREAM_EXCEPTION_PATH
10.1 缺陷说明
这个检测器会找出退出方法时没有及时关闭的I/O流对象。异常发生时,方法未能成功关闭流。
【未对文件流进行关闭操作,检查点未能检测到异常】
10.2 代码示例
public void readFileByBytes(String path){
try {
File f = new File(path);
FileWriter fw = new FileWriter(f);
fw.write(xxxxx);
fw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
10.3 解决方式
public void readFileByBytes(String path) throws IOException{
FileWriter fw = null;
try {
File f = new File(path);
fw = new FileWriter(f);
fw.write(xxxxx);
fw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fw!=null)fw.close();
}
}
11、DMI_HARDCODED_ABSOLUTE_FILENAME
11.1 缺陷说明
代码含有指向一个绝对路径名的硬编码引用。
11.2 代码示例
public void exec(){
File file = new File(c:\\a.txt);
if(file.exists()){
}
}
11.3 解决方式
public void exec() {
String path = ABSOLUTE_FILENAME_U.class.getResource().getPath();
File file = new File(path+/home/testdir);
if(file.exists()){
}
}
12、DMI_CONSTANT_DB_PASSWORD
12.1 缺陷说明
数据库密码的硬编码常量,代码中创建DB的密码时采用了写死的密码。
12.2 代码示例
public void exec() throws SQLException {
Connection conn = null;
try {
Class.forName(oracle.jdbc.driver.OracleDriver);
String url = jdbc:oracle:thin:@127.0.0.1:1521:ORCL;
String UserName = "admin";
String Password = "123456";
conn = DriverManager.getConnection(url, UserName, Password);
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (conn != null)
conn.close();
}
}
12.3 解决方式
public void exec() throws SQLException {
Connection conn = null;
try {
Class.forName(oracle.jdbc.driver.OracleDriver);
String url = jdbc:oracle:thin:@127.0.0.1:1521:ORCL;
String UserName = "admin";
String Password = Config.par.get(passWord);
conn = DriverManager.getConnection(url, UserName, Password);
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (conn != null)
conn.close();
}
}
13、SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE
13.1 缺陷说明
这个检测器会通过数据流分析检查执行SQL语句的方法调用,
找出那些没有使用常量字符串作为实参的方法调用。
13.2 代码示例
public void exec() throws SQLException{
Connection conn = null;
ResultSet res = null;
Statement state = null;
String username = admin;
try {
conn = DriverManager.getConnection(Config.par.get(url),Config.par.get(userName),Config.par.get(passWord));
state = conn.createStatement();
res = state.executeQuery(select * from t_user t where t.username=' + username+');
} catch (SQLException e) {
e.printStackTrace();
}finally{
if(state!=null)
state.close();
if(res!=null)
res.close();
if(conn!=null)
conn.close();
}
}
13.3 解决方式
public void exec() throws SQLException{
Connection conn = null;
ResultSet res = null;
Statement state = null;
try {
conn = DriverManager.getConnection(Config.par.get(url),Config.par.get(userName),Config.par.get(passWord));
if(conn!=null){
String sql = select * from t_user t where t.username=?;
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(0, sss);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
if(state!=null)
state.close();
if(res!=null)
res.close();
if(conn!=null)
conn.close();
}
}
14、SBSC_USE_STRINGBUFFER_CONCATENATION
14.1 缺陷说明
这个检测器会找出在循环中使用“+”运算符拼接字符串的地方。每次循环里的字符串+连接,
都会新产生一个string对象,效率较低,建议利用StringBuffer或者StringBuilder重用对象
14.2 代码示例
public String exec() {
String str = "abc";
for (int i = 0; i < 5; i++) {
str += String.valueOf(i);
}
return str;
}
14.3 解决方式
public String exec(){
StringBuffer str = new StringBuffer();
str.append("abc");
for (int i = 0; i < 5; i++) {
str.append(i);
}
return str.toString();
}
15、NP_SYNC_AND_NULL_CHECK_FIELD
15.1 缺陷说明
这个检测器会找出代码中进行同步操作,然后又检查是否为空值的字段。
如果代码块是同步的,那么就不可能为空。如果是空,同步时就会抛出NullPointerException异常。
15.2 代码示例
public static String getTableLastUpdateTime(String tableName) {
String time = null;
synchronized (Config.par) {
if (Config.par != null) { // 这句判断是多余的,可以去掉!
time = Config.par.get(passWord);
} else {
}
}
return time;
}
15.3 解决方式
public static String getTableLastUpdateTime(String tableName){
String time = null;
synchronized (Config.par.get(passWord)) {
time = Config.par.get(passWord);
}
return time;
}
16、UR_UNINIT_READ
16.1 缺陷说明
这个检测器会检查构造器中是否读取未初始化的字段。
16.2 代码示例
String a;
public UR_UNINIT_READ(){
String abc = a;
System.out.println(abc);
}
16.3 解决方式
String a ="";
public UR_UNINIT_READ_U(){
String abc = a;
System.out.println(abc);
}
17、DE_MIGHT_IGNORE
17.1 缺陷说明
方法可能忽略异常,应该将异常处理、打印或者抛出
17.2 代码示例
public void exec(){
try {
Integer in = Integer.valueOf(xxx);
if(in>100){
}
} catch (Exception e) {}
}
17.3 解决方式
public void exec() {
try {
Integer temp = Integer.valueOf(sss);
if(temp>100){
}
}catch (Exception e) {
logger.error(Catch an exception!, e);
}
}
18、NP_ALWAYS_NULL
18.1 缺陷说明
调用了可能为null的局部变量,可能会发生NullPointerException
18.2 代码示例
public void getStr(){
Date date = null;
int day = date.getDay();
}
18.3 解决方式
public void getStr(boolean flag){
Date date = new Date();
int day = date.getDay();
}
19、DLS_DEAD_LOCAL_STORE
19.1 缺陷说明
代码中定义未被使用的局部变量,建议将未使用的变量从代码中去除。
19.2 代码示例
public int exec(){
int rx = 100;
int ry = 200;
int local = (rx*ry)+100;
return 0;
}
List detailList = new ArrayList();
detailList = resultModel.getDetails();
19.3 解决方式
public int exec() {
int rx = 100;
int ry = 200;
int local = (rx*ry)+100;
return local;
}
List detailList;
detailList = resultModel.getDetails();
20、ES_COMPARING_PARAMETER_STRING_WITH_EQ
20.1 缺陷说明
使用==或者!=来比较字符串会比较两个字符串对象的内存地址,通常这是不一样的,
如果是想比较值的话通过equals(Object)来比较
20.2 代码示例
String firstKey;
if (firstKey != null && firstKey !=) {
System.out.println(wrong);
}
20.3 解决方式
String firstKey;
if (firstKey != null && firstKey.equals("")) {
System.out.println("right");
}
21、EVE_EXCEPTION_PRINT
21.1 缺陷说明
代码不能调用错误堆栈的打印方法,请使用SLF4J形式输出
21.2 代码示例
try {
} catch (Exception e) {
e.printStackTrace();
}
21.3 解决方式
try {
} catch (Exception e) {
LOGGER.info(输入日志信息));
}
22、CJ_SYSTEMCLASS
22.1 缺陷说明
代码不能出现System.out,请使用log形式输出
22.2 代码示例
无
22.3 解决方式
无
23、RE_POSSIBLE_UNINTENDED_PATTERN
23.1 缺陷说明
这个检测器会找出代码中用split方法传递的参数是正则表达式,
用到的字符('.' '|')没有转义的情况
23.2 代码示例
public static void main(String srds[]){
String ipstring=111.112.1113.22;
String iparray[]=ipstring.split(.);
for(String stemp:iparray){
System.out.println(stemp);
}
}
23.3 解决方式
public static void main(String srds[]){
String ipstring=111.112.1113.22;
String iparray[]=ipstring.split(//.);
for(String stemp:iparray){
System.out.println(stemp);
}
}
24、EC_UNRELATED_TYPES
24.1 缺陷说明
这个检测器会找出代码中用equals方法比较不同类型的情况,用equals方法比较不同类型都是返回false
24.2 代码示例
public static void main(String srgs[]){
String a=;
StringBuffer b=new StringBuffer();
if(a.equals(b))
System.out.print(It is false);
}}
24.3 解决方式
public static void main(String srgs[]){
String a=;
StringBuffer b=new StringBuffer();
String c= b.toString() ;
if(a.equals(c) )
System.out.print(It is true);
}