へっぽこITエンジニア@名古屋のブログ

Follow me on GitHub

List→Mapの変換で順序を保持する

JavaのList→Mapの変換をラムダ式で普通に実施するとListの順序が保持されません。保持する方法を記載します。

まずは、以下のようなプログラムを作成しました。

public class Main {

  public static void main(String[] args) throws Exception {

    @Getter
    class Test{
      String key;
      String value;
      
      Test(String key, String value){
        this.key = key;
        this.value = value;
      }
    }
    
    List<Test> testList = new ArrayList<>();
    
    for(int i = 0; i < 10; i++) {
      Test test = new Test("key" + i, "value" + i);
      testList.add(test);
    }
    
    Map<String, String> testMap =testList.stream()
      .collect(Collectors.toMap(
        Test::getKey,
        Test::getValue
        )
      );
    
    testMap.forEach((u, v) -> 
        System.out.println(u + " "+ v)
    );  
  }
}

実行すると以下のような結果が出て、順番がバラバラになります。

key1 value1
key2 value2
key0 value0
key5 value5
key6 value6
key3 value3
key4 value4
key9 value9
key7 value7
key8 value8

これで以下のCollectors.toMapの部分を変更します。

Map<String, String> testMap =testList.stream()
  .collect(Collectors.toMap(
    Test::getKey,
    Test::getValue,
    (u, v) -> v, // この行を追加
    LinkedHashMap::new // この行を追加
    )
  );

そうすると結果は以下のように順番になります。

key0 value0
key1 value1
key2 value2
key3 value3
key4 value4
key5 value5
key6 value6
key7 value7
key8 value8
key9 value9

しかし、このままだとkeyが重複したときに後勝ちになります。 試しにfor分の後に以下のように書いてみましょう。

Test add = new Test("key0", "value10");
testList.add(add);

そうすると、以下のように値が変わります。

key0 value10
key1 value1
key2 value2
key3 value3
key4 value4
key5 value5
key6 value6
key7 value7
key8 value8
key9 value9

キーが重複した場合にExceptionを出したい場合は (u, v) -> vここの部分を(u, v) -> {throw new IllegalArgumentException();}と変えることことで キーが重複している場合にExceptionをThrowします。

まとめ

List→Mapにラムダ式で変換する場合に、順序を保持するには、Collectors.toMapで以下を追加すれ場可能です。

  (u, v) -> v, // この行を追加
  LinkedHashMap::new // この行を追加

(u, v) -> vここの部分を(u, v) -> {throw new IllegalArgumentException();}と変えることで キーが重複している場合にExceptionをThrowできます。

作成日:2022-07-18  更新日:2022-07-19