10個 Java 開發(fā)者常犯的錯誤

  1. 把數(shù)組轉(zhuǎn)成ArrayList

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

List<String> list = 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的實例)圈膏,可以通過以下方式:

ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

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

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

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

Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);

以上方式雖然可以實現(xiàn)功能,但是效率卻比較低老虫。因為將數(shù)組壓入Collection類型中叶骨,首先要將數(shù)組元素遍歷一遍,然后再使用集合類做其他操作祈匙『龉簦可以使用下面方式實現(xiàn):

Arrays.asList(arr).contains(targetValue);

或者

for(String s: arr){
    if(s.equals(targetValue))
        return true;
}
return false;
  1. 在循環(huán)中刪除列表中的元素

先看看下面這段循環(huán)中移除元素的代碼:

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(int i=0;i<list.size();i++){
    list.remove(i);
}
System.out.println(list);

輸出結(jié)果:

[b,d]

這個方法出現(xiàn)了1個嚴重的問題天揖,當一個元素被刪除時,列表的大小縮小并且下標也會隨之變化跪帝,所以當你想要在一個循環(huán)中用下標刪除多個元素的時候今膊,它并不會正常的生效。

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

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(String s:list){
    if(s.equals("a")){
        list.remove(s);
    }
}

但是,很不幸的是黎泣,以上代碼會拋出ConcurrentModificationException恕刘。

想實現(xiàn)這個功能,可以使用如下代碼:

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String s = iter.next();
 
    if (s.equals("a")) {
        iter.remove();
    }
}

next()方法必須在調(diào)用remove()方法之前調(diào)用抒倚。第1個示例褐着,使用了foreach,編譯器會調(diào)用.next()方法托呕,正是這個方法拋出的ConcurrentModificationException含蓉,感興趣的可以看一下 ArrayList.iterator() 的源碼。

  1. HashTable 和 HashMap 的選擇

了解算法的人可能對HashTable比較熟悉项郊,因為他是一個數(shù)據(jù)結(jié)構(gòu)的名字谴餐。但在Java里邊,用HashMap來表示這樣的數(shù)據(jù)結(jié)構(gòu)呆抑。Hashtable和 HashMap的一個關鍵性的不同是岂嗓,HashTable是同步的,而HashMap不是鹊碍。所以通常不需要HashTable厌殉,HashMap用的更多。

  1. 使用原始集合類型

在Java里邊侈咕,原始類型和無界通配符類型很容易混合在一起公罕。以Set為例,Set是一個原始類型耀销,而Set< ? >是一個無界通配符類型楼眷。 (可以把原始類型理解為沒有使用泛型約束的類型)

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

public static void add(List list, Object o){
    list.add(o);
}
public static void main(String[] args){
    List<String> list = new ArrayList<String>();
    add(list, 10);
    String s = list.get(0);
}

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

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

使用原始集合類型是很危險的,因為原始集合類型跳過了泛型類型檢查熊尉,是不安全的罐柳。Set、Set< ? >和Set< Object >之間有很大差別狰住。

  1. 訪問級別

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

  1. ArrayListLinkedList的選擇

當程序員們不知道ArrayListLinkedList的區(qū)別時,他們經(jīng)常使用ArrayList伦忠,因為它看起來比較熟悉省核。然而,它們之間有巨大的性能差別昆码。簡而言之芳撒,如果有大量的增加刪除操作并且沒有很多的隨機訪問元素的操作,應該首先LinkedList未桥。(LinkedList更適合從中間插入或者刪除(鏈表的特性))

  1. 可變與不可變

不可變對象有許多的優(yōu)點笔刹,比如簡單,安全等等冬耿。同時舌菜,也有人提出疑問:既然不可變有這么多好處,為什么不把所有類都搞成不可變的呢亦镶?

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

String result="";
for(String s: arr){
    result = result + s;
}

StackOverflow中也有關于這個的討論。

  1. 父類和子類的構(gòu)造函數(shù)
class Super {
    String s;
    public Super(String s) {
        this.s = s;
    }
}

public class Sub extends Super {
    int x = 200;
    public Sub(String s) {

    }

    public Sub() {
        System.out.println("Sub");
    }

    public static void main(String[] args) {
        Sub s = new Sub();
    }

}

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

  • 如果一個類沒有定義構(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ù)找岖。

我們還應該知道:

  • 子類的所有構(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)灵妨。

  1. ""還是構(gòu)造函數(shù)

創(chuàng)建 String 對象有2種方式:

//1. use double quotes
String x = "abc";
//2. use constructor
String y = new String("abc");

2種方式有什么不同? 下面的例子也許對你有所幫助:

String a = "abcd";
String b = "abcd";
System.out.println(a == b);  // True
System.out.println(a.equals(b)); // True
 
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d);  // False
System.out.println(c.equals(d)); // True

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

英文原文中有很多擴展鏈接,這里并沒給出朱转,后面我會挑選一些翻譯一下蟹地。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市藤为,隨后出現(xiàn)的幾起案子怪与,更是在濱河造成了極大的恐慌,老刑警劉巖缅疟,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件分别,死亡現(xiàn)場離奇詭異,居然都是意外死亡存淫,警方通過查閱死者的電腦和手機耘斩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桅咆,“玉大人括授,你說我怎么就攤上這事⊙冶” “怎么了刽脖?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長忌愚。 經(jīng)常有香客問我曲管,道長,這世上最難降的妖魔是什么硕糊? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任院水,我火速辦了婚禮,結(jié)果婚禮上简十,老公的妹妹穿的比我還像新娘檬某。我一直安慰自己,他們只是感情好螟蝙,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布恢恼。 她就那樣靜靜地躺著,像睡著了一般胰默。 火紅的嫁衣襯著肌膚如雪场斑。 梳的紋絲不亂的頭發(fā)上漓踢,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天,我揣著相機與錄音漏隐,去河邊找鬼喧半。 笑死,一個胖子當著我的面吹牛青责,可吹牛的內(nèi)容都是我干的挺据。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼脖隶,長吁一口氣:“原來是場噩夢啊……” “哼扁耐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起产阱,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤做葵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后心墅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酿矢,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年怎燥,在試婚紗的時候發(fā)現(xiàn)自己被綠了瘫筐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡铐姚,死狀恐怖策肝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情隐绵,我是刑警寧澤之众,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站依许,受9級特大地震影響棺禾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜峭跳,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一膘婶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蛀醉,春花似錦悬襟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春割捅,著一層夾襖步出監(jiān)牢的瞬間奶躯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工棺牧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留巫糙,地道東北人朗儒。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓颊乘,卻偏偏與公主長得像,于是被迫代替她去往敵國和親醉锄。 傳聞我的和親對象是個殘疾皇子乏悄,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361