转自 : http://my.oschina.net/hoodlake/blog/126735
说明:
1.Bug是findbug Eclipse插件原生的bug信息描述,Confidence 是fingbug团队认为该代码导致bug的可能性。
2.以下都是我使用findbug在公司项目中找到的一些bug,这里做一些中文的简短说明(不是翻译)
3.篇幅可能会有点长,阅读时,大家可以通过ctrl+f根据关键字查找自己相关的bug
BUG-0001
Bug: Field only ever set to null: com.bettersoft.admin.BtCorpManager.ps
All writes to this field are of the constant value null, and thus all reads of the field will return null. Check for errors, or remove it if it is useless.
Confidence: Normal, Rank: Troubling (12)
Pattern: UWF_NULL_FIELD
Type: UwF, Category: CORRECTNESS (Correctness)
代码片段:
public class BtCorpManager { private BtCorp btcorp=null; private Connection con = null; private Statement st = null; private PreparedStatement ps = null; private ResultSet rs = null; private void setConnection(String centerno) throws Exception{ //con = DBManager.getConnection(centerno); con = DBManager.getConnection(); }
解释说明:在BtCorpManager类里面定了一个私有的成员变量PreparedStatement ps,但是这个成员变量ps在实例范围内没有得到任何的初始化(采用默认的构造方法),始终为null,所以在实例范围内使用该成员变量时,如果不先对其进行初始化操作或者无意识的行为忘了初始化操作,那肯定是要报空指针异常,所以这无疑是一个bug
推荐修改: 自己看着办
BUG-0002
Bug: Nullcheck of form at line 36 of value previously dereferenced in com.bettersoft.admin.CorpEditAction.execute(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse)
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.
Confidence: High, Rank: Scary (9)
Pattern: RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE
Type: RCN, Category: CORRECTNESS (Correctness)
代码片段:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { //throw new UnsupportedOperationException("Method is not implemented"); ActionErrors errors = new ActionErrors(); CreateCorpActionForm createCorp = new CreateCorpActionForm(); createCorp = (CreateCorpActionForm)form; CreateCorpActionForm webcorp=new CreateCorpActionForm(); BudgetWebcorpManager budgetWebcorpManager=new BudgetWebcorpManager(); webcorp=budgetWebcorpManager.getCWebcorp(createCorp.getId()); createCorp.setFbsaddapproveid(webcorp.getFbsaddapproveid()); createCorp.setFbsinputapproveid(webcorp.getFbsinputapproveid()); createCorp.setFbsprocessapproveid(webcorp.getFbsprocessapproveid()); boolean b=false; if(createCorp!=null){
解释说明:注意到有个局部变量 CreateCorpActionForm createCorp;再看下它的初始化过程,先是通过new给它分配了内存空间,紧接着有让它引用了了另一个未知的变量,这里说未知是指这个新的引用可能为空,显然 createCorp有可能指向一个空的地址,所以在接下来的引用中极可能报空指针异常(在引用之前不进行判空操作的话)! 在接下来的代码,如下
if(createCorp!=null){
其实也就没有存在的必要,因为如果为空的话,上面这行代码根本不可能执行到,所以findbug说这是冗余的空指针检查。当然考虑到特殊情况,这里显然是struts1的action,所以只要web应用正常启动,通常以下代码
createCorp = (CreateCorpActionForm)form;
是不会导致createCorp指向空的,唯一的缺陷就是之前的new操作是多余的。
推荐修改:自己看着办
BUG-0003
Bug: con is null guaranteed to be dereferenced in com.bettersoft.admin.leftAction.getLeft(int, String, String) 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).
Confidence: Normal, Rank: (Troubling 11)
Pattern: NP_GUARANTEED_DEREF_ON_EXCEPTION_PATH
Type: NP, Category: CORRECTNESS (Correctness)
代码片段:
finally { try { if(rs != null) rs.close(); if(ps!=null) ps.close(); con.close(); }catch(Exception ee) { ee.printStackTrace(); } }
解释说明:这应该是大家很熟悉的代码片段了,可以想象Connection con是在catch代码块中进行的初始化操作,findbug对该bug说的很明白,说如果出现异常,Connection con将保证为空,因为很显然如果出现异常,con将得不到正确的初始化,即便初始化了,因为异常的出现,引用也会被解除,回到一开始定义处的null状态,那么在这里的finally代码块中调用Connection con的close()方法,将报空指针异常
推荐修改:自己看着办
BUG-0004
Bug: Possible null pointer dereference of dbVersion in com.bettersoft.admin.LoginAction.loadVersion(HttpServletRequest, ActionErrors) on exception path
A reference value which is null on some exception control path is dereferenced here. This may lead to aNullPointerExceptionwhen 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.
Confidence: Normal, Rank: Troubling (11)
Pattern: NP_NULL_ON_SOME_PATH_EXCEPTION
Type: NP, Category: CORRECTNESS (Correctness)
代码片段:
VersionInfo dbVersion = null; try { con = DBManager.getConnection(); dbVersion = vm.getVersionInfo(con); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { try { con.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (dbVersion.equals(programVersion)) { programVersion.setCorrent(true); } else { programVersion.setCorrent(false); }
解释说明:如果try catch 中捕获异常,那么dbVersion将为空,
dbVersion.equals(programVersion)
上面这行代码,将报空指针异常
BUG-0005
Bug: Dead store to am in com.bettersoft.approve.action.CheckAction.execute(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse)
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.
Confidence: High, Rank: Of Concern (15)
Pattern: DLS_DEAD_LOCAL_STORE
Type: DLS, Category: STYLE (Dodgy code)
代码片段:
ApproveManager am = new ApproveManager();
解释说明:am这个局部变量创建出来后,没有在任何地方被引用。这里确实没有被引用,所以是个bug,但是findbug又说明了,这有可能是误报,因为javac编译器在编译局部常量时,也会产生dead stroes。所以这个要视情况而定,不能过于纠结
BUG-0006
Bug: The class name com.bettersoft.approve.form.BtWebCorp shadows the simple name of the superclass com.bettersoft.admin.BtWebCorp
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.Fooextendsbeta.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 accidently define methods that do not override methods in their superclasses.
Confidence: High, Rank: Troubling (14)
Pattern: NM_SAME_SIMPLE_NAME_AS_SUPERCLASS
Type: Nm, Category: BAD_PRACTICE (Bad practice)
代码片段:
public class BtWebCorp extends com.bettersoft.admin.BtWebCorp{ }
解释说明:这里子类和父类名称一样,findbug认为这回导致很多混淆。显然一旦出问题,将很难发现,运行结果将出乎意料
BUG-0007
Bug: Comparison of String objects using == or != in com.byttersoft.admin.persistence.dao.MessageOpenDao.addOpenSave(MessageOpenForm)
This code comparesjava.lang.Stringobjects for reference equality using the == or != operators. Unless both strings are either constants in a source file, or have been interned using theString.intern()method, the same string value may be represented by two different String objects. Consider using theequals(Object)method instead.
Confidence: Normal, Rank: Troubling (11)
Pattern: ES_COMPARING_STRINGS_WITH_EQ
Type: ES, Category: BAD_PRACTICE (Bad practice)
代码片段:
if(id==null || id==""){ sql = "insert into xx values (1,?,?,?)"; }else{ sql = "insert into xx values ((select max(id) + 1 from xx),?,?,?)"; }
解释说明: 直接使用==进行对象实例比较,而没有使用equals,本来没觉得这个bug咋样,但是发现项目里居然最多的bug就是这个,不管是很多年前的代码还是最近的代码,都存在这大量这样的问题。看来这是一个通病,所以大家注意一下,不光是我们公司的项目有这样的问题,这应该是一个普遍的问题,尤其实在比较String类型的时候,注意只要不是java基本类型都需要使用equals进行比较,哪怕是自动解封的Integer,Double等
BUG-0008
Bug: Call to String.equals(Double) in com.byttersoft.amm.util.BalanceInterzoneRateUtil.formatRate(Double)
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.
Confidence: High, Rank: Scariest (1)
Pattern: EC_UNRELATED_TYPES
Type: EC, Category: CORRECTNESS (Correctness)
代码片段:
private static String formatRate(Double r){ if(r==null || ("undefined").equals(r)){ return null; }
解释说明:使用equals比较不同类型的数据,"undefined"是String类型,r是Double类型,这两个比较肯定返回false
("undefined").equals(r)
上面这行代码完全没有必要 ,不可能存在这种情况
BUG-0009
Bug: Class com.byttersoft.util.CertInfo defines non-transient non-serializable instance field subjectDnAttr
This Serializable class defines a non-primitive instance field which is neither transient, Serializable, orjava.lang.Object, and does not appear to implement theExternalizableinterface or thereadObject()andwriteObject()methods. Objects of this class will not be deserialized correctly if a non-Serializable object is stored in this field.
Confidence: High, Rank: Troubling (14)
Pattern: SE_BAD_FIELD
Type: Se, Category: BAD_PRACTICE (Bad practice)
代码片段:
public class CertInfo implements java.io.Serializable { private String subjectDN=""; private String issuerDN=""; private String notAfterDate=""; private String notBeforeDate=""; private String serialNumber=""; private String sigAlgName=""; private String sigAlgOID=""; private String version=""; private String publicKeyFormat=""; private String publicKeyAlgorithm=""; private Names subjectDnAttr=null; } public class Names {}
解释说明: CertInfo实现的序列话,但是他的成员变量Names subjectDnAttr没有实现序列化,这将会导致序列化失败,String已经默认实现了序列化。注意,序列化时所有的成员变量都必须递归的实现序列化,否则将导致序列化失败。如果某个成员变量不想被序列化要么标注为瞬态要么重写readObj方法
BUG-0010
Bug: Dead store to corpGourps rather than field with same name in com.byttersoft.admin.form.CorpGroupsForm.setCorpGourps(CorpGourps)
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. There is a field with the same name as the local variable. Did you mean to assign to that variable instead?
Confidence: High, Rank: Scary (9)
Pattern: DLS_DEAD_LOCAL_STORE_SHADOWS_FIELD
Type: DLS, Category: STYLE (Dodgy code)
代码片段:
public void setCorpGourps(CorpGourps corpGourps) { corpGourps = corpGourps; }
解释说明:成员变量和局部变量重名
BUG-0011
Bug: Invocation of toString on labelValue in com.byttersoft.approve.persistence.dao.MesAppDao.getMapByPara(String)
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.
Confidence: Normal, Rank: Troubling (10)
Pattern: DMI_INVOKING_TOSTRING_ON_ARRAY
Type: USELESS_STRING, Category: CORRECTNESS (Correctness)
代码片段:
for (String parameter : parameters) { String[] labelValue = parameter.split("="); if (labelValue.length == 2) { String key = labelValue[0]; String value = labelValue[1]; hashMap.put(key, value); } else { logger.debug("参数 " + labelValue + " 配置错误。"); } }
解释说明:在进行日志输出时,直接输出对象,将默认调用对象的toString方法,而默认是输出对象的内存地址,所以这里显然有问题,本意应该是输出数组中的字符串
BUG-0012
Bug: Write to static field com.byttersoft.admin.service.BtSysResService.map from instance method com.byttersoft.admin.service.BtSysResService.hashCatchOfSysRes(boolean)
This instance method writes to a static field. This is tricky to get correct if multiple instances are being manipulated, and generally bad practice.
Confidence: High, Rank: Of Concern (15)
Pattern: ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD
Type: ST, Category: STYLE (Dodgy code)
代码片段:
static Map<String, BtSysRes> map = new HashMap<String, BtSysRes>(); public Map<String, BtSysRes> hashCatchOfSysRes(boolean isRefresh) { if(isRefresh == true){ map = hashCatchOfSysRes(); }else{ if(map == null || map.isEmpty()){ map = hashCatchOfSysRes(); } } return map; }
解释说明:在实例方法中修改类变量的引用,这会导致共享问题,因为其他实例也会访问该静态变量,但是却不知道某个实例已经修改了该静态变量的引用,导致不可预知的问题
推荐修改:将该方法改为类方法
BUG-0013
Bug: Unwritten field: com.byttersoft.admin.service.importservice.ImportServices.bank
This field is never written. All reads of it will return the default value. Check for errors (should it have been initialized?), or remove it if it is useless.
Confidence: Normal, Rank: Troubling (12)
Pattern: UWF_UNWRITTEN_FIELD
Type: UwF, Category: CORRECTNESS (Correctness)
代码片段:
public class ImportServices { private IBankAccServices bank; public IBankAccServices getBank() { return bank; } }
解释说明: bank对象为空,getBank方法返回了一个肯定为空的对象实例
BUG-0014
Bug: There is an apparent infinite recursive loop in com.byttersoft.amm.dao.impl.CheckLoanOrProvideInfoDaoImpl.addBatch(List)
This method unconditionally invokes itself. This would seem to indicate an infinite recursive loop that will result in a stack overflow.
Confidence: High, Rank: Scary (9)
Pattern: IL_INFINITE_RECURSIVE_LOOP
Type: IL, Category: CORRECTNESS (Correctness)
代码片段:
public void addBatch(List<CmsPLoanToBean> cmsPLoanBeans) { this.addBatch(cmsPLoanBeans); }
解释说明:出现了递归调用addBatch,将出现死循环