2015-07-08 19 views
6

Chcę szybko utworzyć ciąg par wartości klucza mojego HashMap<String, String> m.Jak przekonwertować mapę HashMap na ciąg znaków K/V w języku Java 8 ze strumieniami

Próbowałem:

StringBuffer buf = new StringBuffer(); 
buf.append("["); 
for (String key : m.keySet()) { 
    buf.append(key); 
    buf.append("="); 
    buf.append(m.get(key)); 
    buf.append(";"); 
} 
buf.append("]"); 

Z Java8 Próbowałem:

m.entrySet().stream() 
      .map(entry -> entry.getKey() + " = " + entry.getValue()) 
      .collect(Collectors.joining("; " , "[" , "]")); 

Czy istnieje szybszy, lepszy kod, aby to zrobić? Wydaje się, że kosztowne jest dołączanie kluczy i wartości do funkcji mapy, prawda?

+3

Kiedy profilowałeś oba te podejścia, które działały szybciej niż inne? A ile szybciej? –

+4

Nie martwiłbym się o wydajność w tym przypadku ** chyba że ** jest krytyczną częścią systemu i jest wskazane jako wąskie gardło przez użycie profilera lub podobnego narzędzia. Jeśli jeszcze tego nie zrobiłeś i * uważasz, że * ten kod nie jest optymalny, to znaczy, że się mylisz i powinieneś go najpierw przetestować. –

+0

FWIW - Wynik 'm.toString()' może być wystarczająco blisko, aby nie miało to znaczenia. –

Odpowiedz

8
map -> map.entrySet().stream().map(Entry::toString).collect(joining(";", "[", "]")) 

(Zauważ, że pominąłem importu).

Jak Luiggi Mendoza powiedział:

Nie martwiłbym się o wydajność w tym przypadku, chyba że jest to krytyczny częścią system i wskazano jako wąskie gardło za pomocą profilera lub podobnego narzędzia. Jeśli nie zrobiłeś tego wcześniej i uważasz, że ten kod nie jest optymalny, to ja się nie mylę i powinienem to najpierw przetestować.

+3

W wywołaniu OP" Collectors.joining() "został wykluczony ogranicznik, prefiks, sufiks. Twoje rozwiązanie to naprawiło. –

+3

Należy zauważyć, że podczas gdy 'Entry.toString()' zwykle zwraca 'klucz = wartość', nie jest to jawnie wymagane przez [Entry] (http://docs.oracle.com/javase/7/docs/api/java/util /Map.Entry.html), więc możesz trafić w implementację mapy, która zwraca coś innego. Wolałbym bezpośrednie łączenie, jak w pytaniu. –

+0

Sprawdziłem interfejs 'Entry'. Nie mogłem udoskonalić żadnej deklaracji 'toString'. Czy mógłbyś wyjaśnić, jak definiować 'Entry :: toString()? Inną rzeczą, tylko 'Entry :: toString' nie może rozwiązać w moim końcu. Muszę wykonać 'Map.Entry :: toString()'. – seal

0

Użyj StringBuilder zamiast bufora.

Javadoc => Klasa StringBuffer

„Klasa StringBuilder powinny być powszechnie stosowane w preferencji do tego, ponieważ obsługuje wszystkie te same operacje, ale jest szybsze, gdyż nie wykonuje żadnej synchronizacji.” Class StringBuffer

+2

Pytanie OP dotyczy drugiego fragmentu kodu. –

+0

jest szybszy niż rozwiązanie ze strumieniem? Czy można je połączyć? – Joel

+0

Podczas używania StringBuilder może być szybszy niż StringBuffer dla pierwszego kawałka kodu, pytanie jest w szczególności o prędkości drugiego fragmentu kodu, jak wskazuje @LuiggiMendoza. – Vulcan

-1
@Test 
public void testMapPrint() { 
    Map<String, String> map = new HashMap<>(); 
    map.put("a", "b"); 
    map.put("c", "d"); 

    map.entrySet().stream() 
      .forEach(entry -> System.out.println(entry.getKey() + ":" + entry.getValue())); 
} 
+0

Drukowanie każdej pary na konsoli zajmuje osobno dużo czasu. Zbieranie wszystkiego w String {Builder, Builder}, a następnie drukowanie jest prawdopodobnie szybsze. –

+0

Cóż, jeśli chcesz przejść do mikrobezpieczenia, powinieneś również wziąć pod uwagę sytuację, w której rozszerzenie tablicy znaków w konstruktorze ciągu rozszerza się (jest to również kosztowne, domyślnie char [16] jest tworzone) :) – rgrebski

+0

Jeśli chcesz wydrukować mapę bezpośrednio, nie jest potrzebne "Strumień". Po prostu użyj 'map.forEach ((k, v) -> System.out.println (k +": "+ v)); – Holger

Powiązane problemy