findbugs插件查出bug总结

1.用对象之前需要先判断对象是否为空

2.用equal判断值是否相等时,需要两者的数据类型是相同的,否则永远为假。如:将StringBuffer对象的值与空字符串【""】比较时为假(空字符串为String类型,两者类型不一样),且任何情况下,x.equals(null),永远返回是“false”;即x.equals(和x不同类型的对象)永远返回是“false”

3.ignores exceptional return value of java.io.File.mkdirs()

 忽略了返回值,应当含有返回值

后来我在调用.mkdirs()的地方加了try catch异常处理,即如果创建目录失败就抛出异常。【不知道是否是最佳方案,期待高手指点!】

 

4.Object   aObject   =   new   Object();   aObject   =   aPhoneBook.put("abc",   "123456");

用findbug檢查會出現Dead store to local variable的錯誤,他的意思是“本地变量存储了闲置不用的对象”

為什么會出現這個原因呢? 因為           Object   aObject   =   new   Object();  
  这一句执行3个动作:  
  1)创建一个引用  
  2)创建一个Object对象  
  3)把Ojbect的引用赋值给aObject  
   
  其中,后面两个动作是多余的,因为后面的程序中你没有使用这个新建的Object,而是重新给aObject赋值。

所以,只需要  
          Object   aObject;  
  就可以了  

 

5.FindBugs推荐使用Integer.ValueOf(int)代替new Integer(int),因为这样可以提高性能。如果当你的int值介于-128~127时,Integer.ValueOf(int)的效率比Integer(int)快大约3.5倍。

下面看看JDK的源码,看看到Integer.ValueOf(int)里面做了什么优化:

public   static  Integer valueOf( int  i) {
  
final   int  offset  =   128 ;
  
if  (i  >=   - 128   &&  i  <=   127 ) {  //  must cache
     return  IntegerCache.cache[i  +  offset];
  }
  
return   new  Integer(i);




private   static   class  IntegerCache {
  
private  IntegerCache(){}
    
  
static   final  Integer cache[]  =   new  Integer[ - ( - 128 +   127   +   1 ];
  
static  {
  
for ( int  i  =   0 ; i  <  cache.length; i ++ )
     cache 
=   new  Integer(i  -   128 );
  }
}

从源代码可以知道,ValueOf对-128~127这256个值做了缓存(IntegerCache),如果int值的范围是:-128~127,在ValueOf(int)时,他会直接返回IntegerCache的缓存给你。

所以你会看到这样的一个现象:

public   static   void  main(String []args) {
     Integer a 
=   100 ;
     Integer b 
=   100 ;
     System.out.println(a
== b);

     Integer c 
=   new  Integer( 100 );
     Integer d 
=   new  Integer( 100 );
     System.out.println(c
== d);
}

结果是:

true
false

因为:java在编译的时候 Integer a = 100; 被翻译成-> Integer a = Integer.valueOf(100);,所以a和b得到都是一个Cache对象,并且是同一个!而c和d是新创建的两个不同的对象,所以c自然不等于d。

 

再看看这段代码:

public   static   void  main(String args[])  throws  Exception{
        Integer a 
=   100 ;
        Integer b 
=  a;
        a 
=  a  +   1 ;  //或者a++;
        System.out.println(a
== b);
}
结果是:false

因为在对a操作时(a=a+1或者a++),a重新创建了一个对象,而b对应的还是缓存里的100,所以输出的结果为false。


6.makes inefficient use of keySet iterator instead of entrySet iterator【意思是说用keySet 方式遍历Map的性能不如entrySet性能好】
 
Set<Map.Entry<K,V>>entrySet()
          返回此映射中包含的映射关系的 Set 视图。

 

 Set<K>keySet()
          返回此映射中包含的键的 Set 视图。



第一种方式
Iterator<String> keySetIterator = keySetMap.keySet().iterator();
		while (keySetIterator.hasNext()) {
			String key = keySetIterator.next();
			String value = keySetMap.get(key);
			
		}


第二种方式
Iterator<Entry<String, String>> entryKeyIterator = entrySetMap.entrySet()
				.iterator();
		while (entryKeyIterator.hasNext()) {
			Entry<String, String> e = entryKeyIterator.next();
			String value=e.getValue();
		}

性能比较测试类:
 
public class HashMapTest {
	public static void main(String[] args) {

		HashMap<String, String> keySetMap = new HashMap<String, String>();
		HashMap<String, String> entrySetMap = new HashMap<String, String>();

		for (int i = 0; i < 1000; i++) {
			keySetMap.put("" + i, "keySet");
		}
		for (int i = 0; i < 1000; i++) {
			entrySetMap.put("" + i, "entrySet");
		}

		long startTimeOne = System.currentTimeMillis();
		Iterator<String> keySetIterator = keySetMap.keySet().iterator();
		while (keySetIterator.hasNext()) {
			String key = keySetIterator.next();
			String value = keySetMap.get(key);
			System.out.println(value);
		}

		System.out.println("keyset spent times:"
				+ (System.currentTimeMillis() - startTimeOne));

		long startTimeTwo = System.currentTimeMillis();

		Iterator<Entry<String, String>> entryKeyIterator = entrySetMap
				.entrySet().iterator();
		while (entryKeyIterator.hasNext()) {
			Entry<String, String> e = entryKeyIterator.next();
			System.out.println(e.getValue());
		}
		System.out.println("entrySet spent times:"
				+ (System.currentTimeMillis() - startTimeTwo));

	}
}


通过测试发现,第二种方式的性能通常要比第一种方式高一倍.

原因分析:

  通过查看源代码发现,调用这个方法keySetMap.keySet()会生成KeyIterator迭代器,其next方法只返回其key值.

 
Java代码
 private class KeyIterator extends HashIterator<K> {
        public K next() {
            return nextEntry().getKey();
        }
    }

而调用entrySetMap.entrySet()方法会生成EntryIterator 迭代器,其next方法返回一个Entry对象的一个实例,其中包含key和value.

 
Java代码
 private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
  }

二者在此时的性能应该是相同的,但方式一再取得key所对应的value时,此时还要访问Map的这个方法,这时,方式一多遍历了一次table.

Java代码
public V get(Object key) {
        Object k = maskNull(key);
        int hash = hash(k);
        int i = indexFor(hash, table.length);
        Entry<K,V> e = table[i]; 
        while (true) {
            if (e == null)
                return null;
            if (e.hash == hash && eq(k, e.key)) 
                return e.value;
            e = e.next;
        }
    }

这个方法就是二者性能差别的主要原因.




  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值