findbugs 相关

文章目录

0. 当遇到系统中允许该bug出现,但是fingbugs不过时,解决办法

1. 首先配置排除bug的xml文件

findbugs_exclude_package.xml

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
    <Match>
        <!-- 字段不是最终的,无法防止恶意代码,忽略不处理 -->
        <!-- Field isn't final and can't be protected from malicious code -->
        <Package name="~.*" />
        <Bug pattern="MS_CANNOT_BE_FINAL" />
    </Match>
</FindBugsFilter>
2. 在pom.xml指定该配置文件的路径
<build>
	<plugins>
         <!-- findbugs插件 -->
         <plugin>
             <groupId>org.codehaus.mojo</groupId>
             <artifactId>findbugs-maven-plugin</artifactId>
             <version>3.0.5</version>
             <configuration>
                 <!--findbugs需要忽略的错误的配置文件-->
                 <excludeFilterFile>./findbugs/findbugs_exclude_package.xml</excludeFilterFile>
             </configuration>
             <executions>
                 <execution>
                     <id>run-findbugs</id>
                     <!-- 在package(也可设为compile) 阶段触发执行findbugs检查,比如执行 mvn clean package -->
                     <phase>package</phase>
                     <goals>
                         <goal>check</goal>
                     </goals>
                 </execution>
             </executions>
         </plugin>
     </plugins>
 </build>

1. Bug kind and pattern: NP - NP_GUARANTEED_DEREF_ON_EXCEPTION_PATH

翻译

Value is null and guaranteed to be dereferenced on exception path

There is a statement or branch on an exception path that if executed guarantees that a value is null at this point, and that value that is guaranteed to be dereferenced (except on forward paths involving runtime exceptions).

在某个异常发生时候某个值将会被置为null,而该null值会被引用

代码示例
 public static String readInputStream(InputStream inStream, String code) throws Exception {
    StringBuilder builder = new StringBuilder();
    BufferedReader reader = null;

    try {
        reader = new BufferedReader(new InputStreamReader(inStream, code));
        String line;
        while ((line = reader.readLine()) != null) {
            builder.append(line + "\n");
        }
    } catch (Exception e) {
        log.error("system is error {}", e);
    } finally {
        try {
            // findbug 检测改行存在 bug
            reader.close();
        } catch (IOException e) {
            log.error("system is error {}", e);
        }
    }
    return builder.toString();
}
产生原因

比如我们在finally中调用了一个在异常发生时则无法正常初始化的对象,这时候就可能产生空指针等异常

解决办法

判断每个分支中所引用的值在各种情况下是否符合预期,避免产生异常

public static String readInputStream(InputStream inStream, String code) throws Exception {
    StringBuilder builder = new StringBuilder();
    BufferedReader reader = null;

    try {
        reader = new BufferedReader(new InputStreamReader(inStream, code));
        String line;
        while ((line = reader.readLine()) != null) {
            builder.append(line + "\n");
        }
    } catch (Exception e) {
        log.error("system is error {}", e);
    } finally {
        try {
            // 添加 null 校验
            if (null != reader) {
                reader.close();
            }
        } catch (IOException e) {
            log.error("system is error {}", e);
        }
    }
    return builder.toString();
}

2. Bug kind and pattern: NP - NP_NULL_ON_SOME_PATH

翻译

Possible null pointer dereference

There is a branch of statement that, if executed, guarantees that a null value will be dereferenced, which would generate a NullPointerException when the code is executed. Of course, the problem might be that the branch or statement is infeasible and that the null pointer exception can’t ever be executed; deciding that is beyond the ability of FindBugs.

可能出现空指针引用

代码示例
public static JSONObject sendCallByCustomerGw(String num, String taskId,
										  String uuid, String displayNum, String customerId, VoiceTaskPo task, String contactId, String wordCrown, GatewayPo gw, int callTimeOut) {
	try {

		String encodingFormat = "";
		String prefix = "";
		if (gw != null && StringUtils.isNotBlank(gw.getCalloutPrefix())) {
			prefix = gw.getCalloutPrefix();
		}
		if (gw != null) {
			encodingFormat = gw.getEncodingFormat();
		}


		JSONObject data = new JSONObject();
		data.put("cmd", "gwCallout");

		JSONObject jsonParam = new JSONObject();
		jsonParam.put("uuid", uuid);
		jsonParam.put("taskId", taskId);
		jsonParam.put("callId", displayNum);
		jsonParam.put("codec", encodingFormat);
		if (StringUtils.isNotBlank(wordCrown)) {
			jsonParam.put("beijiao", wordCrown + num);
		} else {
			jsonParam.put("beijiao", num);
		}
		jsonParam.put("prefix", prefix);
		
		// findbug 检测改行存在 bug
		jsonParam.put("name", gw.getGatewayName());
		jsonParam.put("phoneId", contactId);
		jsonParam.put("customerId", customerId);
		StringBuffer sipAddr = new StringBuffer();
		sipAddr.append(task.getDuiSip())
				.append("@")
				.append(task.getDuiSipServer())
				.append(":")
				.append(task.getDuiSipPort());
		jsonParam.put("sipAddr", sipAddr.toString());
		jsonParam.put("timeOutSec", callTimeOut);

		data.put("data", jsonParam);
		log.info("gateWay call info : {}", data);
		return data;
	} catch (Exception e) {
		log.error("sendCallByCustomerGw is error ,taskId:{},errorInfo:{}", taskId, e);
		return null;
	}
}
产生原因

调用对象前,未对对象进行null校验,就直接使用该对象中的get方法,则会导致空指针异常

解决办法

调用前进行null校验

public static JSONObject sendCallByCustomerGw(String num, String taskId,
                                          String uuid, String displayNum, String customerId, VoiceTaskPo task, String contactId, String wordCrown, GatewayPo gw, int callTimeOut) {
    try {

        String encodingFormat = "";
        String prefix = "";
        String name = ""; // 修改后的
        if (gw != null && StringUtils.isNotBlank(gw.getCalloutPrefix())) {
            prefix = gw.getCalloutPrefix();
        }
        if (gw != null) {
            encodingFormat = gw.getEncodingFormat();
            name = gw.getGatewayName(); // 修改后的
        }


        JSONObject data = new JSONObject();
        data.put("cmd", "gwCallout");

        JSONObject jsonParam = new JSONObject();
        jsonParam.put("uuid", uuid);
        jsonParam.put("taskId", taskId);
        jsonParam.put("callId", displayNum);
        jsonParam.put("codec", encodingFormat);
        if (StringUtils.isNotBlank(wordCrown)) {
            jsonParam.put("beijiao", wordCrown + num);
        } else {
            jsonParam.put("beijiao", num);
        }
        jsonParam.put("prefix", prefix);
        jsonParam.put("name", name); // 修改后的
        jsonParam.put("phoneId", contactId);
        jsonParam.put("customerId", customerId);
        StringBuffer sipAddr = new StringBuffer();
        sipAddr.append(task.getDuiSip())
                .append("@")
                .append(task.getDuiSipServer())
                .append(":")
                .append(task.getDuiSipPort());
        jsonParam.put("sipAddr", sipAddr.toString());
        jsonParam.put("timeOutSec", callTimeOut);

        data.put("data", jsonParam);
        log.info("gateWay call info : {}", data);
        return data;
    } catch (Exception e) {
        log.error("sendCallByCustomerGw is error ,taskId:{},errorInfo:{}", taskId, e);
        return null;
    }
}

3. Bug kind and pattern: ES - ES_COMPARING_PARAMETER_STRING_WITH_EQ

翻译

Comparison of String parameter using == or !=

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.

使用 == 或 != 比较字符串参数

此代码使用 == 或 != 运算符比较 java.lang.String 参数的引用相等性。 要求调用者仅将字符串常量或内部字符串传递给方法是不必要的脆弱,并且很少会带来可衡量的性能提升。 考虑改用 equals(Object) 方法。

代码示例
public static HttpCodeEnum value(String code) {
    for (HttpCodeEnum index : HttpCodeEnum.values()) {
        
        // findbug 检测改行存在 bug
        if (index.code == code) {
            return index;
        }
    }
    return null;
}
产生原因

使用 == 或 != 比较字符串参数

解决办法

改用 equals(Object) 方法

public static HttpCodeEnum value(String code) {
    for (HttpCodeEnum index : HttpCodeEnum.values()) {
        
        // 修改后
        if (index.code.equals(code)) {
            return index;
        }
    }
    return null;
}

4. Bug kind and pattern: Nm - NM_METHOD_NAMING_CONVENTION

翻译

Method names should start with a lower case letter

Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each internal word capitalized.

方法名称应以小写字母开头

方法应该是动词,大小写混合,首字母小写,每个内部单词的首字母大写。

代码示例
// findbug 检测改行存在 bug
public static long SecsDiff(Date date1, Date date2) {
    return (date2.getTime() - date1.getTime()) / 1000;
}
产生原因

方法名称应以小写字母开头

解决办法

方法应该是动词,大小写混合,首字母小写,每个内部单词的首字母大写。

// 修改后
public static long secsDiff(Date date1, Date date2) {
    return (date2.getTime() - date1.getTime()) / 1000;
}

5. Bug kind and pattern: Se - SE_BAD_FIELD

翻译

Non-transient non-serializable instance field in serializable class

This Serializable class defines a non-primitive instance field which is neither transient, Serializable, or java.lang.Object, and does not appear to implement the Externalizable interface or the readObject() and writeObject() methods. Objects of this class will not be deserialized correctly if a non-Serializable object is stored in this field.

序列化类中包含未实现 Serializable 接口的引用。

代码示例
@Data
public class CdrEsHump implements Serializable {

    private static final long serialVersionUID = -7084617231954917687L;

    // findbug 检测改行存在 bug
    private List<ReplyList> replyList;
}

@Data
public class ReplyList {

    private String node;
    private String flow;
    private String callRole;
    private String reply;

    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private String createTime;
}

@Data
public class ReplyList implements Serializable {

    private static final long serialVersionUID = -7054198727543316937L;

    private String node;
    private String flow;
    private String callRole;
    private String reply;

    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private String createTime;
}
产生原因

ReplyList 类未实现 Serializable 接口。

  • 如果要可序列化某个类,需要实现Serializable接口
  • 为确保序列化与反序列化一致,UID必须不可改变
  • 如果不需要序列化成员变量,那么可以将这个变量标为瞬时的,修饰符:transient
  • 如果需要序列化成员变量的引用,那么这个引用也需要实Serializable接口
解决办法
  • ReplyList 类未实现 Serializable 接口。
  • 添加修饰符 : transient
@Data
public class CdrEsHump implements Serializable {

    private static final long serialVersionUID = -7084617231954917687L;

    private List<ReplyList> replyList;
}

// 修改后
@Data
public class ReplyList implements Serializable {

    private static final long serialVersionUID = -7054198727543316937L;

    private String node;
    private String flow;
    private String callRole;
    private String reply;

    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private String createTime;
}

@Data
public class CdrEsHump implements Serializable {

    private static final long serialVersionUID = -7084617231954917687L;

    // 修改后
    private transient List<ReplyList> replyList;
}

@Data
public class ReplyList {

    private String node;
    private String flow;
    private String callRole;
    private String reply;

    @JSONField(format = "yyyy-MM-dd HH:mm:ss")
    private String createTime;
}

5. Bug kind and pattern: ME - ME_ENUM_FIELD_SETTER

翻译

Public enum method unconditionally sets its field

This public method declared in public enum unconditionally sets enum field, thus this field can be changed by malicious code or by accident from another package. Though mutable enum fields may be used for lazy initialization, it’s a bad practice to expose them to the outer world. Consider removing this method or declaring it package-private.

公共枚举方法无条件设置其字段

在 public enum 中声明的这个公共方法无条件地设置 enum 字段,因此这个字段可以被恶意代码或意外地从另一个包中更改。 尽管可变枚举字段可用于延迟初始化,但将它们暴露给外部世界是一种不好的做法。 考虑删除此方法或将其声明为包私有的。

代码示例
/**
 * 号码呼叫状态
 */
public enum CallStatus {

    EXPIRE_CANCEL_CALL(8, "过期取消呼叫");

    private int code;
    private String name;

    CallStatus(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static CallStatus valueOf(int code) {
        for (CallStatus index : CallStatus.values()) {
            if (index.code == code) {
                return index;
            }
        }
        return null;
    }

    public int getCode() {
        return code;
    }

    // findbug 检测改行存在 bug
    public void setCode(byte code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    // findbug 检测改行存在 bug
    public void setName(String name) {
        this.name = name;
    }
}
产生原因

公共枚举方法中set方法,修饰符设置成了public,有可能导致安全问题

解决办法

在 public enum 中声明的这个公共方法无条件地设置 enum 字段,因此这个字段可以被恶意代码或意外地从另一个包中更改。 尽管可变枚举字段可用于延迟初始化,但将它们暴露给外部世界是一种不好的做法。 考虑删除此方法或将其声明为包私有的。

或者删除调set方法

/**
 * 号码呼叫状态
 */
public enum CallStatus {

    EXPIRE_CANCEL_CALL(8, "过期取消呼叫");

    private int code;
    private String name;

    CallStatus(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static CallStatus valueOf(int code) {
        for (CallStatus index : CallStatus.values()) {
            if (index.code == code) {
                return index;
            }
        }
        return null;
    }

    public int getCode() {
        return code;
    }

    // 修改后
    private void setCode(byte code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    // 修改后
    private void setName(String name) {
        this.name = name;
    }
}

6. Bug kind and pattern: EI - EI_EXPOSE_REP|EI_EXPOSE_REP2

翻译

May expose internal representation by returning reference to mutable object

Returning a reference to a mutable object value stored in one of the object’s fields exposes the internal representation of the object. If instances are accessed by untrusted code, and unchecked changes to the mutable object would compromise security or other important properties, you will need to do something different. Returning a new copy of the object is better approach in many situations.

可以通过引用可变对象来公开内部表示

此代码将对外部可变对象的引用存储到对象的内部表示中。如果不受信任的代码访问实例,并且对可变对象的未经检查的更改会危及安全性或其他重要属性。在许多情况下,存储对象的副本是更好的方法。

代码示例
// findbug 检测改行存在 bug
public Date getStart_stamp() {
    return start_stamp;
}
产生原因

方法参数接收的对象,或者返回的是原有可变对象的引用,有可能在外部会有被改动的风险

解决办法

克隆该可变变量的引用

// 修改后,返回一个克隆引用,对原有对象进行一个保护
public Date getStart_stamp() {
    if (null != start_stamp) {
        return (Date) start_stamp.clone();
    }
    return null;
}

7. Bug kind and pattern: MS - MS_CANNOT_BE_FINAL

翻译

Field isn’t final and can’t be protected from malicious code

A mutable static field could be changed by malicious code or by accident from another package. Unfortunately, the way the field is used doesn’t allow any easy fix to this problem.

字段不是最终的,无法防止恶意代码

可变静态字段可能会被恶意代码或意外从另一个包更改。 不幸的是,该字段的使用方式无法轻松解决此问题。

产生原因

常量类中,静态属性未加final

解决办法

此字段前应该加final

8. Bug kind and pattern: DLS - DLS_DEAD_LOCAL_STORE

翻译

Dead store to local variable

This instruction assigns a value to a local variable, but the value is not read or used in any subsequent instruction. Often, this indicates an error, because the value computed is never used.
Note that Sun’s javac compiler often generates dead stores for final local variables. Because FindBugs is a bytecode-based tool, there is no easy way to eliminate these false positives.

本地变量存储了闲置不用的对象

产生原因

本地变量存储了闲置不用的对象

解决办法

删除或者注释掉即可

9. Bug kind and pattern: ST - ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD

翻译

Write to static field from instance method

This instance method writes to a static field. This is tricky to get correct if multiple instances are being manipulated, and generally bad practice.

从实例方法写入静态字段

此实例方法写入静态字段。 如果操作多个实例,这很难纠正,而且通常是不好的做法。

代码示例
public static String PARTNERSHIP_VERSION = "mengya";

@Value("${setting.partnershipVersion}")
public void setPartnershipVersion(String partnershipVersion) {
    PARTNERSHIP_VERSION = partnershipVersion;
}
产生原因

在实例方法中不能直接对static成员进行赋值,当创建多个实例时,多个实例调用该方法会造成一些不可预知的隐患。

解决办法
public static String PARTNERSHIP_VERSION = "mengya";

@Value("${setting.partnershipVersion}")
public void setPartnershipVersion(String partnershipVersion) {
    setPartnershipVersionStatic(partnershipVersion);
}

private static void setPartnershipVersionStatic(String partnershipVersion) {
    PARTNERSHIP_VERSION = partnershipVersion;
}

10. Bug kind and pattern: WMI - WMI_WRONG_MAP_ITERATOR

翻译

Inefficient use of keySet iterator instead of entrySet 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 迭代器而不是 entrySet 迭代器的效率低下

此方法使用从 keySet 迭代器中检索到的键访问 Map 条目的值。 在映射的 entrySet 上使用迭代器更有效,以避免 Map.get(key) 查找。

代码示例
Set<String> sets = nestedParams.keySet();
for (String key : sets) {
    addQueryParam(key);
    addQueryParam(nestedParams.get(key)); 
}
产生原因

遍历时使用 keySet 迭代器而不是 entrySet 迭代器,keySet 迭代器的效率低下

解决办法

此方法使用从 keySet 迭代器中检索到的键访问 Map 条目的值。 在映射的 entrySet 上使用迭代器更有效,以避免 Map.get(key) 查找。

Set<Map.Entry<String, Object>> entries = nestedParams.entrySet();
for (Map.Entry<String, Object> entry : entries) {
    addQueryParam(entry.getKey();
    addQueryParam(entry.getValue());
}

11. Bug kind and pattern: Bx - DM_BOXED_PRIMITIVE_FOR_PARSING

翻译

Boxing/unboxing to parse a primitive

A boxed primitive is created from a String, just to extract the unboxed primitive value. It is more efficient to just call the static parseXXX method.

装箱/拆箱以解析原语

装箱原语是从字符串创建的,只是为了提取未装箱的原语值。 只调用静态的 parseXXX 方法效率更高。

代码示例
@Value("${setting.defaultRobotNum}")
public void setRobotCount(String robotCount) {
    ROBOT_COUNT = Integer.valueOf(robotCount);
}

产生原因

使用 Integer.valueOf(robotCount) 进行类型转换,涉及到装箱/拆箱,效率没有 Integer.parseInt(robotCount) 高

解决办法

将 Integer.valueOf(robotCount); 换成 Integer.parseInt(robotCount);

@Value("${setting.defaultRobotNum}")
public void setRobotCount(String robotCount) {
    ROBOT_COUNT = Integer.parseInt(robotCount);
}

12. Bug kind and pattern: DC - DC_DOUBLECHECK

翻译

Possible double check of field

This method may contain an instance of double-checked locking. This idiom is not correct according to the semantics of the Java memory model. For more information, see the web page http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.

可能对字段进行双重检查

此方法可能包含双重检查锁定的实例。 根据 Java 内存模型的语义,这个习惯用法是不正确的。 有关详细信息,请参阅网页 http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html。

代码示例

产生原因
解决办法

13. Bug kind and pattern: UL - UL_UNRELEASED_LOCK_EXCEPTION_PATH

翻译

Method does not release lock on all exception paths

This method acquires a JSR-166 (java.util.concurrent) lock, but does not release it on all exception paths out of the method. In general, the correct idiom for using a JSR-166 lock is:

方法不会释放所有异常路径上的锁

此方法获取 JSR-166 (java.util.concurrent) 锁,但不会在该方法之外的所有异常路径上释放它。 一般来说,使用 JSR-166 锁的正确习惯用法是:

Lock l = ...;
l.lock();
try {
    // do something
} finally {
    l.unlock();
}
代码示例
private static Lock fastClientlock = new ReentrantLock();
private static RestClient getFastEsClient() {
    fastClientlock.lock();
    if (null == fastClientQueue) {
        init();
    }
    try {
        return fastClientQueue.poll(lockTime, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
        log.error("getFastEsClient is error:", e);
        return null;
    } finally {
        fastClientlock.unlock();
    }
}
产生原因
if (null == fastClientQueue) {
    init();
}

上面判断添加为真时,进入 init() 方法,当在 init() 中出现异常时,下面那坨代码据不会被执行了,导致锁进不能被释放掉

解决办法
if (null == fastClientQueue) {
    init();
}

把上面判断逻辑添加到 try 代块码中

private static Lock fastClientlock = new ReentrantLock();
private static RestClient getFastEsClient() {
    fastClientlock.lock();
    try {
        if (null == fastClientQueue) {
            init();
        }
        return fastClientQueue.poll(lockTime, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
        log.error("getFastEsClient is error:", e);
        return null;
    } finally {
        fastClientlock.unlock();
    }
}

14 Bug kind and pattern: BSHIFT - BSHIFT_WRONG_ADD_PRIORITY

翻译

Possible bad parsing of shift operation

The code performs an operation like (x << 8 + y). Although this might be correct, probably it was meant to perform (x << 8) + y, but shift operation has a lower precedence, so it’s actually parsed as x << (8 + y).

移位操作的可能错误解析

该代码执行类似 (x << 8 + y) 的操作。 虽然这可能是正确的,可能是为了执行 (x << 8) + y,但是移位操作的优先级较低,所以它实际上被解析为 x << (8 + y)。

代码示例
sequenceNumber = data[2] << 8 + data[3];
产生原因

该代码执行类似 (x << 8 + y) 的操作。 虽然这可能是正确的,可能是为了执行 (x << 8) + y,但是移位操作的优先级较低,所以它实际上被解析为 x << (8 + y)。

解决办法
sequenceNumber = (data[2] << 8+ data[3];

15. Bug kind and pattern: EC - EC_UNRELATED_TYPES

翻译

Call to equals() comparing different types

This method calls equals(Object) on two references of different class types and analysis suggests they will be to objects of different classes at runtime. Further, examination of the equals methods that would be invoked suggest that either this call will always return false, or else the equals method is not be symmetric (which is a property required by the contract for equals in class Object).

调用 equals() 比较不同类型

此方法对两个不同类类型的引用调用 equals(Object),分析表明它们将在运行时指向不同类的对象。 此外,对将被调用的 equals 方法的检查表明该调用将始终返回 false,或者 equals 方法不是对称的(这是 Object 类中的 equals 的契约所要求的属性)。

代码示例
private boolean isCellNull = false;
if ("".equals(isCellNull)) {
    ...
}
产生原因

调用 equals() 比较不同类型

解决办法

换成相同类型的再进行比较

private boolean isCellNull = false;
if (isCellNull) {
    ...
}

16. Bug kind and pattern: NP - NP_ALWAYS_NULL

翻译

Null pointer dereference

A null pointer is dereferenced here. This will lead to a NullPointerException when the code is executed.

空指针解引用

此处取消引用空指针。 这将在执行代码时导致 NullPointerException。

代码示例
if (sessionid == null && sessionid.length() > 0) {
    ...
}
产生原因

sessionid == null 时,因为时 && 所以会执行 sessionid.length() 这样就会出现空指针异常

解决办法
if (sessionid == null || sessionid.length() <= 0) {
    ...
}

17. Bug kind and pattern: NP - NP_NULL_ON_SOME_PATH_EXCEPTION

翻译

Possible null pointer dereference in method on exception path

A reference value which is null on some exception control path is dereferenced here. This may lead to a NullPointerException when the code is executed. Note that because FindBugs currently does not prune infeasible exception paths, this may be a false warning.
Also note that FindBugs considers the default case of a switch statement to be an exception path, since the default case is often infeasible.

常路径上的方法中可能取消引用空指针

在某些异常控制路径上为 null 的引用值在此处被取消引用。 这可能会在执行代码时导致 NullPointerException。 请注意,由于 FindBugs 当前不会修剪不可行的异常路径,因此这可能是错误警告。
另请注意,FindBugs 将 switch 语句的默认情况视为异常路径,因为默认情况通常是不可行的。

代码示例
ZipOutputStream out = null;
try {
    out = new ZipOutputStream(new FileOutputStream(zipFile));
    doCompress(srcFile, out);
} catch (Exception e) {
    throw e;
} finally {
    out.close();// 记得关闭资源
}
产生原因

在 finally 代码块中 为对 out 进行判空,有可能导致空指针异常

解决办法
ZipOutputStream out = null;
try {
    out = new ZipOutputStream(new FileOutputStream(zipFile));
    doCompress(srcFile, out);
} catch (Exception e) {
    throw e;
} finally {
    if (null != out) {
        out.close();// 记得关闭资源
    }
}

18. Bug kind and pattern: NP - NP_NULL_PARAM_DEREF

翻译

Method call passes null for non-null parameter

This method call passes a null value for a non-null method parameter. Either the parameter is annotated as a parameter that should always be non-null, or analysis has shown that it will always be dereferenced.

方法调用为非空参数传递空值

此方法调用为非空方法参数传递空值。 要么将该参数注释为应始终为非空的参数,要么分析表明它将始终取消引用。

代码示例
public List<P> getEntityByIds(IDT[] ids, String customerId) {
    QueryWrapper<P> wrapper = Wrappers.query();
    wrapper.eq(StringUtils.isNotBlank(customerId), "customer_id", customerId).in(null != ids && ids.length > 0, "id", ids);
    List<P> ps = baseMapper.selectBatchIds(Arrays.asList(ids));
    if (StringUtils.isNotBlank(customerId) && null != ps && ps.size() > 0) {
        setCustomerNameInT(ps,
                customerMapper.getCustomerNameById(Integer.parseInt(customerId)));
    }
    return ps;
}
产生原因

未对方法参数进行判空,会在方法中处理时产生空指针异常

解决办法
public List<P> getEntityByIds(IDT[] ids, String customerId) {
    List<P> ps = Lists.newArrayList();
    if (null == ids || ids.length <= 0) {
        return ps;
    }
    QueryWrapper<P> wrapper = Wrappers.query();
    wrapper.eq(StringUtils.isNotBlank(customerId), "customer_id", customerId).in(null != ids && ids.length > 0, "id", ids);
    ps = baseMapper.selectBatchIds(Arrays.asList(ids));
    if (StringUtils.isNotBlank(customerId) && null != ps && ps.size() > 0) {
        setCustomerNameInT(ps,
                customerMapper.getCustomerNameById(Integer.parseInt(customerId)));
    }
    return ps;
}

19. Bug kind and pattern: RC - RC_REF_COMPARISON

翻译

Suspicious reference comparison

This method compares two reference values using the == or != operator, where the correct way to compare instances of this type is generally with the equals() method. It is possible to create distinct instances that are equal but do not compare as == since they are different objects. Examples of classes which should generally not be compared by reference are java.lang.Integer, java.lang.Float, etc.

可疑参考比较

此方法使用 == 或 != 运算符比较两个引用值,其中比较此类型实例的正确方法通常是使用 equals() 方法。 可以创建相等但不作为 == 比较的不同实例,因为它们是不同的对象。 通常不应通过引用进行比较的类示例有 java.lang.Integer、java.lang.Float 等。

代码示例
if (robotPo.getId() !=  id) {
    ...
}
产生原因

此方法使用 == 或 != 运算符比较两个引用值

解决办法
if (null == id || id.equals(robotPo.getId())) {
    ...
}

20. Bug kind and pattern: RCN - RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE

翻译

Nullcheck of value previously dereferenced

A value is checked here to see whether it is null, but this value can’t be null because it was previously dereferenced and if it were null a null pointer exception would have occurred at the earlier dereference. Essentially, this code and the previous dereference disagree as to whether this value is allowed to be null. Either the check is redundant or the previous dereference is erroneous.

先前取消引用的值的空检查

此处检查一个值以查看它是否为空,但该值不能为空,因为它先前已被取消引用,如果它为空,则在更早的取消引用时会发生空指针异常。 本质上,这段代码和之前的解引用不同意这个值是否允许为空。 要么检查是多余的,要么之前的取消引用是错误的。

代码示例
// 验证用户是否有该task权限
if (!CustomerUtil.tpUserIsBindTaskId(username, taskId)) {
    return RestResponse.build(HttpCodeEnum.PARAM_ERROR, "username无该task权限");
}
if (null == taskId) {
    return RestResponse.build(HttpCodeEnum.PARAM_ERROR, "缺少taskId参数");
}
产生原因

两个if顺序由问题,需要先判断为空,再去执行其他代码

解决办法
if (null == taskId) {
    return RestResponse.build(HttpCodeEnum.PARAM_ERROR, "缺少taskId参数");
}
// 验证用户是否有该task权限
if (!CustomerUtil.tpUserIsBindTaskId(username, taskId)) {
    return RestResponse.build(HttpCodeEnum.PARAM_ERROR, "username无该task权限");
}

21. Bug kind and pattern: INT - INT_BAD_COMPARISON_WITH_NONNEGATIVE_VALUE

翻译

Bad comparison of nonnegative value with negative constant or zero

This code compares a value that is guaranteed to be non-negative with a negative constant or zero.

非负值与负常数或零的错误比较

此代码将保证为非负的值与负常数或零进行比较。

代码示例
 boolean flag = (minVal < 0 || (minVal >= 0 && billsec >= minVal))
 && (maxVal < 0 || (maxVal >= 0 && billsec < maxVal));
产生原因

因为前面已经判断 minVal < 0 所以 || 后就不用 minVal >= 0,这样的话有点多此一举,去掉就可以

解决办法
(minVal < 0 || billsec >= minVal)
&& (maxVal < 0 || billsec < maxVal)

22. Bug kind and pattern: USELESS_STRING - DMI_INVOKING_TOSTRING_ON_ARRAY

翻译

Invocation of toString on an array

The code invokes toString on an array, which will generate a fairly useless result such as [C@16f0472. Consider using Arrays.toString to convert the array into a readable String that gives the contents of the array. See Programming Puzzlers, chapter 3, puzzle 12.

在数组上调用 toString

该代码对数组调用 toString,这将生成一个相当无用的结果,例如 [C@16f0472. 考虑使用 Arrays.toString 将数组转换为提供数组内容的可读字符串。

代码示例
String[] fields;
log.error("号码变量处理异常" + fields);
产生原因

在数组上调用 toString

解决办法
String[] fields;
log.error("号码变量处理异常: {}", JSONObject.toJSONString(fields));

23. Bug kind and pattern: BC - BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS

翻译

Equals method should not assume anything about the type of its argument

The equals(Object o) method shouldn’t make any assumptions about the type of o. It should simply return false if o is not the same type as this.

Equals 方法不应该对其参数的类型做任何假设

equals(Object o) 方法不应该对 o 的类型做出任何假设。 如果 o 与此类型不同,它应该简单地返回 false。

代码示例
@Override
public boolean equals(Object object) {
    if (null != object) {
        GoipSimVo vo = (GoipSimVo) object;
        if (null != this.phone) {
            return this.phone.equals(vo.getPhone());
        }
    }
    return false;
}
产生原因

当你在实现类的equals方法时,不应该对参数有任何的预先设定。如上代码所写,则设定了参数object肯定是GoipSimVo类的一个对象.但是如果在函数调用时,参数object不是一个GoipSimVo类或其子类,就会导致代码会抛出一个ClassCastException。因此在实现equals方法,应该加一个判断,如果参数object不是一个GoipSimVo类对象,则返回false。

解决办法
@Override
public boolean equals(Object object) {
    if (null != object) {
        if (object instanceof GoipSimVo) {
            GoipSimVo vo = (GoipSimVo) object;
            if (null != this.phone) {
                return this.phone.equals(vo.getPhone());
            } 
        }
    }
    return false;
}

24. Bug kind and pattern: RV - RV_RETURN_VALUE_IGNORED_BAD_PRACTICE

翻译

Method ignores exceptional return value

This method returns a value that is not checked. The return value should be checked since it can indicate an unusual or unexpected function execution. For example, the File.delete() method returns false if the file could not be successfully deleted (rather than throwing an Exception). If you don’t check the result, you won’t notice if the method invocation signals unexpected behavior by returning an atypical return value.

方法忽略异常返回值

此方法返回一个未检查的值。 应该检查返回值,因为它可以指示异常或意外的函数执行。 例如,如果文件无法成功删除(而不是抛出异常),则 File.delete() 方法返回 false。 如果您不检查结果,您将不会注意到方法调用是否通过返回非典型返回值来表示意外行为。

代码示例
newsFileRoot.mkdirs();
产生原因

没有检查方法的返回值,但返回值可以代表异常。

解决办法
boolean mkdirs = newsFileRoot.mkdirs();
if (!mkdirs) {
    log.error("FileUtil saveFile mkdirs fail.{}", newsRootPath);
}

25. Bug kind and pattern: Nm - NM_SAME_SIMPLE_NAME_AS_SUPERCLASS

翻译

Class names shouldn’t shadow simple name of superclass

This class has a simple name that is identical to that of its superclass, except that its superclass is in a different package (e.g., alpha.Foo extends beta.Foo). This can be exceptionally confusing, create lots of situations in which you have to look at import statements to resolve references and creates many opportunities to accidentally define methods that do not override methods in their superclasses.

类名不应掩盖超类的简单名称

此类具有与其超类相同的简单名称,但其超类位于不同的包中(例如,alpha.Foo 扩展了 beta.Foo)。 这可能会非常令人困惑,会产生很多情况,在这种情况下,您必须查看导入语句来解析引用,并会产生许多机会意外定义不覆盖超类中方法的方法。

代码示例
public class SimpleByteSource extends org.apache.shiro.util.SimpleByteSource  {}
产生原因

子类名称和父类名称相同

解决办法
public class MySimpleByteSource extends SimpleByteSource {}

26. Bug kind and pattern: Se - SE_NO_SUITABLE_CONSTRUCTOR

翻译

Class is Serializable but its superclass doesn’t define a void constructor

This class implements the Serializable interface and its superclass does not. When such an object is deserialized, the fields of the superclass need to be initialized by invoking the void constructor of the superclass. Since the superclass does not have one, serialization and deserialization will fail at runtime.

类是可序列化的,但它的超类没有定义空构造函数

这个类实现了 Serializable 接口,而它的超类没有。 当这样的对象被反序列化时,需要通过调用超类的 void 构造函数来初始化超类的字段。 由于超类没有,序列化和反序列化将在运行时失败。

代码示例

产生原因
解决办法

27. Bug kind and pattern: RC - RC_REF_COMPARISON_BAD_PRACTICE

翻译

Suspicious reference comparison to constant

This method compares a reference value to a constant using the == or != operator, where the correct way to compare instances of this type is generally with the equals() method. It is possible to create distinct instances that are equal but do not compare as == since they are different objects. Examples of classes which should generally not be compared by reference are java.lang.Integer, java.lang.Float, etc.

与常量的可疑参考比较

此方法使用 == 或 != 运算符将引用值与常量进行比较,其中比较此类型实例的正确方法通常是使用 equals() 方法。 可以创建相等但不作为 == 比较的不同实例,因为它们是不同的对象。 通常不应通过引用进行比较的类示例有 java.lang.Integer、java.lang.Float 等。

代码示例
if (record.getCustomerId() == SystemConstants.SUPER_CUSTOMER_ID) {
    ...
}
产生原因

不能使用 == 或者 != 来比较,应该使用 equals()

解决办法
if (SystemConstants.SUPER_CUSTOMER_ID.equals(record.getCustomerId())) {
    ...
}

28. Bug kind and pattern: OS - OS_OPEN_STREAM

翻译

Method may fail to close 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.

方法可能无法关闭流

该方法创建一个 IO 流对象,不将其分配给任何字段,将其传递给可能关闭它或返回它的其他方法,并且似乎不会在该方法之外的所有路径上关闭流。 这可能会导致文件描述符泄漏。 使用 finally 块来确保流被关闭通常是一个好主意。

产生原因

没有关闭已经打开的流

解决办法

在 finally 代码块中进行关闭

29. Bug kind and pattern: OBL - OBL_UNSATISFIED_OBLIGATION

翻译

Method may fail to clean up stream or resource

This method may fail to clean up (close, dispose of) a stream, database object, or other resource requiring an explicit cleanup operation.
In general, if a method opens a stream or other resource, the method should use a try/finally block to ensure that the stream or resource is cleaned up before the method returns.
This bug pattern is essentially the same as the OS_OPEN_STREAM and ODR_OPEN_DATABASE_RESOURCE bug patterns, but is based on a different (and hopefully better) static analysis technique. We are interested is getting feedback about the usefulness of this bug pattern. To send feedback, either:
send email to findbugs@cs.umd.edu
file a bug report: http://findbugs.sourceforge.net/reportingBugs.html
In particular, the false-positive suppression heuristics for this bug pattern have not been extensively tuned, so reports about false positives are helpful to us.
See Weimer and Necula, Finding and Preventing Run-Time Error Handling Mistakes, for a description of the analysis technique.

方法可能无法清理流或资源

此方法可能无法清理(关闭、处置)流、数据库对象或其他需要显式清理操作的资源。
一般来说,如果一个方法打开一个流或其他资源,该方法应该使用一个 try/finally 块来确保在该方法返回之前清除该流或资源。
此错误模式本质上与 OS_OPEN_STREAM 和 ODR_OPEN_DATABASE_RESOURCE 错误模式相同,但基于不同的(希望更好的)静态分析技术。我们感兴趣的是获得有关此错误模式有用性的反馈。要发送反馈,请执行以下任一操作:
发送电子邮件至 findbugs@cs.umd.edu
提交错误报告:http://findbugs.sourceforge.net/reportingBugs.html
特别是,此错误模式的误报抑制启发式方法尚未得到广泛调整,因此有关误报的报告对我们很有帮助。
有关分析技术的说明,请参阅 Weimer 和 Necula,查找和防止运行时错误处理错误。

代码示例

产生原因
解决办法

30. Bug kind and pattern: OBL - OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE

翻译

Method may fail to clean up stream or resource on checked exception

This method may fail to clean up (close, dispose of) a stream, database object, or other resource requiring an explicit cleanup operation.
In general, if a method opens a stream or other resource, the method should use a try/finally block to ensure that the stream or resource is cleaned up before the method returns.
This bug pattern is essentially the same as the OS_OPEN_STREAM and ODR_OPEN_DATABASE_RESOURCE bug patterns, but is based on a different (and hopefully better) static analysis technique. We are interested is getting feedback about the usefulness of this bug pattern. To send feedback, either:
send email to findbugs@cs.umd.edu
file a bug report: http://findbugs.sourceforge.net/reportingBugs.html
In particular, the false-positive suppression heuristics for this bug pattern have not been extensively tuned, so reports about false positives are helpful to us.
See Weimer and Necula, Finding and Preventing Run-Time Error Handling Mistakes, for a description of the analysis technique.

方法可能无法在检查异常时清理流或资源

此方法可能无法清理(关闭、处置)流、数据库对象或其他需要显式清理操作的资源。
一般来说,如果一个方法打开一个流或其他资源,该方法应该使用一个 try/finally 块来确保在该方法返回之前清除该流或资源。
此错误模式本质上与 OS_OPEN_STREAM 和 ODR_OPEN_DATABASE_RESOURCE 错误模式相同,但基于不同的(希望更好的)静态分析技术。我们感兴趣的是获得有关此错误模式有用性的反馈。要发送反馈,请执行以下任一操作:
发送电子邮件至 findbugs@cs.umd.edu
提交错误报告:http://findbugs.sourceforge.net/reportingBugs.html
特别是,此错误模式的误报抑制启发式方法尚未得到广泛调整,因此有关误报的报告对我们很有帮助。
有关分析技术的说明,请参阅 Weimer 和 Necula,查找和防止运行时错误处理错误。

代码示例
public static String encodeBase64File(String path) throws Exception {
    File file = new File(path);
    FileInputStream inputFile = new FileInputStream(file);
    byte[] buffer = new byte[(int) file.length()];
    inputFile.read(buffer);
    inputFile.close();
    return new BASE64Encoder().encode(buffer);
}
产生原因
  • 未在 finally 块中关闭流
  • 由于OutStream依赖于流InputStream,如果InputStream关闭失败,就会导致OutStream也关闭失败,所以恰当的做法是先关闭依赖流,再关闭被依赖的流。
解决办法
public static String encodeBase64File(String path) throws Exception {
    FileInputStream inputFile = null;
    try {
        File file = new File(path);
        inputFile = new FileInputStream(file);
        byte[] buffer = new byte[(int) file.length()];
        inputFile.read(buffer);
        return new BASE64Encoder().encode(buffer);
    } catch (Exception e) {
        log.error("MyStringUtil encodeBase64File is error: {}", e);
        return null;
    } finally {
        if (null != inputFile) {
            inputFile.close();
        }
    }
}

31. Bug kind and pattern: Dm - DM_DEFAULT_ENCODING

翻译

Reliance on default encoding

Found a call to a method which will perform a byte to String (or String to byte) conversion, and will assume that the default platform encoding is suitable. This will cause the application behaviour to vary between platforms. Use an alternative API and specify a charset name or Charset object explicitly.

依赖默认编码

找到了一个方法调用,该方法将执行字节到字符串(或字符串到字节)的转换,并假定默认平台编码是合适的。 这将导致应用程序行为因平台而异。 使用替代 API 并明确指定字符集名称或字符集对象。

代码示例

产生原因
解决办法

32. Bug kind and pattern: RCN - RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE

翻译

Redundant nullcheck of value known to be non-null

This method contains a redundant check of a known non-null value against the constant null.

已知非空值的冗余空值检查

此方法包含对已知非空值与常量空值的冗余检查。

代码示例

产生原因
解决办法

33. Bug kind and pattern: Eq - EQ_DOESNT_OVERRIDE_EQUALS

翻译

Class doesn’t override equals in superclass

This class extends a class that defines an equals method and adds fields, but doesn’t define an equals method itself. Thus, equality on instances of this class will ignore the identity of the subclass and the added fields. Be sure this is what is intended, and that you don’t need to override the equals method. Even if you don’t need to override the equals method, consider overriding it anyway to document the fact that the equals method for the subclass just return the result of invoking super.equals(o).

类不会覆盖超类中的等于

这个类扩展了一个定义equals方法并添加字段的类,但不定义equals方法本身。 因此,此类实例的相等性将忽略子类的标识和添加的字段。 确保这是预期的,并且您不需要覆盖 equals 方法。 即使您不需要覆盖 equals 方法,也要考虑覆盖它以记录子类的 equals 方法只返回调用 super.equals(o) 的结果这一事实。

产生原因

类没有覆盖父类的equals方法

34. Bug kind and pattern: NP - NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE

翻译

Possible null pointer dereference due to return value of called method

The return value from a method is dereferenced without a null check, and the return value of that method is one that should generally be checked for null. This may lead to a NullPointerException when the code is executed.

由于被调用方法的返回值可能导致空指针取消引用

方法的返回值在没有空检查的情况下被取消引用,并且该方法的返回值通常应该检查空值。 这可能会在执行代码时导致 NullPointerException。

代码示例

产生原因
解决办法

35. Bug kind and pattern: ICAST - ICAST_IDIV_CAST_TO_DOUBLE

翻译

Integral division result cast to double or float

This code casts the result of an integral division (e.g., int or long division) operation to double or float. Doing division on integers truncates the result to the integer value closest to zero. The fact that the result was cast to double suggests that this precision should have been retained. What was probably meant was to cast one or both of the operands to double before performing the division. Here is an example:

int x = 2;
int y = 5;
// Wrong: yields result 0.0
double value1 =  x / y;

// Right: yields result 0.4
double value2 =  x / (double) y;

整数除法结果转换为双精度或浮点数

此代码将整数除法(例如 int 或 long 除法)运算的结果转换为 double 或 float。 对整数进行除法会将结果截断为最接近零的整数值。 结果被强制转换为 double 的事实表明应该保留这种精度。 可能的意思是在执行除法之前将一个或两个操作数强制转换为双倍。 下面是一个例子:

int x = 2;
int y = 5;
// Wrong: yields result 0.0
double value1 =  x / y;

// Right: yields result 0.4
double value2 =  x / (double) y;
代码示例

产生原因
解决办法

36. Bug kind and pattern: BC - BC_UNCONFIRMED_CAST

翻译

Unchecked/unconfirmed cast

This cast is unchecked, and not all instances of the type casted from can be cast to the type it is being cast to. Check that your program logic ensures that this cast will not fail.

未经检查/未经确认的演员表

此强制转换是未检查的,并且并非所有被强制转换的类型的实例都可以强制转换为它要转换到的类型。 检查您的程序逻辑是否确保此转换不会失败。

产生原因

强转时,类型与被强转类型不否

37. Bug kind and pattern: HE - HE_EQUALS_NO_HASHCODE

翻译

Class defines equals() but not 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()

此类覆盖 equals(Object),但不覆盖 hashCode()。 因此,该类可能违反相等对象必须具有相等哈希码的不变量。

38. Bug kind and pattern: SIC - SIC_INNER_SHOULD_BE_STATIC

翻译

Should be a static inner class

This class is an inner class, but does not use its embedded reference to the object which created it. This reference makes the instances of the class larger, and may keep the reference to the creator object alive longer than necessary. If possible, the class should be made static.

应该是静态内部类

这个类是一个内部类,但不使用它对创建它的对象的嵌入引用。 此引用使类的实例更大,并且可能使对创建者对象的引用保持比需要的时间更长。 如果可能,类应该是静态的。

解决

https://blog.csdn.net/ydk888888/article/details/80283759

39. Bug kind and pattern: HRS - HRS_REQUEST_PARAMETER_TO_HTTP_HEADER

翻译

HTTP Response splitting vulnerability

This code directly writes an HTTP parameter to an HTTP header, which allows for a HTTP response splitting vulnerability. See http://en.wikipedia.org/wiki/HTTP_response_splitting for more information.
FindBugs looks only for the most blatant, obvious cases of HTTP response splitting. If FindBugs found any, you almost certainly have more vulnerabilities that FindBugs doesn’t report. If you are concerned about HTTP response splitting, you should seriously consider using a commercial static analysis or pen-testing tool.

HTTP 响应拆分漏洞

此代码直接将 HTTP 参数写入 HTTP 标头,从而存在 HTTP 响应拆分漏洞。 有关更多信息,请参阅 http://en.wikipedia.org/wiki/HTTP_response_splitting。
FindBugs 只查找最明显、最明显的 HTTP 响应拆分案例。 如果 FindBugs 发现任何漏洞,您几乎肯定会有更多 FindBugs 未报告的漏洞。 如果您担心 HTTP 响应拆分,您应该认真考虑使用商业静态分析或渗透测试工具。

解决

http://www.cocoachina.com/articles/42269

修改前

String rqHd = request.getHeader("Access-Control-Request-Headers");    
response.addHeader("Access-Control-Allow-Headers", rqHd); // findbugs error here

修改后

String rqHd = request.getHeader("Access-Control-Request-Headers"); 
if(rqHd != null){
    String rqHeader = URLEncoder.encode(rqHd,StandardCharsets.UTF_8.displayName());   
    response.addHeader("Access-Control-Allow-Headers", rqHeader);
}

40. Bug kind and pattern: MS - MS_PKGPROTECT

翻译

Field should be package protected

A mutable static field could be changed by malicious code or by accident. The field could be made package protected to avoid this vulnerability.

字段应该是包保护的

可变静态字段可能会被恶意代码或意外更改。 可以对该字段进行包保护以避免此漏洞。

解决

https://www.cnblogs.com/jiangxinnju/p/6582404.html

41. Bug kind and pattern: MS - MS_MUTABLE_ARRAY

翻译

Field is a mutable array

A final static field references an array and can be accessed by malicious code or by accident from another package. This code can freely modify the contents of the array。

字段是一个可变数组

最后一个静态字段引用一个数组,可以被恶意代码访问,也可以从另一个包中意外访问。 这段代码可以自由修改数组的内容。

42. Bug kind and pattern: Dm - DM_EXIT

翻译

Method invokes System.exit(…)

Invoking System.exit shuts down the entire Java virtual machine. This should only been done when it is appropriate. Such calls make it hard or impossible for your code to be invoked by other code. Consider throwing a RuntimeException instead.

方法调用 System.exit(…)

调用 System.exit 会关闭整个 Java 虚拟机。 只有在适当的时候才应该这样做。 此类调用使您的代码很难或不可能被其他代码调用。 考虑改为抛出 RuntimeException。

43. Bug kind and pattern: MS - MS_SHOULD_BE_FINAL

翻译

Field isn’t final but should be

This static field public but not final, and could be changed by malicious code or by accident from another package. The field could be made final to avoid this vulnerability.

字段不是最终的,但应该是

这个静态字段 public 但不是 final,并且可能被恶意代码或意外从另一个包更改。 该字段可以是最终的,以避免此漏洞。

产生原因

字段属性没有被final修饰

44. Bug kind and pattern: Eq - EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC

翻译

equals method overrides equals in superclass and may not be symmetric

This class defines an equals method that overrides an equals method in a superclass. Both equals methods methods use instanceof in the determination of whether two objects are equal. This is fraught with peril, since it is important that the equals method is symmetrical (in other words, a.equals(b) == b.equals(a)). If B is a subtype of A, and A’s equals method checks that the argument is an instanceof A, and B’s equals method checks that the argument is an instanceof B, it is quite likely that the equivalence relation defined by these methods is not symmetric.

equals 方法覆盖超类中的 equals 并且可能不对称

此类定义了一个 equals 方法,该方法覆盖了超类中的 equals 方法。 两个 equals 方法都使用 instanceof 来确定两个对象是否相等。 这充满了危险,因为 equals 方法对称很重要(换句话说,a.equals(b) == b.equals(a))。 如果 B 是 A 的子类型,并且 A 的 equals 方法检查参数是 A 的实例,而 B 的 equals 方法检查参数是 B 的实例,则这些方法定义的等价关系很可能不是对称的。

产生原因

子类覆盖了父类中的equals方法,而两个类中都是用了instanceof来判断两个对象是否相等,这个操作存在风险。equals方法应该具有对称性(a.equals(b) == b.equals(a)),但是当B是A的子类时,A的equals方法检查参数是A的实例,B的equals方法检查参数是B的实例,则这些方法定义的equal关系很可能不是对称的。

解决办法

加上注解 @EqualsAndHashCode(callSuper = true)

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值