2014-03-30 121 views
83

我剛剛開始研究Java 8並嘗試使用lambdas,我認爲我會嘗試重寫最近編寫的一個非常簡單的東西。我需要將一個字符串映射到列到另一個字符串映射到列的位置,其中新映射中的列是第一個映射中列的防禦副本。列有一個拷貝構造函數。到目前爲止,我所得到的最接近的是:在Java 8中,如何使用lambda?將地圖<K,V>轉換爲另一個地圖<K,V>?

,但我敢肯定,必須有做一個更好的方式,我會爲一些建議表示感謝。

回答

122

你可以使用一個Collector

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

public class Defensive { 

    public static void main(String[] args) { 
    Map<String, Column> original = new HashMap<>(); 
    original.put("foo", new Column()); 
    original.put("bar", new Column()); 

    Map<String, Column> copy = original.entrySet() 
     .stream() 
     .collect(Collectors.toMap(Map.Entry::getKey, 
            e -> new Column(e.getValue()))); 

    System.out.println(original); 
    System.out.println(copy); 
    } 

    static class Column { 
    public Column() {} 
    public Column(Column c) {} 
    } 
} 
18
Map<String, Integer> map = new HashMap<>(); 
    map.put("test1", 1); 
    map.put("test2", 2); 

    Map<String, Integer> map2 = new HashMap<>(); 
    map.forEach(map2::put); 

    System.out.println("map: " + map); 
    System.out.println("map2: " + map2); 
    //Output: 
    //map: {test2=2, test1=1} 
    //map2: {test2=2, test1=1} 

您可以使用forEach方法做你想做的。

你在做什麼有:

map.forEach(new BiConsumer<String, Integer>() { 
     @Override 
     public void accept(String s, Integer integer) { 
      map2.put(s, integer);  
     } 
    }); 

,我們可以簡化爲lambda:

map.forEach((s, integer) -> map2.put(s, integer)); 

而且因爲我們只是調用現有的方法,我們可以使用一個method reference,這給了我們:

map.forEach(map2::put); 
+5

我喜歡你如何解釋到底發生了什麼幕後這裏,這使得它更清晰。但我認爲這只是給了我原始地圖的一個直接副本,而不是一張價值已經變成防禦性副本的新地圖。我正確理解你,我們可以使用的原因(map2 :: put)是相同的參數進入lambda,例如, (s,integer)進入put方法嗎?所以要做一個防禦性的副本,它需要是'originalColumnMap.forEach((字符串,列) - > newColumnMap.put(字符串,新的列(列)));'或我可以縮短? – annesadleir

+0

是的,你是。如果你只是傳入相同的參數,你可以使用方法引用,但是在這種情況下,因爲你有'新列(列)'作爲參數,你必須去做。 – Arrem

+0

我更喜歡這個答案,因爲如果兩個地圖都已經提供給你,比如在會話更新中,它就可以工作。 –

10

沒有重新插入的方式將所有條目插入到新映射中應該是最快的它不會因爲HashMap.clone也在內部執行rehash。

Map<String, Column> newColumnMap = originalColumnMap.clone(); 
newColumnMap.replaceAll((s, c) -> new Column(c)); 
+0

這是一個非常可讀的方式,它非常簡潔。它看起來像HashMap.clone()那樣是Map newColumnMap = new HashMap <>(originalColumnMap);'。我不知道在封面下是否有任何不同。 – annesadleir

+2

這種方法的優點是保持'Map'實現的行爲,即如果'Map'是一個'EnumMap'或一個'SortedMap',則最終的'Map'也是如此。對於帶有特殊「比較器」的'SortedMap',它可能會產生巨大的語義差異。哦,這同樣適用於'IdentityHashMap' ... – Holger

2

如果你不介意使用第三方庫,我cyclops-react LIB對所有JDK Collection類型,包括Map擴展。您可以直接使用map或bimap方法來轉換您的地圖。 MapX可以從現有的Map構造而成,例如。

MapX<String, Column> y = MapX.fromMap(orgColumnMap) 
           .map(c->new Column(c.getValue()); 

如果你也想改變的關鍵,你可以寫

MapX<String, Column> y = MapX.fromMap(orgColumnMap) 
           .bimap(this::newKey,c->new Column(c.getValue()); 

bimap的可用於在同一時間轉換鍵和值。

,像MapX擴展地圖生成的地圖也可以被定義爲

Map<String, Column> y 
0

這裏是允許您訪問的關鍵,並在同一時間的價值的另一種方式,如果你有做某種的轉化。

Map<String, Integer> pointsByName = new HashMap<>(); 
Map<String, Integer> maxPointsByName = new HashMap<>(); 

Map<String, Double> gradesByName = pointsByName.entrySet().stream() 
     .map(entry -> new AbstractMap.SimpleImmutableEntry<>(
       entry.getKey(), ((double) entry.getValue()/
         maxPointsByName.get(entry.getKey())) * 100d)) 
     .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); 
-1

保持簡單和使用Java 8: -

Map<String, AccountGroupMappingModel> mapAccountGroup=CustomerDAO.getAccountGroupMapping(); 
Map<String, AccountGroupMappingModel> mapH2ToBydAccountGroups = 
       mapAccountGroup.entrySet().stream() 
         .collect(Collectors.toMap(e->e.getValue().getH2AccountGroup(), 
                e ->e.getValue()) 
           ); 
相關問題