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...
資料庫悲觀鎖與樂觀鎖完整比較
做過庫存扣款、積分更新這種涉及併發的操作沒有?一開始以為很簡單,後來才發現如果不懂鎖機制,資料一定會爆。悲觀鎖和樂觀鎖是兩種完全不同的思路,沒搞懂選錯一個,後期真的有夠慘。 悲觀鎖(Pessimistic Lock)悲觀鎖的思路就是:「我相信一定會有人跟我搶」,所以先佔著位子再說。 SQL 寫法最常見就是 SELECT … FOR UPDATE: 1234567891011@Repositorypublic class InventoryRepository { @Autowired private JdbcTemplate jdbcTemplate; public Integer getInventoryWithLock(Long productId) { String sql = "SELECT quantity FROM inventory WHERE product_id = ? FOR UPDATE"; return jdbcTemplate.queryForObjec...
Spring TransactionTemplate 程式化交易管理與 Rollback
當初一開始用 Spring,習慣只會 @Transactional 這招。後來才發現 TransactionTemplate 這東西,發現它在某些場景真的有夠方便。 @Transactional 的限制@Transactional 很直觀啦,加一個 annotation 就搞定交易管理。但踩坑的地方是: Proxy 限制 - 同個 class 內部呼叫不會觸發 proxy,交易會爆掉 粒度問題 - 整個方法才是一個交易,沒辦法在同一個方法裡控制多段獨立的交易 Rollback 控制 - 用 rollbackFor 有點硬,不能細粒度決定要不要 rollback TransactionTemplate 的救世主角色TransactionTemplate 提供了「程式化」的交易控制。不用 annotation,直接寫程式邏輯,搭配 callback 來執行。 基本用法首先注入 PlatformTransactionManager: 12345678910111213141516171819202122232425262728@Servicepublic class OrderSe...
Spring @Transactional 類別層級效果與 CGLIB Proxy
@Transactional 是 Spring 最常用的註解之一,但很多人對它的底層原理不太了解,導致寫出一些表面上沒問題,但實際上交易沒有生效的程式碼。我就踩過好幾次這種坑,最後才徹底理解它的運作方式。 類別層級 vs 方法層級@Transactional 可以標在類別上,也可以標在方法上。 標在類別上1234567891011121314151617@Service@Transactionalpublic class UserService { public void updateUser(User user) { // 有交易 } public void deleteUser(String userId) { // 也有交易 } @Transactional(readOnly = true) public User getUser(String userId) { // 覆蓋了類別層級的設定,用 readOnly ...














