1. 程式人生 > >Java 8 – Convert List to Map(將 List 轉換為 Map)

Java 8 – Convert List to Map(將 List 轉換為 Map)

   幾個Java 8的例子展示怎樣將一個 物件的集合(List)放入一個Map中,並且展示怎樣處理多個重複keys的問題。

Hosting.java
package com.mkyong.java8

public class Hosting {

    private int Id;
    private String name;
    private long websites;

    public Hosting(int id, String name, long websites) {
        Id = id;
        this.name = name;
this.websites = websites; } //getters, setters and toString() }

1. List to Map – Collectors.toMap()

建立一個 Hosting 物件集合, 並且用 Collectors.toMap 去將它轉換放入一個 Map.

TestListMap.java
package com.mkyong.java8

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.
util.stream.Collectors; public class TestListMap { public static void main(String[] args) { List<Hosting> list = new ArrayList<>(); list.add(new Hosting(1, "liquidweb.com", 80000)); list.add(new Hosting(2, "linode.com", 90000)); list.add(new Hosting(3, "digitalocean.com"
, 120000)); list.add(new Hosting(4, "aws.amazon.com", 200000)); list.add(new Hosting(5, "mkyong.com", 1)); // key = id, value - websites Map<Integer, String> result1 = list.stream().collect( Collectors.toMap(Hosting::getId, Hosting::getName)); System.out.println("Result 1 : " + result1); // key = name, value - websites Map<String, Long> result2 = list.stream().collect( Collectors.toMap(Hosting::getName, Hosting::getWebsites)); System.out.println("Result 2 : " + result2); // Same with result1, just different syntax // key = id, value = name Map<Integer, String> result3 = list.stream().collect( Collectors.toMap(x -> x.getId(), x -> x.getName())); System.out.println("Result 3 : " + result3); } }

Output

Result 1 : {1=liquidweb.com, 2=linode.com, 3=digitalocean.com, 4=aws.amazon.com, 5=mkyong.com}
Result 2 : {liquidweb.com=80000, mkyong.com=1, digitalocean.com=120000, aws.amazon.com=200000, linode.com=90000}
Result 3 : {1=liquidweb.com, 2=linode.com, 3=digitalocean.com, 4=aws.amazon.com, 5=mkyong.com}

2. List to Map – Duplicated Key! (List轉Map 重複key問題)

2.1 Run below code, and duplicated key errors will be thrown!

TestDuplicatedKey.java
package com.mkyong.java8;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TestDuplicatedKey {

    public static void main(String[] args) {

        List<Hosting> list = new ArrayList<>();
        list.add(new Hosting(1, "liquidweb.com", 80000));
        list.add(new Hosting(2, "linode.com", 90000));
        list.add(new Hosting(3, "digitalocean.com", 120000));
        list.add(new Hosting(4, "aws.amazon.com", 200000));
        list.add(new Hosting(5, "mkyong.com", 1));

        list.add(new Hosting(6, "linode.com", 100000)); // new line

        // key = name, value - websites , but the key 'linode' is duplicated!?
        Map<String, Long> result1 = list.stream().collect(
                Collectors.toMap(Hosting::getName, Hosting::getWebsites));

        System.out.println("Result 1 : " + result1);

    }
}

輸出:下面這個錯誤有的誤導,它應該顯示 “linode” 代替key的值。

Exception in thread "main" java.lang.IllegalStateException: Duplicate key 90000
	at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
	at java.util.HashMap.merge(HashMap.java:1245)
	//...

2.2  為了解決上面重複key的問題,通過增加第三個引數解決:

Map<String, Long> result1 = list.stream().collect(
                Collectors.toMap(Hosting::getName, Hosting::getWebsites,
                        (oldValue, newValue) -> oldValue
                )
        );

Output

Result 1 : {..., aws.amazon.com=200000, linode.com=90000}
Note
(oldValue, newValue) -> oldValue ==> 如果key是重複的,你選擇oldKey or newKey?

3.3 Try newValue

Map<String, Long> result1 = list.stream().collect(
                Collectors.toMap(Hosting::getName, Hosting::getWebsites,
                        (oldValue, newValue) -> newvalue
                )
        );

Output

Result 1 : {..., aws.amazon.com=200000, linode.com=100000}

3. List to Map – Sort & Collect

TestSortCollect.java
package com.mkyong.java8;

import java.util.*;
import java.util.stream.Collectors;

public class TestSortCollect {

    public static void main(String[] args) {

        List<Hosting> list = new ArrayList<>();
        list.add(new Hosting(1, "liquidweb.com", 80000));
        list.add(new Hosting(2, "linode.com", 90000));
        list.add(new Hosting(3, "digitalocean.com", 120000));
        list.add(new Hosting(4, "aws.amazon.com", 200000));
        list.add(new Hosting(5, "mkyong.com", 1));
        list.add(new Hosting(6, "linode.com", 100000));

        //example 1
        Map result1 = list.stream()
                .sorted(Comparator.comparingLong(Hosting::getWebsites).reversed())
                .collect(
                        Collectors.toMap(
                                Hosting::getName, Hosting::getWebsites, // key = name, value = websites
                                (oldValue, newValue) -> oldValue,       // if same key, take the old key
                                LinkedHashMap::new                      // returns a LinkedHashMap, keep order
                        ));

        System.out.println("Result 1 : " + result1);

    }
}

Output

Result 1 : {aws.amazon.com=200000, digitalocean.com=120000, linode.com=100000, liquidweb.com=80000, mkyong.com=1}

P.S  在上面的例子中, stream 在collect 之前已經被排序, 所以 “linode.com=100000”變為 ‘oldValue’.

References