0

I have a method that iterates over a Map and performs an operation on the value and populates a Map to return.

My question is, how do I convert this to Java 8 (perform the operation without looping)?

Code:

private static Map<String, Object> iterateAndConvertValueXmlToString(Map<String, Object> data) {
    Map<String, Object> returnMap = new HashMap<>();
    for (Map.Entry<String,Object> entry : data.entrySet()) {
        returnMap.put(entry.getKey(), getXmlAsString((String)entry.getValue()));
    }
    return returnMap;
}
tomrozb
  • 23,522
  • 30
  • 89
  • 110
David
  • 573
  • 3
  • 6
  • 12

3 Answers3

2
private static Map<String, Object> convertXmlValueToString(Map<String, Object> data) {
    return data.entrySet().stream().collect(Collectors.toMap(
        Map.Entry::getKey,
        entry -> getXmlAsString((String)entry.getValue())
    ));
}

Btw.: Shouldn't the return type be Map<String, String> rather than Map<String, Object>?

isnot2bad
  • 22,602
  • 2
  • 27
  • 43
2

Avoid forEach unless absolutely needed, favor collectors instead.

   public static final String getXmlAsString(final Object xmlObject) {

        return xmlObject.toString();

    }

    public static final Map<String, String> xmlObjectToString(final Map<String, Object> xmlObjectsByString) {
        return xmlObjectsByString.entrySet()
                .stream()
                .collect(Collectors.toMap(Map.Entry::getKey, entry -> getXmlAsString(entry.getValue())));
    }

    public static final void main(final String... args) {

        final Map<String, Object> xmlObjectsByString = new HashMap<>();
        xmlObjectsByString.put("Mykey", "<xml/>");

        final Map<String, String> xmlStringsByString = xmlObjectToString(xmlObjectsByString);

        // {Mykey=<xml/>}
        System.out.println(xmlStringsByString);
    }
Jeff
  • 3,104
  • 1
  • 19
  • 22
  • Are collectors more efficient? Please explain why collectors are preferred. – David Jul 23 '14 at 13:41
  • 2
    ForEach works via side effects. In the forEach answer it is populating a map that was created outside of the stream's internal scope. When using collect we can guarantee that the returnMap won't be mutated before it is populated. We can't say that with forEach. Limiting forEach usage to when we have to side effect tends to be safer and easier to reason about in the long run. Also collect allows us to directly construct immutable collections in a single step, further enhancing program saftey. – Jeff Jul 23 '14 at 13:54
  • @Jeff very good point! I think avoiding side-effects is/will be the most ignored rule of stream API. Btw.: There is a small bug in your code: `Collectors.toMap` requires a `Function` as second argument. So `getXmlAsString` should have `Map.Entry` as parameter. – isnot2bad Jul 23 '14 at 15:40
0

Quick pseudo code may lead to something like this -

data.entrySet().forEach((entry) -> returnMap.put(entry.getKey(), getXmlAsString((String)entry.getValue())));
return returnMap;
Ved
  • 7,667
  • 6
  • 33
  • 68
  • 2
    If we're trying to teach Java 8 and we are making a new Map anyway, we should use `collectors` – dkatzel Jul 23 '14 at 13:59
  • 1
    This code unnecessarily uses side-effects (it modifies the `returnMap`), which is discouraged. Avoid this by using a `Collector` instead! – isnot2bad Jul 23 '14 at 15:34