吐槽,Java 設計的槽點

来源:https://www.cnblogs.com/socoool/archive/2020/04/04/12629811.html
-Advertisement-
Play Games

今天不灌水,直接上乾貨!希望下麵的講解,能與你產生一些共鳴。 1. 求長度各有千秋 你是否曾經在面試的時候,經常被問到:數組有沒有 length() 方法?字元串有沒有 length() 方法? 集合有沒有 length() 方法? 面對這個問題,那麼不得不吐槽一下,Java 中獲取長度的方式,設計 ...


今天不灌水,直接上乾貨!希望下麵的講解,能與你產生一些共鳴。

 

1. 求長度各有千秋

 

你是否曾經在面試的時候,經常被問到:數組有沒有 length() 方法?字元串有沒有 length() 方法? 集合有沒有 length() 方法?

 

面對這個問題,那麼不得不吐槽一下,Java 中獲取長度的方式,設計著實有點亂,對剛入門的程式猿而言,那絕對是一臉的懵逼。

 

String[] array = {"abc", "def"};
String str = "abcedf";
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("def");

System.out.println("數組的長度: " + array.length);
System.out.println("字元串的長度: " + str.length());
System.out.println("集合的長度: " + list.size());

  

正式科普一下,希望能夠銘記你心中。數組求長度用 length 屬性;字元串求長度用 length() 方法;集合求長度用 size() 方法。

 

2. 字元串截取有深意

 

對於程式猿來說,編程規範能夠養成良好的編程習慣,提高代碼質量,減少溝通成本。阿裡 Java 開發手冊編程規約中記載,【強制】方法名、參數名、成員變數、局部變數都統一使用 lowerCamelCase 風格,必須遵從駝峰形式。

 

看到這裡,不得不提 String 中的 substring 方法,你是不是經常把“substring”寫成“subString”。本次這個命名不是吐槽的重點。主要想分享如下代碼片段。

 

public class StringInterview {
   public static void main(String[] args) {
       String str = "......abcdefgh.......";
       String subStr = str.substring(1,3);
       str = null;
       System.out.println(subStr);
   }
}

  

 

假如上述這段程式在 Java 1.6 中運行,代碼中雖然強制使 str 引用為空,本意是釋放 str 占用的空間,但是這個時候,GC 是無法回收這個大的 char 數組的,因為還在被 subStr 字元串內部引用著,雖然 subStr 只截取這個大數組的一小部分。當 str 是一個非常大字元串的時候,這種浪費是非常明顯的,甚至會帶來記憶體泄露問題。

 

深入 Java 1.6 中 substring 的設計一探究竟。

public String substring(int beginIndex, int endIndex) {

  if (beginIndex < 0) {
      。。 。。 。。
  }

  if (endIndex > count) {
       。。 。。 。。
  }

  if (beginIndex > endIndex) {
       。。 。。 。。
  }

  return ((beginIndex == 0) && (endIndex == count)) ? this :
   new String(offset + beginIndex, endIndex - beginIndex, value);
}

  

上述方法調用的構造方法

String(int offset, int count, char value[]) {
  this.value = value;
  this.offset = offset;
  this.count = count;
}

  

到此你應該撥雲見日豁然開朗。當我們調用字元串 str 的 substring 得到字元串 subStr,其實這個操作,無非就是調整了一下 subStr 的 offset 和 count ,用到的內容還是 str 之前的 value 字元數組,並沒有重新創建新的專屬於 subStr 的內容字元數組。如果 subStr 的生命周期要長於 str 或者手動設置 str 為null,當垃圾回收進行後,str 被回收掉,subStr 沒有回收掉,那麼記憶體占用依舊存在,因為 subStr 持有 str 字元數組的引用。

 

正式科普一下,這個問題出現在 Java 1.6,並且 Java 1.7 中已經修複。雖然已經修複,並不代表我們就不需要瞭解,如果你正在求職路上,稍微瞭解一下,說不定會加分。

 

3. 一條 if 語句引發不滿

 

先給各位拋一段 Java LinkedList 類的代碼片段,一起吐槽吐槽。

 

public E getFirst() {
  final Node<E> f = first;
  if (f == null)
       throw new NoSuchElementException();
   return f.item;
}

  

JDK 中 if 語句後只有一條語句,大部分都是這麼實現的。原則上,if 語句如果後面跟著只有一句話,是可以不加的。但是在我們實際開發中,有些現象卻會讓你匪夷所思,不信你看看下麵的代碼片段。

 

片段一:

if (f == null)
   //拋出異常,或者加一條列印語句,加上此句註釋邏輯就變了
   throw new NoSuchElementException();

  

片段二:

public class Interview {
   public static void main(String[] args) {
       Class c = Interview.class;
       try {
           Object o = c.newInstance();
           if (o instanceof Interview)
               Interview tt = (Interview) o; //為什麼會報錯?請各位解釋原因
       } catch (Exception e) {
           e.printStackTrace();
       }
   }
}

  

正式科普一下,看似一個簡單的編碼規範,背後隱藏了多少坑啊,所以為了良好的編程習慣,建議還是統一加上大括弧為好,良好的編碼習慣是真重要啊。

 

4. 時間實現也找茬

 

Tiago Fernandez 做過一次投票,選舉最爛的 Java API,排第二的就是日期 API(Date 和Calender)。一言不合就拋代碼,如下片段是計算兩個日期之間的天數。

public static void main(String[] args) {
   Calendar begin = Calendar.getInstance();
   begin.set(1990, Calendar.JUNE, 17);
   Calendar end = Calendar.getInstance();
   System.out.println(alculatedDays(begin, end));
   System.out.println(alculatedDays(begin, end)); // 為什麼顯示 0?
}

public static long alculatedDays(Calendar begin, Calendar end) {
   long days = 0;
   while (begin.before(end)) {
       begin.add(Calendar.DAY_OF_MONTH, 1);
       days++;
   }

   return days;
}

 

alculatedDays 方法,如果連續計算兩個 Date 實例的話,第二次會取得 0,因為 Calendar 狀態是可變的,考慮到重覆計算的場合,最好複製一個新的 Calendar,改造如下

public static long alculatedDays(Calendar begin, Calendar end) {
   Calendar calendar = (Calendar) begin.clone(); // 複製
   long days = 0;
   while (calendar.before(end)) {
       calendar.add(Calendar.DAY_OF_MONTH, 1);
       days++;
   }

   return days;
}

  

不過萬物都在向前進化,因為由於原來老舊的日期 API 一直被人詬病,所以 JDK 1.8 中對日期的改動是特別大的,基本上是引入了一套全新易用的 API,各位有時間可以體驗一下。

 

好了,吐槽中見真諦,今天就講這麼多吧。希望你能 get 到一點點共鳴,如果你比較感興趣,就多多分享給身邊的朋友吧。

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 昨天有同事問 UserService、XxxService 都會調用 Dao 的 insert、update ... ...,這些重覆的代碼,有沒有辦法變得靈活一些? 巧了,和咱們分享的主題剛好碰上,賣個關子,先不談解決方案,就當啥事沒有發生,重新引入今天的話題(捂嘴笑)。 想蛻變的研發人員,偶爾會 ...
  • 記錄一些方法,關於 VBScript 中,動態 Array 的實現 ,也適用於 VBA, 很久以前,寫 VBA 的時候,就覺得使用 Array 很不方便,因為大小固定, 當時想的是,要是 Array 可以像 Python 里的 list 一樣好用該多好啊, 那麼下麵,就記錄一些方法,能讓 Array ...
  • 今天找到一片電影,想把它下載下來。 先開Networks工具分析一下: 初步分析發現,視頻載入時會拉取TS格式的文件,推測這是一個m3u8的索引,記錄著幾百段TS文件,這樣方便快進時載入。 但是實際分析m3u8文件時,發現這並不是一個有效的索引文件,應該只是載入一個形式,實際的handler在其他地 ...
  • 01 關註"一猿小講"朋友,都知道以往的文章一直倡導拒絕 CRUD,那到底什麼是 CRUD?今天咱們就聊聊 Java 妹子小猿與資料庫老頭交互的事兒。 產品小汪鏗鏘有力的說:小猿同學,咱們近期要推一爆款產品,你先實現用戶基本的登錄的功能。 啥玩意?小猿內心嘀咕嘀咕:爆款產品,還基本的登錄,那不就是實 ...
  • 線上應用程式升級,需要把缺失的數據關聯補充一下,你寫個程式處理一下? 客戶信息同步,由於是線上敏感欄位都是加密處理,所以需要你再寫個程式解密處理一下? 曾記得 N 年前,我經常幹這種事情,碼這種代碼。今天回過頭來,對此類事情簡單做一個分享,以防你們也遇到此類問題,不妨拿去實踐一下,說不定會提高效率呢 ...
  • 我的LeetCode:https://leetcode cn.com/u/ituring/ 我的LeetCode刷題源碼[GitHub]:https://github.com/izhoujie/Algorithmcii LeetCode 42. 接雨水 題目 給定 n 個非負整數表示每個寬度為 1 ...
  • Java概述 Java是什麼? Java is a general purpose programming language that is class based, object oriented, and designed to have as few implementation depend ...
  • 字元串常見操作 索引 切片 字元串的常見操作 應用 判斷是否是小數 ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...