Java開發者易犯錯誤Top10

2022-01-29 CSDN

本文總結了Java開發者經常會犯的前十種錯誤列表。

Top1. 數組轉換為數組列表

將數組轉換為數組列表,開發者經常會這樣做:

[java]

List<String> list = Arrays.asList(arr);

Arrays.asList()將返回一個數組內部是私有靜態類的ArrayList,這不是java.util.ArrayList類,java.util.Arrays.ArrayList類有set()、 get()、 contains()方法,但是沒有任何加元素的方法,因此它的大小是固定的。你應該這麼做來創建一個真正的數組:

[java]

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

ArrayList的構造函數能夠接受一個集合類型,這也是java.util.Arrays.ArrayList的超級類型。

Top2. 檢查一個數組包含一個值

開發者經常這麼做:

[java]

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

return set.contains(targetValue);

代碼可以工作,但是沒有必要首先轉換列表到Set,轉換一個列表到一個Set需要額外的時間。因此你可以把它簡化為:

[java]

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

[java]

for(String s: arr){

if(s.equals(targetValue))

return true;

}

return false;

第一個比第二個更具可讀性

Top3. 在一個循環中從一個列表裡刪除一個元素

考慮下面刪除元素的代碼在迭代中的結果:

[java]

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);

輸出是:

[java]

[b, d]

該方法有一個嚴重的問題,當一個元素被刪除時,列表收縮的大小以及指針改變了。所以想要在循環內利用指針刪除多個元素是無法正常進行的。

這種情況下使用迭代器才是正確的方法,foreach循環在Java中的工作像是一個迭代器,但實際上並不是,考慮下面的代碼:

[java]

ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));

for (String s : list) {

if (s.equals("a"))

list.remove(s);

}

它會報出ConcurrentModificationException異常。

相反下面這個就可以正常工作。

[java]

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()之前被調用。在foreach循環中,編譯器將在刪除元素操作之後調用.next(),這也是導致ConcurrentModificationException異常的原因,你可以點擊此處查看ArrayList.iterator()的原始碼。

Top4. Hashtable vs HashMap

根據算法的常規,Hashtable是對數據結構的稱呼。但是在Java中,數據結構的名稱是HashMap。Hashtable和HashMap關鍵不同之一是Hashtable是同步的。

關於這一點可查看以下兩個連結(請點擊「閱讀原文」查看):

HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap

Map問題Top10

Top5. 使用集合的原始類型

在Java中,原始類型和無限制的通配符類型很容易被混淆。以Set為例,Set是原始類型,而Set(?)則是無限制的通配符類型。

考慮下面的代碼,以一個原始類型List作為參數:

[java]

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]

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

at ...

使用原始類型集合是危險的,因為原始類型集合跳過了泛型類型檢查,也不安全。Set、Set<?>和Set<Object>之間有很大的不同。詳細可查看

Raw type vs. Unbounded wildcard和Type Erasure。

Top6. 訪問級別

開發者經常對類域使用public,這很容易通過直接引用獲得域值,但這是一個非常糟糕的設計。根據經驗來說是給予成員的訪問級別越低越好。

詳細情況可點擊查看Java中成員訪問級別(請點擊「閱讀原文」查看):public、protected、private

Top7.ArrayList VS LinkedList

如果你不知道ArrayList和LinkedList之間的區別時,你可能會經常的選用ArrayList,因為它看起來看熟悉。然而它們之間有巨大的性能不同。簡單的來說,如果有大量的添加/刪除操作,並且沒有很多的隨機存取操作時,LinkedList應該是你的首選。如果您對此不是很了解的話,點此此處查看更多關於它們性能的信息。

Top8. Mutable VS Immutable

Immutable對象有很多優勢,比如簡單、安全等等。但它要求每一個不同的值都需要有一個不同的對象,而太多的對象可能會導致垃圾收集的高成本。所以對Mutable和Immutable的選擇應該有一個平衡點。

一般來說,Mutable對象用於避免產生過多的中間對象,經典的例子是連接大量的字符串數。如果你使用Immutable字符串,那麼會產生很多符合垃圾收集條件的對象。這對CPU是浪費時間和精力的,當其可以使用Mutable對象作為正確的解決方案。(如StringBuilder)

[java]

String result="";

for(String s: arr){

result = result + s;

}

這裡還有一些其他Mutable對象可取的情況。例如mutable對象傳遞到方法中允許你在不跳過太多語法的情況下收集多個結果。另一個例子是排序和過濾,你可以構建一個帶有原有集合的方法,並返回一個已排序的,不過這對大的集合來說會造成更大的浪費。

推薦閱讀(請點擊「閱讀原文」查看):為什麼字符串是Immutable?

Top9. Super和Sub構造函數


這個編譯錯誤是因為默認的Super構造函數是未定義的。在Java中,如果一個類沒有定義一個構造函數,編譯器會默認的為類插入一個無參數構造函數。如果一個構造函數是在Super類中定義的,這種情況下Super(String s),編譯器不會插入默認的無參數構造函數。

另一方面,Sub類的構造函數,無論帶不帶有參數,都會調用無參數的Super構造函數。

編譯器在Sub類中試圖將Super()插入到兩個構造函數中,但是Super默認的構造函數是沒有定義的,編譯器才會報錯。如何解決這一問題?你只需在Super類中添加一個Super()構造函數,如下所示:

[java]

public Super(){

System.out.println("Super");

}

或移除自定義的Super構造函數,又或者在Sub函數中添加super(value)。

這方面想了解更多的可以點擊此處查看。

Top10. ""或構造函數?

字符串可以通過兩種方式創建:

[java]

//1. use double quotes

String x = "abc";

//2. use constructor

String y = new String("abc");

它們之間有何不同?下面的例子可以給出答案:

[java]

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

關於它們如何在內存中分布的更多細節可以查看《使用""或構造函數創建Java字符串》。

本文為CSDN翻譯整理,點擊「閱讀原文」可查看全文並參與討論。

如果您喜歡這篇文章,請點擊右上角「…」將本文分享給你的朋友。

相關焦點

  • Java 處理 Exception 的 9 個最佳實踐!
    不僅僅初學者很難理解,即使一些有經驗的開發者也需要花費很多時間來思考如何處理異常,包括需要處理哪些異常,怎樣處理等等。這也是絕大多數開發團隊都會制定一些規則來規範對異常的處理的原因。而團隊之間的這些規範往往是截然不同的。本文給出幾個被很多團隊使用的異常處理最佳實踐。1.
  • 網球初學者的易犯錯誤
    網球初學者的易犯錯誤網球發球是很重要的一個步驟,如果球都發不好更別說接下來的步驟了。那麼,網球發球的動作要領都有哪些呢?下面就隨小編一起去看看網球發球的動作要領吧。1、站位和握拍:身體側對球網,以右手持拍為例,左腳與底線45度左右,右腳與底線平行,兩腳距離與肩同寬。大陸式握拍,放鬆。2、拋球:手臂伸直,眼睛的水平高度將球送上去,眼睛盯球很重要。
  • Node.js對Java:一場史詩級的爭奪開發者注意力的對決
    當 web 的大部分依賴於 JavaScript 執行引擎時,開發者的時間大部分花在了打磨邊邊角角上面。然而,所有的創新都有一個缺點,那就是新的功能可能擴散太快,以至於開發者們來不及吸收這些功能。一些老派的開發者經常會對充斥著最新 ECMAScript 句法的增強特性感到困惑。另外,這些新代碼可能還會導致某些舊版瀏覽器崩潰。
  • 關愛甲狀腺疾病,別犯七個易犯的錯誤!
    昆明中研甲狀腺醫院提醒大家避免以下七個易犯錯誤,讓你更好地控制甲狀腺疾病 1 不按時按量服藥 生活中,很多患者不能按時按量地服藥。如果你希望自己能按時吃藥,但就是常常想不起來? 可以利用手機鬧鐘來設定服藥的時間,幫助按時服藥。
  • JDK/Java 15發布
    384:Records (Second Preview)Records 提供了一種緊湊的語法來聲明類,以幫助開發者寫出更簡潔的代碼,這些類是淺層不可變數據(shallowly immutable data)的透明擁有者。該特性主要用在特定領域的類,這些類主要用於保存數據,不提供領域行為。目前處於第 2 個預覽版本階段。
  • Kotlin VS Java:基本語法差異
    ,歡迎加入Java和Android架構社區Android開發規範和架構總結5月18號,goole宣布Kotlin成為官方支持的開發語言以來,Kotlin語言社區,公眾號,qq群等全面轟炸,本文是一篇譯文,來自國外的一個用戶,將給大家介紹,基礎語法部分Kotlin和java
  • 最通俗易懂的 Java 10 新特性講解 | 原力計劃
    查看自己的 Java 10 版本。主要增加了下面幾個擴展方法。java.time.temporal.WeekFields::ofjava.util.Calendar::{getFirstDayOfWeek,getMinimalDaysInWeek}java.util.Currency::getInstancejava.util.Locale::getDisplayNamejava.util.spi.LocaleNameProvider
  • Java 處理異常 9 個最佳實踐,你知道幾個?
    來源:http://t.cn/ESocliD在本文中,作者介紹了9個處理異常的最佳方法與實踐,以舉例與代碼展示結合的方式,讓開發者更好的理解這9種方式,並指導讀者在不同情況下選擇不同的異常處理方式。以下為譯文:Java中的異常處理不是一個簡單的話題。
  • 3分鐘帶你品嘗新鮮出爐的Java 17,看完就知道香不香!
    2.1  JEP 306: Restore Always-Strict Floating-Point Semantics主要就是簡化數學類庫的開發,包括java.lang.Math and java.lang.StrictMath.
  • smart-doc 2.0.1 發布,Java 零註解 API 文檔生成工具
    smart-doc是一款同時支持java restful api和apache dubbo rpc接口文檔生成的工具
  • JDK/Java 14 發布
    總共 16 個新特性如下:305:Pattern Matching for instanceof (Preview)為 instanceof 運算符引入模式匹配(預覽階段)通過模式匹配,開發者可以用更簡潔和更安全的方式來表達通用的程序邏輯。
  • java練習本(2019-06-12)
    題目java語言使用的字符集是?2.答案解析A.這是一種常用於會計系統中的編碼方式,與java關係不大,錯誤B.ASCII碼1961年提出,是目前使用最廣泛的西文字符集,但不是java使用的編碼C.GBK為一種漢子編碼格式,包含了大量的漢子編碼,java也並未使用它最為編碼格式D.Unicode編碼是一種將世界上所有符號都納入其中的編碼格式來避免編碼不匹配的亂碼問題
  • Java 8—Java 10 特性詳解
    Java 8 特性詳解知識體系函數編程在Java世界裡面,面向對象還是主流思想,對於習慣了面向對象編程的開發者來說,抽象的概念並不陌生。面向對象編程是對數據進行抽象,而函數式編程是對行為進行抽象。現實世界中,數據和行為並存,程序也是如此,因此這兩種編程方式我們都得學。
  • [博客更新]Java 中 final 關鍵詞的使用
    上一篇文章我們講了 java 中 static 關鍵字的使用,這裡再將一下 final 關鍵字的使用。final 在 java 中可以看做一個「終結者」,它可以定義類、定義方法和定義變量。哎呀,好像沒別的可說了,就這樣吧,這可能是我寫過的字數最少的一篇文章了 算了,最後加一個示例程序吧,當然是錯誤的程序,包含了以上三種使用方法的錯誤使用報錯信息:package com.example.finalDemo;/** * User: sunriseydy * 2018-4-25 22:04 */finalclassPerson{String name
  • Java 中的異常和處理詳解
    錯誤:Error類以及他的子類的實例,代表了JVM本身的錯誤。錯誤不能被程式設計師通過代碼處理,Error很少出現。因此,程式設計師應該關注Exception為父類的分支下的各種異常類。異常:Exception以及他的子類,代表程序運行時發送的各種不期望發生的事件。可以被Java異常處理機制使用,是異常處理的核心。
  • 每日一課 | Java Final關鍵字示例
    final變量值的任何多次更改將導致編譯錯誤。FinalVariableExample.javapackage com.mkyong;public class FinalVariableExample {  final int count = 0;   public FinalVariableExample()
  • Java開發者不可錯過的Spring Boot
    不知不覺,12年就這麼過去了,Spring已然成為Java應用開發的事實標準,影響著無數Java開發者。如果說Spring Framework的目標是幫助開發者寫出好的系統,那Spring Boot的目標就是幫助開發者用更少的代碼,更快地寫出好的生產系統。Spring Boot為開發者帶來了更好的開發體驗,但寫完代碼只是萬裡長徵路上的一小步,後續的運維工作才是讓很多人真正感到無助的。
  • java集合【6】——— Iterable接口
    內部定義的方法 java集合最源頭的接口,實現這個接口的作用主要是集合對象可以通過迭代器去遍歷每一個元素。list) {            if(item.equals("Jam")){                list.remove(item);            }            System.out.println(item);        }    }從下面的錯誤我們可以看出
  • Java 數組轉 List 的三種方式及對比
    本文介紹Java中數組轉為List三種情況的優劣對比,以及應用場景的對比,以及程式設計師常犯的類型轉換錯誤原因解析。一.最常見方式(未必最佳)通過 Arrays.asList(strArray) 方式,將數組轉換List後,不能對List增刪,只能查改,否則拋異常。
  • 番外 —— Java 的那些開發者
    這是一個橫掃 Google、Facebook 公司 Offer 的奇女子,自然,Oracle 的 Offer 也不在話下,文章記述了她在求學和求職過程中接觸到的 Java 語言、Java 開發者和 Oracle 的面試者,寫得非常有意思。我很喜歡讀 Angela 寫的技術雜談,由於其深厚的技術功底和科研經歷,很多東西寫得既深入淺出,又縱橫開闔,視角宏大,讀來非常過癮。