注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

淡泊明智

 
 
 

日志

 
 

从 FingBugs的错误来看JAVA代码质量(一)  

2012-11-16 14:51:37|  分类: 代码质量 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
JAVA代码质量
JavaITeyeperformanceSecurity
错误码:WMI_WRONG_MAP_ITERATOR
案例一: 
从 FingBugs的错误来看JAVA代码质量(一) - 火木棉 - 淡泊明智
 
案例二: 
从 FingBugs的错误来看JAVA代码质量(一) - 火木棉 - 淡泊明智
 
Bug: Method JTAMainFrame.initView(JFrame) makes inefficient use of keySet iterator instead of entrySet iterator
Pattern id: WMI_WRONG_MAP_ITERATOR, type: WMI, category: PERFORMANCE
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.
解释:
很多人都这样遍历Map,没错,但是效率很低,先一个一个的把key遍历,然后在根据key去查找value,这不是多此一举么,为什么不遍历entry(桶)然后直接从entry得到value呢?它们的执行效率大概为1.5:1(有人实际测试过)。
我们看看HashMap.get方法的源代码:
Java代码 复制代码 收藏代码从 FingBugs的错误来看JAVA代码质量(一) - 火木棉 - 淡泊明智
1.  public V get(Object key) {     
2.      if (key == null)     
3.          return getForNullKey();     
4.      int hash = hash(key.hashCode());     
5.      for (Entry<K,V> e = table[indexFor(hash, table.length)];     
6.           e != null;     
7.           e = e.next) {     
8.          Object k;     
9.          if (e.hash == hash && ((k = e.key) == key || key.equals(k)))     
10.             return e.value;     
11.     }     
12.     return null;     
13. }    
从这里可以看出查找value的原理,先计算出hashcode,然后散列表里取出entry(类似2次循环查找,不管是计算hashcode,还是执行循环for以及执行equals方法,都是CPU密集运算,非常耗费CPU资源,如果对一个比较大的map进行遍历,会出现CPU迅速飚高的现象,直接影响机器的响应速度,在并发的情况下,简直就是一场灾难。
解决方法:
Java代码 复制代码 收藏代码从 FingBugs的错误来看JAVA代码质量(一) - 火木棉 - 淡泊明智
1.  for (Map.Entry<String, JMenu> entry : menuList.entrySet()) {     
2.      mb.add(entry.getValue());   
}  
 
从 FingBugs的错误来看JAVA代码质量(一) - 火木棉 - 淡泊明智
 
错误码:EI_EXPOSE_REP2
案例 
从 FingBugs的错误来看JAVA代码质量(一) - 火木棉 - 淡泊明智

 
Bug: SingleNePollConfigDialog.collectValues(Hashtable) may expose internal representation by storing an externally mutable object into SingleNePollConfigDialog.values
Pattern id: EI_EXPOSE_REP2, type: EI2, category: MALICIOUS_CODE
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.
翻译愿意:
此代码存储到一个到对象的内部表示外部可变对象的引用。如果实例是由不受信任的代码,并以可变对象会危及安全或其他重要的属性选中更改访问,你需要做不同的东西。存储一个对象的副本,在许多情况下是更好的办法。
解释:
DO类实例产生之后,里面包含的Date不是原始数据类型,导致其gmtCrate属性不光DO实例的set方法可以改变其值,外部引用修改之后也可能导致gmtCreate 被改变,会引起可能的不安全或者错误。
这个是一个不好的实践,不过我们应用里面DO都是比较简单使用,不太会出现这种情况。
解决方法:
修改成:
Java代码 复制代码 收藏代码从 FingBugs的错误来看JAVA代码质量(一) - 火木棉 - 淡泊明智
public Date getGmtCreate() {   
        if(this.gmtCreate != null)   
           return new Date(this.gmtCreate.getTime()); //正确值   
        else    
            return null;   
}  


总结:这个其实是说可变类和不可变类的问题,
可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容。
不可变类:当你获得这个类的一个实例引用时,你不可以改变这个实例的内容。不可变类 的实例一但创建,其内在成员变量的值就不能被修改 ;
DO是一个可变类,但是最好是只提供set方法才能改变其实例的的成员变量的值,减少被修改的风险。

  评论这张
 
阅读(291)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018