2016-03-23 18 views
8

ho String e HashMap come qui di seguito i codici:Sostituire stringa con valore hashmap usando Java 8 flusso

Map<String, String> map = new HashMap<>(); 
    map.put("ABC", "123"); 
    String test = "helloABC"; 
    map.forEach((key, value) -> { 
     test = test.replaceAll(key, value); 
    }); 

e cerco di sostituire la stringa con i valori HashMap, ma questo non funziona perché test è finale e non può essere riassegnato nel corpo di forEach.

Quindi ci sono soluzioni per sostituire String con HashMap utilizzando Java 8 Stream API?

+2

'foreach()' non è sincronizzato. Il tuo codice non viene compilato perché non puoi avere un effetto collaterale su 'message' dall'interno della tua espressione lambda. Anche se tu potessi, tutto quello che otterresti è "messaggio" contenente l'ultima sostituzione su "test" per l'ultima voce sulla mappa nella mappa. Che probabilmente non è quello che vuoi. Anche perché "ultima voce sulla mappa" non è deterministica per 'HashMap'. – Ralf

+0

Ok grazie, ho capito. ma cosa dovrei fare per ottenere tutti i contenuti del test che sono già stati sostituiti? –

risposta

3

Poiché ciò non può essere fatto utilizzando solo forEach() (message deve essere efficacemente finale), soluzione potrebbe essere quella di creare un contenitore finale (ad esempio List) che memorizza un singolo String che viene riscritta:

final List<String> msg = Arrays.asList("helloABC"); 
map.forEach((key, value) -> msg.set(0, msg.get(0).replace(key, value))); 
String test = msg.get(0); 

Notare che ho modificato in replace() perché l'ex funziona con espressioni regolari, ma a giudicare dal codice sembra che sia necessario sostituire la stringa stessa (non preoccuparti, nonostante il nome confuso sostituisce anche tutte le occorrenze).

Se si vuole esattamente Trasmettere in streaming API, è possibile utilizzare reduce() funzionamento:

String test = map.entrySet() 
       .stream() 
       .reduce("helloABC", 
         (s, e) -> s.replace(e.getKey(), e.getValue()), 
         (s1, s2) -> null); 

Ma prendere in considerazione, che tale riduzione funzionerà correttamente solo in serie (non parallelo) flusso, in cui la funzione combinatore è mai chiamato (quindi potrebbe essere qualsiasi).

+0

L'ho già provato, ma sembra così difficile. e come se abbiamo molti elementi in Map? –

+0

@ChheaVanrin '0' si riferisce a' Elenco', non a 'Mappa'. 'forEach()' elaborerà tutte le voci della mappa che hai. –

+0

Scusa se non l'ho visto chiaramente :). ma non sembra così logico. Voglio solo lavorare con stream completamente java 8. Grazie comunque :) –

3

Questo tipo di problema non è adatto per l'API di Streams. L'attuale incarnazione degli Stream è principalmente diretta a compiti che possono essere fatti paralleli. Forse il supporto per questo tipo di operazione verrà aggiunto in futuro (vedere https://bugs.openjdk.java.net/browse/JDK-8133680).

Un approccio flussi-based che si potrebbe trovare interessante è quello di ridurre il funzioni, piuttosto che sulla stringa:

Function<String, String> combined = map.entrySet().stream() 
    .reduce(
     Function.identity(), 
     (f, e) -> s -> f.apply(s).replaceAll(e.getKey(), e.getValue()), 
     Function::andThen 
    ); 

String result = combined.apply(test); 
+3

Sembra che non ci sia la possibilità di vedere 'foldLeft' in Java-9. Purtroppo. –

+1

@TagirValeev Ho visto i tuoi sforzi sulla mailing list di core-lib alcuni mesi fa. Grazie per averci provato. – Misha

Problemi correlati