Nella maggior parte dei casi, quando si utilizza forEach
su un flusso, è necessario riconsiderare se si sta utilizzando lo strumento giusto per il proprio lavoro o se lo si sta utilizzando nel modo corretto.
In genere, è necessario cercare un'operazione di terminale appropriata che esegua ciò che si desidera ottenere o per un servizio di raccolta appropriato. Ora, ci sono i collezionisti per produrre Map
se List
s, ma nessun collettore pronto all'uso per combinare due diversi raccoglitori, in base a un predicato.
Ora, this answer contiene un raccoglitore per la combinazione di due collettori. Usando questo collettore, è possibile ottenere l'attività come
Pair<Map<KeyType, Animal>, List<KeyType>> pair = animalMap.entrySet().stream()
.collect(conditional(entry -> entry.getValue() != null,
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue),
Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
Map<KeyType,Animal> myMap = pair.a;
List<KeyType> myList = pair.b;
Ma forse, si può risolvere questo compito specifico in modo più semplice. Uno di voi risultati corrisponde al tipo di input; è la stessa mappa appena spogliata delle voci che mappano a null
.Se la vostra mappa originale è mutevole e non è necessario che in seguito, si può solo raccogliere la lista e rimuovere questi tasti dalla mappa originale in quanto si escludono a vicenda:
List<KeyType> myList=animalMap.entrySet().stream()
.filter(pair -> pair.getValue() == null)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
animalMap.keySet().removeAll(myList);
Si noti che è possibile rimuovere i mapping di null
anche senza avere l'elenco delle altre chiavi:
animalMap.values().removeIf(Objects::isNull);
o
animalMap.values().removeAll(Collections.singleton(null));
Se non puoi (o non vuoi) modificare la mappa originale, c'è ancora una soluzione senza un raccoglitore personalizzato. Come accennato in Alexis C.’s answer, partitioningBy
sta andando nella giusta direzione, ma si può semplificare:
Map<Boolean,Map<KeyType,Animal>> tmp = animalMap.entrySet().stream()
.collect(Collectors.partitioningBy(pair -> pair.getValue() != null,
Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
Map<KeyType,Animal> myMap = tmp.get(true);
List<KeyType> myList = new ArrayList<>(tmp.get(false).keySet());
La linea di fondo è, non dimenticare le operazioni di raccolta ordinaria, non c'è bisogno di fare tutto con la nuova API Stream.
Sembra una situazione in cui gli stream non ti stanno facendo alcun favore. Si nasconde semplicemente la sintassi del flusso di controllo con le API in un modo che risulta essere scomodo e il tuo 'forEach' lambda è di stato. – Radiodef