99热99这里只有精品6国产,亚洲中文字幕在线天天更新,在线观看亚洲精品国产福利片 ,久久久久综合网

歡迎加入QQ討論群258996829
麥子學(xué)院 頭像
蘋果6袋
6
麥子學(xué)院

Java程序猿最常犯的10個錯誤,你犯過嗎?

發(fā)布時間:2016-12-16 21:37  回復(fù):0  查看:2338   最后回復(fù):2016-12-16 21:37  

本文和大家分享的主要是java開發(fā)中常見的10種最易犯的錯誤,你有沒有犯過其中的一種或幾種錯誤呢?一起來看看吧。

  一、把數(shù)組轉(zhuǎn)成ArrayList

  為了將數(shù)組轉(zhuǎn)換為ArrayList,開發(fā)者經(jīng)常會這樣做:

  1. Listlist = Arrays.asList(arr);

  使用Arrays.asList()方法可以得到一個ArrayList,但是得到這個ArrayList其實是定義在Arrays類中的一個私有的靜態(tài)內(nèi)部類。這 個類雖然和java.util.ArrayList同名,但是并不是同一個類。java.util.Arrays.ArrayList類中實現(xiàn)了set(),

  get(),

  contains()等方法,但是并沒有定義向其中增加元素的方法。也就是說通過Arrays.asList()得到的ArrayList的大小是固定的。

  如果在開發(fā)過程中,想得到一個真正的ArrayList對象(java.util.ArrayList的實例),可以通過以下方式:

  1. ArrayListarrayList = new ArrayList(Arrays.asList(arr));

  java.util.ArrayList中包含一個可以接受集合類型參數(shù)的構(gòu)造函數(shù)。因為java.util.Arrays.ArrayList這個內(nèi)部類繼承了AbstractList類,所以,該類也是Collection的子類。

  二、判斷一個數(shù)組是否包含某個值

  在判斷一個數(shù)組中是否包含某個值的時候,開發(fā)者經(jīng)常這樣做:

  1. Setset = new HashSet(Arrays.asList(arr));

  2. return set.contains(targetValue);

  在在Java中如何高效的判斷數(shù)組中是否包含某個元素一文中,深入分析過,以上方式 雖然可以實現(xiàn)功能,但是效率卻比較低。因為將數(shù)組壓入Collection類型中,首先要將數(shù)組元素遍歷一遍,然后再使用集合類做其他操作。

  在判斷一個數(shù)組是否包含某個值的時候,推薦使用for循環(huán)遍歷的形式或者使用Apache

  Commons類庫中提供的ArrayUtils類的contains方法。

  三、在循環(huán)中刪除列表中的元素

  在討論這個問題之前,先考慮以下代碼的輸出結(jié)果:

  1. ArrayListlist = new ArrayList(Arrays.asList("a","b","c","d"));

  2. for(int i=0;i<list.size();i++){

  3. list.remove(i);

  4. }

  5. System.out.println(list);

  輸出結(jié)果:

  1. [b,d]

  以上代碼的目的是想遍歷刪除list中所有元素,但是結(jié)果卻沒有成功。原因是忽略了一個關(guān)鍵的問題:當(dāng)一個元素被刪除時,列表的大小縮小并且下標(biāo)也會隨之變化,所以當(dāng)你想要在一個循環(huán)中用下標(biāo)刪除多個元素的時候,它并不會正常的生效。

  也有些人知道以上代碼的問題就由于數(shù)組下標(biāo)變換引起的。所以,他們想到使用增強for循環(huán)的形式:

  1. ArrayListlist = new ArrayList(Arrays.asList("a","b","c","d"));

  2. for(String s:list){

  3. if(s.equals("a")){

  4. list.remove(s);

  5. }

  6. }

  但是,很不幸的是,以上代碼會拋出ConcurrentModificationException,有趣的是,如果在remove操作后增加一個break,代碼就不會報錯:

  1. ArrayListlist = new ArrayList(Arrays.asList("a","b","c","d"));

  2. for(String s:list){

  3. if(s.equals("a")){

  4. list.remove(s);

  5. break;

  6. }

  7. }

  在Java中的fail-fast機制一文中,深入分析了幾種在遍歷數(shù)組的同時刪除其中元素的方法以及各種方法存在的問題。其中就介紹了上面的代碼出錯的原因。

  迭代器(Iterator)是工作在一個獨立的線程中,并且擁有一個 mutex 鎖。

  迭代器被創(chuàng)建之后會建立一個指向原來對象的單鏈索引表,當(dāng)原來的對象數(shù)量發(fā)生變化時,這個索引表的內(nèi)容不會同步改變,所以當(dāng)索引指針往后移動的時候就找不到要迭代的對象,所以按照

  fail-fast 原則

  迭代器會馬上拋出java.util.ConcurrentModificationException 異常。

  所以,正確的在遍歷過程中刪除元素的方法應(yīng)該是使用Iterator

  1. ArrayListlist = new ArrayList(Arrays.asList("a", "b", "c", "d"));

  2. Iteratoriter = list.iterator();

  3. while (iter.hasNext()) {

  4. String s = iter.next();

  5.

  6. if (s.equals("a")) {

  7. iter.remove();

  8. }

  9. }

  next()方法必須在調(diào)用remove()方法之前調(diào)用。如果在循環(huán)過程中先調(diào)用remove(),再調(diào)用next(),就會導(dǎo)致異常ConcurrentModificationException。原因如上。

  四、HashTable 和 HashMap 的選擇

  了解算法的人可能對HashTable比較熟悉,因為他是一個數(shù)據(jù)結(jié)構(gòu)的名字。但在Java里邊,用HashMap來表示這樣的數(shù)據(jù)結(jié)構(gòu)。Hashtable 

  HashMap的一個關(guān)鍵性的不同是,HashTable是同步的,而HashMap不是。所以通常不需要HashTable,HashMap用的更多。

  HashMap完全解讀、Java中常見親屬比較等文章中介紹了他們的區(qū)別和如何選擇。

  五、使用原始集合類型

  在Java里邊,原始類型和無界通配符類型很容易混合在一起。以Set為例,Set是一個原始類型,而Set<

  ? >是一個無界通配符類型。

 ?。梢园言碱愋屠斫鉃闆]有使用泛型約束的類型)

  考慮下面使用原始類型List作為參數(shù)的代碼:

  1. public static void add(List list, Object o){

  2. list.add(o);

  3. }

  4. public static void main(String[] args){

  5. Listlist = new ArrayList();

  6. add(list, 10);

  7. String s = list.get(0);

  8. }

  上面的代碼將會拋出異常:

  java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

  使用原始集合類型是很危險的,因為原始集合類型跳過了泛型類型檢查,是不安全的。Set、Set<

  ? >Set< Object

  六、訪問級別

  程序員們經(jīng)常使用public作為類中的字段的修飾符,因為這樣可以很簡單的通過引用得到值,但這并不是好的設(shè)計,按照經(jīng)驗,分配給成員變量的訪問級別應(yīng)該盡可能的低。參考Java中的四種訪問級別

  七、ArrayListLinkedList的選擇

  當(dāng)程序員們不知道ArrayListLinkedList的區(qū)別時,他們經(jīng)常使用ArrayList,因為它看起來比較熟悉。然而,它們之前有巨大的性能差別。在ArrayList vs LinkedList vs Vector區(qū)別、Java中常見親屬比較等文章中介紹過,簡而言之,如果有大量的增加刪除操作并且沒有很多的隨機訪問元素的操作,應(yīng)該首先LinkedList。

  八、可變與不可變

  在為什么Java要把字符串設(shè)計成不可變的一文中介紹過,不可變對象有許多的優(yōu)點, 比如簡單,安全等等。同時,也有人提出疑問:既然不可變有這么多好處,為什么不把所有類都搞成不可變的呢?

  通常情況下,可變對象可以用來避免產(chǎn)生過多的中間對象。一個經(jīng)典的實例就是連接大量的字符串,如果使用不可變的字符串,將會產(chǎn)生大量的需要進行垃圾回收的對象。這會浪費CPU大量的時間,使用可變對象才是正確的方案(比如StringBuilder)

  1. String result="";

  2. for(String s: arr){

  3. result = result + s;

  4. }

  九、父類和子類的構(gòu)造函數(shù)

  上圖的代碼中有兩處編譯時錯誤,原因其實很簡單,主要和構(gòu)造函數(shù)有關(guān)。首先,我們都知道:

  如果一個類沒有定義構(gòu)造函數(shù),編譯器將會插入一個無參數(shù)的默認構(gòu)造函數(shù)。

  如果一個類中定義了一個帶參數(shù)的構(gòu)造函數(shù),那么編譯器就不會再幫我們創(chuàng)建無參的構(gòu)造函數(shù)。

  上面的Super類中定義了一個帶參數(shù)的構(gòu)造函數(shù)。編譯器將不會插入默認的無參數(shù)構(gòu)造函數(shù)。

  我們還應(yīng)該知道:

  子類的所有構(gòu)造函數(shù)(無論是有參還是無參)在執(zhí)行時,都會調(diào)用父類的無參構(gòu)造函數(shù)。

  所以,編譯器試圖調(diào)用Super類中的無參構(gòu)造函數(shù)。但是父類默認的構(gòu)造函數(shù)未定義,編譯器就會報出這個錯誤信息。

  要解決這個問題,可以簡單的通過

  1)在父類中添加一個Super()構(gòu)造方法,就像這樣:

  public Super(){}

  2)移除自定義的父類構(gòu)造函數(shù)

  3)在子類的構(gòu)造函數(shù)中調(diào)用父類的super(value)

  十、””還是構(gòu)造函數(shù)

  關(guān)于這個問題,也是程序員經(jīng)常出現(xiàn)困惑的地方,在該如何創(chuàng)建字符串,使用

  還是構(gòu)造函數(shù)?中也介紹過.

  如果你只需要創(chuàng)建一個字符串,你可以使用雙引號的方式,如果你需要在堆中創(chuàng)建一個新的對象,你可以選擇構(gòu)造函數(shù)的方式。

  在String d = new String("abcd")時,因為字面值“abcd”已經(jīng)是字符串類型,那么使用構(gòu)造函數(shù)方式只會創(chuàng)建一個額外沒有用處的對 象。

您還未登錄,請先登錄

熱門帖子

最新帖子

?