2016-04-25 7 views
2

ich eine Situation, wo ich Seite Liste haben enthält Sammlung von Map-Seite, und in Karte habe ich eine andere Liste Gruppen nennen, die wie ist aussehen:Verschachtelte Liste HashMap Verarbeitung in Java Lambda

List<Map<String,Object>> group = new ArrayList<>(); 
Map<String,Object> groupMap = new HashMap<>(); 
groupMap.put("G1F1", null); //<-- null value need to remove from groupMap 
groupMap.put("G1F2", "F2value"); 
groupMap.put("G1F3", "F3value"); 
groupMap.put("G1F4", null);//<-- null value need to remove from groupMap 
group.add(groupMap); 

Map<String,Object> groupMap2 = new HashMap<>(); 
groupMap2.put("G2F1", null);//<-- null value need to remove from groupMap2 
groupMap2.put("G2F2", "F2value"); 
groupMap2.put("G2F3", "F3value"); 
groupMap2.put("G2F4", null);//<-- null value need to remove from groupMap2 
group.add(groupMap2); 

Map<String,Object> page1 = new HashMap<>(); 
page1.put("PageID", "PID1001"); 
page1.put("Groups", group); 

Map<String,Object> page2 = new HashMap<>();//<-- page2 do not have Groups need to remove from pages 
page2.put("PageID", "PID1208"); 
Map<String,Object> page3 = new HashMap<>();//<-- page3 do not have Groups need to remove from pages 
page3.put("PageID", "PID1212"); 
Map<String,Object> page4 = new HashMap<>();//<-- page4 do not have Groups need to remove from pages 
page4.put("PageID", "PID1214"); 
Map<String,Object> page5 = new HashMap<>(); 
page5.put("PageID", "PID15555"); 
page5.put("Groups", group); 

pages.add(page1); 
pages.add(page2); 
pages.add(page3); 
pages.add(page4); 
pages.add(page5); 

In der Obiges Seitenobjekt Ich muss die Seiten entfernen, die keine Gruppen haben, und in den Gruppen muss ich die Elemente entfernen, die einen Nullwert haben.

Ich versuchte mit dem folgenden Code mit Java8 Lamda, aber die Ausgabe ist unerwartet, die wie [true, true, false, false] ist.

Object object = pages.stream().filter(page -> page.containsKey("Groups")) 
    .map(page -> (List) page.get("Groups")) 
      .flatMap(x -> x.stream()).map(group -> ((Map<String,Object>)group).entrySet().removeIf(g -> g.getValue() == null)).collect(Collectors.toList()); 

Ich bin in der Lage, alle Elemente in den Gruppen zu entfernen, die durch den folgenden Code ein Nullwert enthält:

pages.stream().filter(page -> page.containsKey("Groups")) 
    .map(page -> (List) page.get("Groups")).flatMap(x -> x.stream()).forEach(group -> ((Map<String,Object>)group).entrySet().removeIf(entry -> null == entry.getValue())); 

aber nicht in der Lage, die Seiten herauszufiltern bedeutet, wenn die Seite donot enthält jede Gruppen dann muß ich einzelne Anweisung Lambda der Seite Benutzer entfernen, kann ich es herkömmlichen Java Iterationsprozess mit tun, die aussehen wie ist:

private static void sanitizePages() { 
    Iterator<Map<String,Object>> listIt = pages.iterator(); 
    while(listIt.hasNext()) { 
     Map<String,Object> item = listIt.next(); 

     if(!item.containsKey(("Groups"))){ 
      listIt.remove(); 
      continue; 
     } 
     List<Map<String,Object>> groups = (List<Map<String,Object>>)item.get("Groups"); 
     Iterator<Map<String,Object>> groupsIt = groups.iterator(); 

     while(groupsIt.hasNext()) { 
      Map<String,Object> map = groupsIt.next(); 
      Iterator<Entry<String, Object>> groupIt = map.entrySet().iterator(); 
      while(groupIt.hasNext()) { 
       Entry<String,Object> group = groupIt.next(); 
       if(null == group.getValue()) groupIt.remove(); 
      } 
     } 
    } 
} 

Aber ich brauche Lambda-Lösung.

Antwort

3

Zunächst einmal, Streams sind nicht das richtige Werkzeug, wenn Sie ändern möchten Sammlungen, aber beachten Sie, dass es mehrere nützliche Methoden für die Sammlungen selbst.

Wenn Sie einen Preis für die Maximierung der Lambda-Nutzung gewinnen möchten, können Sie verwenden:

pages.removeIf(item -> { 
    List<Map<String,Object>> groups = (List<Map<String,Object>>)item.get("Groups"); 
    if(groups==null) return true; 
    groups.forEach(map -> map.values().removeIf(Objects::isNull)); 
    return false; 
}); 

Aber beachten Sie, dass es gute alte Methoden wie removeAll, die noch arbeiten und sind nicht komplizierter als die Lambda Basis Verwendung:

Set<Object> nulls=Collections.singleton(null); 
pages.removeIf(item -> { 
    List<Map<String,Object>> groups = (List<Map<String,Object>>)item.get("Groups"); 
    if(groups==null) return true; 
    groups.forEach(map -> map.values().removeAll(nulls)); 
    return false; 
}); 

natürlich war der Code einfacher, wenn die Sammlungen nicht mit Object geben wurden, eine ungeprüfte Typumwandlung erfordert ...

+0

Actua Ich fange an, an Lamda zu arbeiten, und es scheint, dass es kompakter Form als der herkömmliche Programmierstil ist, kannst du mir bitte eine Erklärung geben, warum der Strom nicht korrekt ist, um die Sammlung zu ändern, ist es Leistungsproblem oder besser nicht Stream für Sammlungsänderung verwenden – Assad

+0

Es ist nicht ihre beabsichtigte Verwendung. Im Allgemeinen wird davon abgeraten, Nebenwirkungen in Funktionen zu haben, die an Stream-Operationen übergeben werden. Wenn die Nebenwirkungen die Einschränkung [Nicht-Interferenz] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#NonInterference) verletzen, muss der Code sein als fehlerhaft angesehen werden (und dazu führen können, dass Ausnahmen oder, noch schlimmer, stille Daten während der Laufzeit beschädigt werden; je nach den Umständen scheint es manchmal sogar zu funktionieren). Streams eignen sich gut zum * Verarbeiten * der Elemente einer Sammlung. Sie können das Ergebnis in einer neuen Sammlung sammeln, aber nicht ändern. – Holger

+0

Dies bedeutet nicht, dass Sie Collection-Vorgänge mit Lambda-Ausdrücken nicht vereinfachen können. Sie können die neuen Methoden verwenden, die von der Collection API angeboten werden, wie in meiner Antwort gezeigt. Diese sind nicht mit der Stream-API zu verwechseln. Siehe 'Iterable.forEach' und' Collection.removeIf' (beide in meiner Antwort) oder 'List.replaceAll',' Map.forEach', 'Map.merge' usw. – Holger