我剛剛開始研究Java 8並嘗試使用lambdas,我認爲我會嘗試重寫最近編寫的一個非常簡單的東西。我需要將一個字符串映射到列到另一個字符串映射到列的位置,其中新映射中的列是第一個映射中列的防禦副本。列有一個拷貝構造函數。到目前爲止,我所得到的最接近的是:在Java 8中,如何使用lambda?將地圖<K,V>轉換爲另一個地圖<K,V>?
,但我敢肯定,必須有做一個更好的方式,我會爲一些建議表示感謝。
我剛剛開始研究Java 8並嘗試使用lambdas,我認爲我會嘗試重寫最近編寫的一個非常簡單的東西。我需要將一個字符串映射到列到另一個字符串映射到列的位置,其中新映射中的列是第一個映射中列的防禦副本。列有一個拷貝構造函數。到目前爲止,我所得到的最接近的是:在Java 8中,如何使用lambda?將地圖<K,V>轉換爲另一個地圖<K,V>?
,但我敢肯定,必須有做一個更好的方式,我會爲一些建議表示感謝。
你可以使用一個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) {}
}
}
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);
沒有重新插入的方式將所有條目插入到新映射中應該是最快的它不會因爲HashMap.clone
也在內部執行rehash。
Map<String, Column> newColumnMap = originalColumnMap.clone();
newColumnMap.replaceAll((s, c) -> new Column(c));
這是一個非常可讀的方式,它非常簡潔。它看起來像HashMap.clone()那樣是Map
這種方法的優點是保持'Map'實現的行爲,即如果'Map'是一個'EnumMap'或一個'SortedMap',則最終的'Map'也是如此。對於帶有特殊「比較器」的'SortedMap',它可能會產生巨大的語義差異。哦,這同樣適用於'IdentityHashMap' ... – Holger
如果你不介意使用第三方庫,我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
這裏是允許您訪問的關鍵,並在同一時間的價值的另一種方式,如果你有做某種的轉化。
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));
保持簡單和使用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())
);
我喜歡你如何解釋到底發生了什麼幕後這裏,這使得它更清晰。但我認爲這只是給了我原始地圖的一個直接副本,而不是一張價值已經變成防禦性副本的新地圖。我正確理解你,我們可以使用的原因(map2 :: put)是相同的參數進入lambda,例如, (s,integer)進入put方法嗎?所以要做一個防禦性的副本,它需要是'originalColumnMap.forEach((字符串,列) - > newColumnMap.put(字符串,新的列(列)));'或我可以縮短? – annesadleir
是的,你是。如果你只是傳入相同的參數,你可以使用方法引用,但是在這種情況下,因爲你有'新列(列)'作爲參數,你必須去做。 – Arrem
我更喜歡這個答案,因爲如果兩個地圖都已經提供給你,比如在會話更新中,它就可以工作。 –