淺談 Hash、Hashtable 與 HashMap
Hash 這玩意兒是程式世界的基礎,但一堆人搞不清楚 Hash、Hashtable、HashMap 的差別。常見情況:被問到為啥用 HashMap 不用 Hashtable,只能兩眼發直。今天就一次講清楚。 Hash 的概念Hash 就是把任意長度的資料「打碎」再「拼湊」成固定長度的代碼。 Hash Function 做的事12String input = "This is a very long sentence with lots of words";int hashCode = input.hashCode(); // 回傳一個整數,比如 -123456789 Hash Function 的特性: 決定性 - 同一個輸入永遠產生同一個輸出 單向性 - 不可逆,不能從 hash code 推回原始資料 雪崩效應 - 輸入改一點點,輸出就完全不同 均勻分佈 - 理想情況下,不同輸入的 hash 值均勻分佈在整個範圍 Hash 的應用1. 數位簽章確認資料沒有被竄改。簽署人計算文件的 hash 值,用私鑰加密。驗證人計算一遍 hash,再用公鑰解密比對...
Java Retry 重試機制 - 指數退避模版
遠端呼叫爆了,重試一下通常就活了。但如果一直狂轟,server 只會更爆。所以咱們要聰明一點,用指數退避(exponential backoff)的方式慢慢來。 為啥要指數退避直接 retry 沒有 delay 的問題: Server 還沒回過來,馬上再打一次,等於雪上加霜 頻繁重試反而加重服務負擔 看起來像 DDoS 攻擊 XD 指數退避的邏輯: 第 1 次失敗,等 2 秒再試 第 2 次失敗,等 4 秒再試 第 3 次失敗,等 8 秒再試 以此類推… 給 server 喘息的時間,機率就高很多。 通用模版12345678910111213141516171819202122232425262728public boolean retry(int maxAttempts, int initialDelaySeconds, Runnable action) { int attempts = 0; int delay = initialDelaySeconds; while (attempts < maxAttempts) ...
Java Optional 完整用法指南
Optional 是 Java 8 引入的概念,初看很簡單,其實用法超深。一開始很多人覺得 Optional 很煩,後來用對了才發現「真香」。最關鍵是理解它的三段式結構。 Optional 的三段式結構Optional 的用法可以分成三段:頭部(建立)→ 身體(轉換)→ 尾巴(取值) 12建立 轉換(0~多個) 取值Optional → filter/map/flatMap → orElse/ifPresent 頭部:建立 Optionalof() - 確定非 null1234567User user = new User("Alice");// 用 of() 當你確定值一定不為 nullOptional<User> opt = Optional.of(user);// 如果值是 null,直接拋 NullPointerExceptionOptional<User> opt2 = Optional.of(null); // ❌ 拋 exception ofNullable() - 可能 null12345...
Java 實體類物件比較 - equals 與 hashCode 正確實作
比較兩個物件相等這種事,看似簡單但超容易踩坑。特別是涉及 equals 和 hashCode 時,小細節搞錯就會爆。見過太多人只覆寫 equals 不覆寫 hashCode,或用 BigDecimal 的 equals 爆掉的慘案。 核心概念要比較兩個物件相等,**必須同時覆寫 equals() 和 hashCode()**。 為什麼?因為 HashMap、HashSet 等容器依賴 hashCode 和 equals 配合: 123456789// 容器先用 hashCode 定位,再用 equals 驗證Map<User, String> map = new HashMap<>();User u1 = new User(1L, "Alice");map.put(u1, "value1");User u2 = new User(1L, "Alice");// 如果只覆寫 equals 不覆寫 hashCode:// u1 和 u2 hashCode 不同 → 容器認為是不同的鍵// map.ge...
HashMap 轉 JSON 的三種方式
HashMap 轉 JSON 看似簡單,但真正用上去踩坑才多。有三種常見的方式,各有優缺點,選對一個才不會被 JsonProcessingException 折磨。 場景說明先假設有這樣的 HashMap: 1234567891011Map<String, Object> userMap = new HashMap<>();userMap.put("id", 123);userMap.put("name", "Alice");userMap.put("email", "[email protected]");userMap.put("age", 30);userMap.put("tags", Arrays.asList("admin", "developer"));Map<String, Object> addressMap = new HashMap<>...
Java 8 Stream forEach 與傳統迭代的差異
一開始用 Stream 時,就是 forEach 走天下。後來才發現 Stream forEach 和傳統 Iterator 根本是兩套邏輯,搞混的話效能會爆。 概念差異傳統迭代:外部迭代(External Iteration)你決定怎麼走訪: 1234567891011121314151617List<String> names = Arrays.asList("Alice", "Bob", "Charlie");// for-loop 迴圈for (int i = 0; i < names.size(); i++) { System.out.println(names.get(i));}// Iterator 迴圈Iterator<String> iterator = names.iterator();while (iterator.hasNext()) { System.out.println(iterator.next());}//...
Thread.sleep 的七種替代寫法
每次要延遲執行時,很多人只想到 Thread.sleep()。但你知道嗎?有七種寫法可以選,每種各有優缺點。選對的話,程式真香,選錯的話,維護時會想揍自己。 方法 1:Thread.sleep(ms) - 最基本沒啥好說的,最原始的方式: 1234567try { System.out.println("Before sleep"); Thread.sleep(2000); // 睡 2 秒 System.out.println("After sleep");} catch (InterruptedException e) { Thread.currentThread().interrupt(); // 重新設定中斷狀態} 優點: 簡單直接缺點: 毫秒單位,容易打錯;InterruptedException 必須處理;不易讀 方法 2:TimeUnit.SECONDS.sleep(n) - 可讀性最好用 TimeUnit 包裝,讓意圖更清楚: 1234567try {...
Java Synchronized 六種同步模式完整解析
synchronized 這東西從大學開始就在教,但會用和懂用是兩碼子事。踩過不少坑之後,發現這六種同步模式各有眉角,搞不清楚一定會爆。 模式 1:Synchronized Method最簡單的寫法,直接加在方法上: 1234567891011public class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; }} 鎖住的對象是什麼? this(呼叫這個方法的物件實例) 12345678910Counter counter1 = new Counter();Counter counter2 = new Counter();Thread t1 = new Thread(counter1::increment);Thread t...
CGLIB 動態代理原理與使用
剛開始用 Spring AOP 時,以為都是用 JDK Proxy。後來發現為啥有些類別代理不了,還是要靠 CGLIB,才開始研究這東西。CGLIB 現在真的無所不在,有必要搞懂它的原理。 為什麼需要 CGLIB?JDK Proxy 有個死穴:必須有 interface。 12345678910111213// JDK Proxy 能代理這個public interface UserService { void save(User user);}public class UserServiceImpl implements UserService { public void save(User user) { }}// JDK Proxy 代理不了這個 - 沒有 interfacepublic class OrderService { public void createOrder(Order order) { }} 現實中一堆類別沒有 interface,難不...
Java Supplier 函式介面用途與延遲執行
一開始看 Supplier 就覺得「幹嘛不直接傳值就好?」,後來用過幾次才明白,這東西在延遲執行的場景真的超香。 什麼是 SupplierSupplier 是 Java 8 引入的函式介面(Functional Interface),定義很簡單: 1234@FunctionalInterfacepublic interface Supplier<T> { T get();} 特點就是: 不接參數 - 呼叫時不需要傳任何東西 回傳一個值 - 回傳型別由泛型 T 決定 可以 lambda - 因為是 @FunctionalInterface,能用 lambda 表達 核心用途:延遲執行Supplier 最強的地方就是「延遲執行」。把一段邏輯包成 Supplier,等到真正需要時才呼叫 .get() 去執行。 實例 1:Logger 的 Lazy Evaluation最經典的例子: 12345// 不好的做法 - 即使 log level 是 INFO,也會執行運算logger.debug("Current value is &qu...














