切換語言為:簡體

那年我吃了Stream流 toMap() 的苦!

  • 爱糖宝
  • 2024-07-07
  • 2070
  • 0
  • 0

你可能會想,toList 和 toSet 都這麼便捷順手了,又怎麼能少得了 toMap() 呢。

答應我,一定打消你的這個想法,否則這將成為你噩夢的開端。

讓我們先準備一個使用者實體類。

@Data
@AllArgsConstructor  
public class User {  
  
    private int id;  
    
    private String name;  
}

假設有這麼一個場景,你從資料庫讀取 User 集合,你需要將其轉為 Map 結構資料,key 和 value 分別為 user 的 id 和 name

很快,你啪的一下就寫出了下面的程式碼:

public class UserTest {
    @Test
    public void demo() {  
        List<User> userList = new ArrayList<>();
        // 模擬資料
        userList.add(new User(1, "Alex"));  
        userList.add(new User(1, "Beth"));

        Map<Integer, String> map = userList.stream()  
                .collect(Collectors.toMap(User::getId, User::getName));  
        System.out.println(map);  
    }
}

執行程式,你已經想好了開始怎麼摸魚,結果啪的一下 IllegalStateException 報錯就拍你臉上,你定睛一看怎麼提示 Key 值重複。

那年我吃了Stream流 toMap() 的苦!

作為優秀的八股文選手,你清楚的記得 HashMap 物件 Key 重複是進行替換。你不信邪,斷點一打,堆疊一看,碩大的 uniqKeys 擺在了面前,憑藉四級 424 分的優秀戰績你頓時菊花一緊,點開一看,誰家好人 map key 還要去重判斷啊。

那年我吃了Stream流 toMap() 的苦!

好好好,這麼玩是吧,你轉身開啟瀏覽器一搜,原來需要自己手動處理重複場景,啪的一下你又重新改了一下程式碼:

public class UserTest {
    @Test
    public void demo() {  
        List<User> userList = new ArrayList<>();
        // 模擬資料
        userList.add(new User(1, "Alex"));  
        userList.add(new User(2, null));
        
        Map<Integer, String> map = userList.stream()  
                .collect(Collectors.toMap(User::getId, User::getName, (oldData, newData) -> newData));  
        System.out.println(map);  
    }
}

再次執行程式,你似乎已經看到知乎的摸魚貼在向你招手了,結果啪的一下 NPE 又拍在你那笑容漸漸消失的臉上。

那年我吃了Stream流 toMap() 的苦!

靜下心來,本著什麼大風大浪我沒見過的心態,斷點堆疊一氣呵成,而下一秒你又望著程式碼陷入了沉思,我是誰?我在幹什麼?

那年我吃了Stream流 toMap() 的苦!

那年我吃了Stream流 toMap() 的苦!

鼓起勇氣,你還不信今天就過不去這個坎了,大手一揮,又一段優雅的程式碼孕育而生。

public class UserTest {
    @Test
    public void demo() {  
        List<User> userList = new ArrayList<>();
        // 模擬資料
        userList.add(new User(1, "Alex"));  
        userList.add(new User(1, "Beth"));
        userList.add(new User(2, null));
        
        Map<Integer, String> map = userList.stream()  
                .collect(Collectors.toMap(  
                    User::getId,  
                    it -> Optional.ofNullable(it.getName()).orElse(""),  
                    (oldData, newData) -> newData)  
                );
        System.out.println(map);  
    }
}

優雅,真是太優雅了,又是 Stream 又是 Optional,可謂是狠狠拿捏技術博文的 G 點了。

那年我吃了Stream流 toMap() 的苦!

這時候你回頭一看,我需要是什麼來著?

這 TM 不是一個迴圈就萬事大吉了嗎,不信邪的你迴歸初心,迴歸了 for 迴圈的懷抱,又寫了一版。

public class UserTest {
    @Test
    public void demo() {  
        List<User> userList = new ArrayList<>();
        // 模擬資料
        userList.add(new User(1, "Alex"));  
        userList.add(new User(1, "Beth"));
        userList.add(new User(2, null));
  
        Map<Integer, String> map = new HashMap<>();  
        userList.forEach(it -> {  
            map.put(it.getId(), it.getName());  
        });  
        System.out.println(map);
    }
}

看著執行完美無缺的程式碼,你一時陷入了沉思,數分鐘過去了,你刪除了 for 迴圈,換上 Stream 與 Optional 不羈的外衣,安心的提交了程式碼,這口細糠一定也要讓好同事去嘗一嘗。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.