2016-02-28 70 views
2

任何方式使用Java 8Java來收集轉換成一個鍵多個值映射

 final Map<String, Collection<ProductStrAttributeOverrideRulesModel>> attributeRulesMap = new HashMap<String, Collection<ProductStrAttributeOverrideRulesModel>>(); 
     for (final ProductStrAttributeOverrideRulesModel rule : rules) 
     { 
      final String key = rule.getProductStrAttributeOverride().getProductStrTypeField().getAttributeDescriptorQualifier(); 
      if (attributeRulesMap.containsKey(key)) 
      { 
       final Collection<ProductStrAttributeOverrideRulesModel> currentRules = attributeRulesMap.get(key); 
       currentRules.add(rule); 
      } 
      else 
      { 
       final Collection<ProductStrAttributeOverrideRulesModel> list = new LinkedList<ProductStrAttributeOverrideRulesModel>(); 
       list.add(rule); 
       attributeRulesMap.put(key, list); 
      } 
     } 

執行下面的代碼,如果它僅僅是

final Map<String, ProductStrAttributeOverrideRulesModel> attributeRulesMap 

比我可以這樣做以下8路但我需要根據關鍵字將整個集合安排在地圖中,並且每個關鍵字可以具有存儲在集合中的多個值。

Map<String, ProductStrAttributeOverrideRulesModel> result = 
choices.stream().collect(Collectors.toMap(ProductStrAttributeOverrideRulesModel::getProductStrAttributeOverride.getProductStrTypeField.getAttributeDescriptorQualifier, 
              Function.identity())); 
+2

對於Java 8之前的代碼,這有點反模式。你可以簡單地使用兩個地圖查找('containsKey'和'get')。這使得代碼可能慢很多。 –

+0

你提到了一個好點的鮑里斯。非常感謝。 –

+0

@BoristheSpider如果有一對'(「something」,null)','containsKey(「something」)'將返回'true',但get(「something」)'將返回'null' - 結果相同彷彿根本沒有這樣的鑰匙。 –

回答

3

你可以使用groupingBy

Map<String,List<ProductStrAttributeOverrideRulesModel>> 
    map = 
     choices.stream() 
       .collect(Collectors.groupingBy(rule -> rule.getProductStrAttributeOverride().getProductStrTypeField().getAttributeDescriptorQualifier())); 

如果你不想做List,你可以傳遞第二個參數給groupingBy,並指定你想要的任何Collection。例如:

Map<String,Collection<ProductStrAttributeOverrideRulesModel>> 
    map = 
     choices.stream() 
       .collect(Collectors.groupingBy(rule -> rule.getProductStrAttributeOverride().getProductStrTypeField().getAttributeDescriptorQualifier(), 
               Collectors.toCollection(HashSet::new))); 
+0

最終地圖<字符串,列表>地圖= rules.stream()收集(Collectors.groupingBy( \t \t \t \t規則 - > rule.getProductStrAttributeOverride()getProductStrTypeField()。getAttributeDescriptorQualifier()));給我以下錯誤類型不匹配:無法從映射>轉換爲映射> –

+2

@SaurabhKumar getAttributeDescriptorQualifier()方法返回String嗎? – Eran

+0

是的,它返回字符串 –

1

注意,它並不總是必須是Stream操作。您的代碼也將受益於使用「鑽石運算符」(雖然對於Java 8來說並不陌生)以及使用新的集合操作(​​即computeIfAbsent),該操作允許在循環內省略整個條件及其代碼重複。把兩者放在一起,你會得到:

final Map<String, Collection<ProductStrAttributeOverrideRulesModel>> 
                attributeRulesMap = new HashMap<>(); 
for(final ProductStrAttributeOverrideRulesModel rule: rules) 
{ 
    final String key = rule.getProductStrAttributeOverride() 
     .getProductStrTypeField().getAttributeDescriptorQualifier(); 
    attributeRulesMap.computeIfAbsent(key, x->new LinkedList<>()).add(rule); 
} 

您還可以通過一個forEach調用替換循環,如果你想:

rules.forEach(rule -> attributeRulesMap.computeIfAbsent(
    rule.getProductStrAttributeOverride() 
     .getProductStrTypeField().getAttributeDescriptorQualifier(), 
    x->new LinkedList<>()).add(rule) 
); 

雖然這是值得商榷的,這是否是在古典循環的改善這裏...