2016-03-23 16 views
8

mam String i HashMap jak poniżej kodów:Wymień String o wartości HashMap używając Java 8 strumień

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

i staram się zastąpić ciąg z wartościami HashMap, ale to nie działa, ponieważ test jest ostateczna i nie można ponownie przydzielić w treści forEach.

Więc czy są jakieś rozwiązania, które zastąpią String z HashMap wykorzystujące Java 8 Stream API?

+2

'foreach()' nie jest zsynchronizowany. Twój kod nie kompiluje się, ponieważ nie możesz mieć efektu ubocznego na 'wiadomość' od wewnątrz wyrażenia lambda. Nawet gdybyś mógł, wszystko, co dostałeś, to 'wiadomość' zawierająca ostatnią zamianę' testu' na ostatni wpis mapy na mapie. Które prawdopodobnie nie jest tym, czego chcesz. Również dlatego, że "ostatni wpis na mapie" jest niedeterministyczny dla 'HashMap'. – Ralf

+0

OK Dzięki, mam to. ale co mam zrobić, aby uzyskać całą zawartość testu, która już została zastąpiona? –

Odpowiedz

3

Jak to nie może być wykonane przy użyciu tylko forEach() (message musi być skutecznie końcowy), obejście mogłoby być stworzenie ostatecznego pojemnika (np List), który przechowuje jeden String że jest ponownie napisane:

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); 

Zauważ, że zmieniłam replaceAll() na replace(), ponieważ poprzednia działa z regex, ale sądząc po kodzie, wydaje ci się, że potrzebujesz zamiany za pomocą samego ciągu (nie martw się, pomimo mylącej nazwy zastępuje on także wszystkie wystąpienia).

Jeśli chcesz dokładnie Stream API można użyć reduce() operacji:

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

jednak wziąć pod uwagę, że takie ograniczenie będzie działać prawidłowo tylko w port szeregowy (nie równolegle) strumień, gdzie funkcja sumator jest nigdy nie był wywoływany (a więc może być dowolny).

+0

Już go wypróbowałem, ale wydaje się to trudne. i jak mamy wiele elementów w Mapie? –

+0

@ChheaVanrin '0' odnosi się do' List', a nie do 'Mapy'. 'forEach()' przetworzy tyle pozycji na mapie, ile masz. –

+0

Niestety nie widziałem tego wyraźnie :). ale nie wydaje się to logiczne. Po prostu chcę pracować z pełnym strumieniem w języku Java 8. Dzięki i tak :) –

3

Ten rodzaj problemu nie jest dobrze dopasowany do interfejsu API strumieni. Obecne wcielenie Strumieni jest głównie ukierunkowane na zadania, które mogą być realizowane równolegle. Być może wsparcie dla tego typu operacji zostanie dodane w przyszłości (patrz https://bugs.openjdk.java.net/browse/JDK-8133680).

Jedno podejście oparte strumienie, które można znaleźć interesujące jest zmniejszenie o funkcjach zamiast na ciąg:

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

Wydaje się, że nie ma szansy na zobaczenie 'foldLeft' w Java-9. Niestety. –

+1

@TagirValeev Widziałem twoje wysiłki na liście mailingowej core-lib kilka miesięcy temu. Dziękuję za próbowanie. – Misha