最近使用findbugs分析了最近做过的一个project,发现自己写的代码出现好多问题,在这里做一个小小的总结。
下面是针对我的代码中出现的bug结合网络做了一下分析学习,借助Google翻译,感觉翻译的仍然很别扭。
May expose internal representation by incorporating reference to mutable
object.This code stores a reference to an externally mutable
object into 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.
Storing a copy of the object is better approach in many situations.
可能因使引用可指向多个对象而暴露内部存储结构。
这代码使一个指向外部多个对象的引用指向了一个内部对象存储地址。
如果实例被未被信任代码访问或多个对象发生了未经检查的改变就会危及安全性或其它重要属性,
你需要去做一些不同的事情。存储一个对象的拷贝在许多情况下会是一个更好的方法。
网上findbug使用的介绍文章中写到,按下面修改findbug就没bug提示了,
为什么要放到一个临时变量中就可以了?
- public class Test {
- private String[] name;
- public String[] getName() {
- String[] temp = name;
- return temp;
- }
- public void setName(String[] name) {
- String[] temp = name;
- this.name = temp;
- }
- }
因为代码中会经常出现getter/setter,我觉得这个bug是不必要进行修改的。
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.
本地变量存储了闲置不用的对象,也就是说这个变量是多余的。
Hashtable hTable = new Hashtable();
Object obj = new Object();
obj = hTable.put("uuid", "abcd1234");
- String abc = "abc";
- String xyz = new String("");
- xyz = abc;
- System.out.println(xyz);
用findbug檢查會出現Dead store to local variable的錯誤,他的意思是“本地变量存储了闲置不用的对象”
為什么會出現這個原因呢? 因為 String xyz = new String("");
这一句执行3个动作:
1)创建一个引用xyz
2)创建一个String对象
3)把String的引用赋值给xyz
其中,后面两个动作是多余的,因为后面的程序中你没有使用这个新建的String对象,而是重新给xyz赋值,
xyz = abc;所以,只需要String xyz = abc; 就可以了。这样,findbugs就不会报了。
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.
向static字段中写入值,如:
- private static Logger logger;
- public XXXActionCtrl(){
- logger = Logger.getLogger(getClass());
- }
- 可改为:private static Logger logger = Logger.getLogger(getClass());
Unread field: should this field be static?
This class contains an instance final field that is initialized to a compile-time static value. Consider
making the field static.
未读的领域:这个领域应该是静态的?
这个类包含一个实例的最后字段初始化为编译时静态值。考虑静态的领域。(findbugs建议修改该属性为static的)。
如:private final String FAIL_FLAG = "exit";
改为:private static final String FAIL_FLAG = "exit";
Unread field
This field is never read. Consider removing it from the class.
未读的领域(字段,属性)
类中声明了从未用过的字段。考虑从类中删除。
Method concatenates strings using + in a loop
The method seems to be building a String using concatenation in a loop. In each iteration, the String is
converted to a StringBuffer/StringBuilder, appended to, and converted back to a String. This can lead to a
cost quadratic in the number of iterations, as the growing string is recopied in each iteration.
Better performance can be obtained by using a StringBuffer (or StringBuilder in Java 1.5) explicitly.
字符串串联使用方法在一个循环+
该方法似乎是建立在循环使用字符串串联。在每次迭代中,字符串转换为一个StringBuffer / StringBuilder的,附加到
,并转换回为String。这可能导致成本的二次迭代,因为不断增长的字符串是在每次迭代中重新复制。
更好的性能,可使用StringBuffer(或StringBuilder的)会更好一些。
- For example:
- // This is bad
- String s = "";
- for (int i = 0; i < field.length; ++i) {
- s = s + field[i];
- }
- // This is better
- StringBuffer buf = new StringBuffer();
- for (int i = 0; i < field.length; ++i) {
- buf.append(field[i]);
- }
- String s = buf.toString();
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迭代器。
使用entrySet效率会比keySet高。
keySet()迭代后只能通过get()取key。
entrySet()迭代后可以e.getKey(),e.getValue()取key和value,返回的是Entry接口。
Field isn't final but should be.
A mutable static field could be changed by malicious code or by accident from another package. The field
could be made final to avoid this vulnerability.
字段应该声明为final,实际上却未声明final。
一个易变的static字段可以被恶意代码改变,使用final关键字以避免此漏洞。
Call to equals() with null argument.
This method calls equals(Object), passing a null value as the argument. According to the contract of the equals() method, this call should always return false.
使用null参数调用equals()。
此方法调用等于(对象),作为参数传递一个空值。根据合同的equals()方法,此调用应始终返回false。
如:queryStr.equals(null); 这样使用是不可取的,虽然能够通过编译。
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方法
将数组转化为一个可读的给出数组内容的字符串。
比如:在使用System.out.println(xx.readNext());时候会碰到这样的提示,readNext() 方法放回一个String[]。
可改为:
String[] arr = reader.readNext();
System.out.println(Arrays.asList(arr).toString());
(好像有点麻烦,没想到更简洁的办法)。
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.
此代码之前废弃null值检查。
一个值被选中这里看它是否是空的,但这个值不能为空,因为它在此之前废弃null值检查,而且如果它为null,空指针异
常将会发生在此处,如果它是空一空指针异常会发生在较早取消引用。
从本质上讲,此代码和前边废弃的null值检查将会出现不一致,是否这个值是容许
空。
出现该bug有两种情况:多余的null检查;前边废弃null值检查的。
比如:我们经常会这个使用ActionForm,
String clazzId = request.getParameter("clazzId");// script1
studentForm.setClazzID(clazzId);// script2
往往会在script2会出现该错误,因为在script1出未检查clazzId是否为null才导致的。
修改为 :
if(clazzId != null) {
studentForm.setClazzID(clazzId);
}
在设置使用clazzId之前先判断其是否为null。
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值检查,可能会导致后面的代码出现空指针异常。如:
- md = null;
- try {
- md = MessageDigest.getInstance("SHA-256");
- md.update(bt);
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();// script1
- }
- byte[] digest = md.digest();// script2
- bug出现在script2处,在script1处处理相应的exception即可,如throw 或 return;
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.
可能的空指针引用。
如在JDBC编程时候,在关闭ResultSet时候(rs.close()),经常会出现这个bug,解决办法很容易想到,判断是否为null或
使用try...catch...finally。
Call to equals() comparing different types
This method calls equals(Object) on two references of different class types with no common subclasses.
Therefore, the objects being compared are unlikely to be members of the same class at runtime (unless some
application classes were not analyzed, or dynamic class loading can occur at runtime). According to the
contract of equals(), objects of different classes should always compare as unequal; therefore, according
to the contract defined by java.lang.Object.equals(Object), the result of this comparison will always be
false at runtime.
调用equals()比较不同的类型。
此方法调用相当于两个不同的类类型的引用,没有共同的子类(对象)。
因此,所比较的对象是不太可能在运行时相同的类成员(除非一些
应用类没有分析或动态类加载可以发生在运行时)。据
equals()的规则,不同类的对象应始终比较不平等,因此,根据
由java.lang.Object.equals定义的合同(对象),FALSE将永远是比较的结果
在运行时错误。
。。。