Java 中最常見的 5 個錯誤:
1、Null 的過度使用
避免過度使用 null 值是一個最佳實踐。例如,更好的做法是讓方法返回空的 array 或者 collection 而不是 null 值,因為這樣可以防止程序拋出 NullPointerException。
2、忽視異常
我們經常對異常置之不理。然而,針對初學者和有經驗的 Java程序員,最佳實踐仍是處理它們。異常拋出通常是帶有目的性的,因此在大多數情況下需要記錄引起異常的事件。別小看這件事,如果必要的話,你可以重新拋出它,在一個對話框中將錯誤信息展示給用戶或者將錯誤信息記錄在日誌中。至少,為了讓其它開發者知曉前因後果,你應該解釋為什麼沒有處理這個異常。
3、並發修改異常
這種異常發生在集合對象被修改,同時又沒有使用 iterator 對象提供的方法去更新集合中的內容。
4、違約
有時候,為了更好地協作,由標准庫或者第三方提供的代碼必須遵守共同的依賴准則。例如,必須遵守hashCode和equals的共同約定,從而保證 Java 集合框架中的一系列集合類和其它使用hashCode和equals方法的類能夠正常工作。不遵守約定並不會產生 exception 或者破壞代碼編譯之類的錯誤;它很陰險,因為它隨時可能在毫無危險提示的情況下更改應用程序行為。
5、使用原始類型而不是參數化的
根據 Java 文檔描述:原始類型要麼是非參數化的,要麼是類 R 的(同時也是非繼承 R 父類或者父介面的)非靜態成員。在 Java 泛型被引入之前,並沒有原始類型的替代類型。Java 從1.5版本開始支持泛型編程,毫無疑問這是一個重要的功能提升。然而,由於向後兼容的原因,這里存在一個陷阱可能會破壞整個類型系統。
㈡ Java開發人員最常犯的10個錯誤
一 、把數組轉成ArrayList
為了將數組轉換為ArrayList,開發者經常會這樣做:
List list = Arrays.asList(arr);
使用Arrays.asList()方法可以得到一個ArrayList,但是得到這個ArrayList其實是定義在Arrays類中的一個私有的靜態內部類。這個類雖然和java.util.ArrayList同名,但是並不是同一個類。java.util.Arrays.ArrayList類中實現了set(), get(), contains()等方法,但是並沒有定義向其中增加元素的方法。也就是說通過Arrays.asList()得到的ArrayList的大小是固定的。
如果在開發過程中,想得到一個真正的ArrayList對象(java.util.ArrayList的實例),可以通過以下方式:
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
java.util.ArrayList中包含一個可以接受集合類型參數的構造函數。因為java.util.Arrays.ArrayList這個內部類繼承了AbstractList類,所以,該類也是Collection的子類。
二、判斷一個數組是否包含某個值
在判斷一個數組中是否包含某個值的時候,開發者經常這樣做:
Set<String> set = new HashSet<String>(Arrays.asList(arr));return set.contains(targetValue);
在Java中如何高效的判斷數組中是否包含某個元素一文中,深入分析過,以上方式雖然可以實現功能,但是效率卻比較低。因為將數組壓入Collection類型中,首先要將數組元素遍歷一遍,然後再使用集合類做其他操作。
在判斷一個數組是否包含某個值的時候,推薦使用for循環遍歷的形式或者使用Apache Commons類庫中提供的ArrayUtils類的contains方法。
三、在循環中刪除列表中的元素
在討論這個問題之前,先考慮以下代碼的輸出結果:
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);
輸出結果:
[b,d]
以上代碼的目的是想遍歷刪除list中所有元素,但是結果卻沒有成功。原因是忽
略了一個關鍵的問題:當一個元素被刪除時,列表的大小縮小並且下標也會隨之變化,所以當你想要在一個循環中用下標刪除多個元素的時候,它並不會正常的生效。
也有些人知道以上代碼的問題就由於數組下標變換引起的。所以,他們想到使用增強for循環的形式:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(String s:list){
if(s.equals("a")){
list.remove(s);
}
}
但是,很不幸的是,以上代碼會拋出,有趣的是,如果在remove操作後增加一個break,代碼就不會報錯:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(String s:list){
if(s.equals("a")){
list.remove(s);
break;
}
}
在Java中的fail-fast機制一文中,深入分析了幾種在遍歷數組的同時刪除其中元素的方法以及各種方法存在的問題。其中就介紹了上面的代碼出錯的原因。
迭代器(Iterator)是工作在一個獨立的線程中,並且擁有一個 mutex 鎖。 迭代器被創建之後會建立一個指向原來對象的單鏈索引表,當原來的對象數量發生變化時,這個索引表的內容不會同步改變,所以當索引指針往後移動的時候就找不到要迭代的對象,所以按照 fail-fast 原則 迭代器會馬上拋出java.util. 異常。
所以,正確的在遍歷過程中刪除元素的方法應該是使用Iterator:
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()方法必須在調用remove()方法之前調用。如果在循環過程中先調用remove(),再調用next(),就會導致異常。原因如上。
四、HashTable 和 HashMap 的選擇
了解演算法的人可能對HashTable比較熟悉,因為他是一個數據結構的名字。但在Java里邊,用HashMap來表示這樣的數據結構。Hashtable和 HashMap的一個關鍵性的不同是,HashTable是同步的,而HashMap不是。所以通常不需要HashTable,HashMap用的更多。
HashMap完全解讀、Java中常見親屬比較等文章中介紹了他們的區別和如何選擇。
五、使用原始集合類型
在Java里邊,原始類型和無界通配符類型很容易混合在一起。以Set為例,Set是一個原始類型,而Set< ? >是一個無界通配符類型。 (可以把原始類型理解為沒有使用泛型約束的類型)
考慮下面使用原始類型List作為參數的代碼:
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 >之間有很大差別。關於泛型,可以參考下列文章:《成神之路-基礎篇》Java基礎知識——泛型
六、訪問級別
程序員們經常使用public作為類中的欄位的修飾符,因為這樣可以很簡單的通過引用得到值,但這並不是好的設計,按照經驗,分配給成員變數的訪問級別應該盡可能的低。參考Java中的四種訪問級別
七、ArrayList與LinkedList的選擇
當程序員們不知道ArrayList與LinkedList的區別時,他們經常使用ArrayList,因為它看起來比較熟悉。然而,它們之前有巨大的性能差別。在ArrayList vs LinkedList vs Vector 區別、Java中常見親屬比較等文章中介紹過,簡而言之,如果有大量的增加刪除操作並且沒有很多的隨機訪問元素的操作,應該首先LinkedList。(LinkedList更適合從中間插入或者刪除(鏈表的特性))
八、可變與不可變
在為什麼Java要把字元串設計成不可變的一文中介紹過,不可變對象有許多的優點,比如簡單,安全等等。同時,也有人提出疑問:既然不可變有這么多好處,為什麼不把所有類都搞成不可變的呢?
通常情況下,可變對象可以用來避免產生過多的中間對象。一個經典的實例就是連接大量的字元串,如果使用不可變的字元串,將會產生大量的需要進行垃圾回收的對象。這會浪費CPU大量的時間,使用可變對象才是正確的方案(比如StringBuilder)。
String result="";
for(String s: arr){
result = result + s;
}
StackOverflow中也有關於這個的討論。
九、父類和子類的構造函數
上圖的代碼中有兩處編譯時錯誤,原因其實很簡單,主要和構造函數有關。首先,我們都知道:
如果一個類沒有定義構造函數,編譯器將會插入一個無參數的默認構造函數。
如果一個類中定義了一個帶參數的構造函數,那麼編譯器就不會再幫我們創建無參的構造函數。
上面的Super類中定義了一個帶參數的構造函數。編譯器將不會插入默認的無參數構造函數。
我們還應該知道:
子類的所有構造函數(無論是有參還是無參)在執行時,都會調用父類的無參構造函數。
所以,編譯器試圖調用Super類中的無參構造函數。但是父類默認的構造函數未
定義,編譯器就會報出這個錯誤信息。
要解決這個問題,可以簡單的通過
? 在父類中添加一個Super()構造方法,就像這樣:
public Super(){}
? 移除自定義的父類構造函數
? 在子類的構造函數中調用父類的super(value)。
十、」」還是構造函數
關於這個問題,也是程序員經常出現困惑的地方,在該如何創建字元串,使用」 「還是構造函數?中也介紹過.
如果你只需要創建一個字元串,你可以使用雙引號的方式,如果你需要在堆中創建一個新的對象,你可以選擇構造函數的方式。
在String d = new String("abcd")時,因為字面值「abcd」已經是字元串類型,那麼使用構造函數方式只會創建一個額外沒有用處的對象。
還可以關注微信公眾平台:javaniuniu
㈢ python每級縮進都只能使用四個空格。一個判斷題,對不對
不對,python的每級縮進並不是只能使用四個空格,python的縮進規則是第一句的代碼縮進是兩個空格,那麼其他的縮進也要是兩個空格,如果第一句的代碼縮進是四個空格,那麼其他的縮進都是需要四個空格。如果是一個tab鍵那麼其他的縮進也是一個tab鍵。
不過常用的是四個空格的縮進,其他的非常的少見。四個空格的縮進看起來非常的舒服。代碼更加的美觀。
(3)程序員錯誤的用法擴展閱讀:
python的特點
優點:
簡單:Python是一種代表簡單主義思想的語言。閱讀一個良好的Python程序就感覺像是在讀英語一樣。它使你能夠專注於解決問題而不是去搞明白語言本身。
易學:Python極其容易上手,因為Python有極其簡單的說明文檔。
速度快:Python 的底層是用 C 語言寫的,很多標准庫和第三方庫也都是用 C 寫的,運行速度非常快。
免費、開源:Python是FLOSS(自由/開放源碼軟體)之一。使用者可以自由地發布這個軟體的拷貝、閱讀它的源代碼、對它做改動、把它的一部分用於新的自由軟體中。FLOSS是基於一個團體分享知識的概念。
高層語言:用Python語言編寫程序的時候無需考慮諸如如何管理你的程序使用的內存一類的底層細節。
可移植性:由於它的開源本質,Python已經被移植在許多平台上(經過改動使它能夠工作在不同平台上)。
缺點:
運行速度慢:這里是指與C和C++相比。
python的應用
系統編程:提供API(Application Programming Interface應用程序編程介面),能方便進行系統維護和管理,Linux下標志性語言之一,是很多系統管理員理想的編程工具。
圖形處理:有PIL、Tkinter等圖形庫支持,能方便進行圖形處理。
數學處理:NumPy擴展提供大量與許多標准數學庫的介面。
文本處理:python提供的re模塊能支持正則表達式,還提供SGML,XML分析模塊,許多程序員利用python進行XML程序的開發。
參考資料來源:網路-Python