62

Is there a better functional way of converting an array of Strings in the form of "key:value" to a Map using the Java 8 lambda syntax?

Arrays.asList("a:1.0", "b:2.0", "c:3.0")
        .stream()
        .map(elem -> elem.split(":")
        .collect(Collectors.toMap(keyMapper?, valueMapper?));

The solution I have right now does not seem really functional:

Map<String, Double> kvs = new HashMap<>();
Arrays.asList("a:1.0", "b:2.0", "c:3.0")
        .stream()
        .map(elem -> elem.split(":"))
        .forEach(elem -> kvs.put(elem[0], Double.parseDouble(elem[1])));

1 Answer 1

97

You can modify your solution to collect the Stream of String arrays into a Map (instead of using forEach) :

Map<String, Double> kvs =
    Arrays.asList("a:1.0", "b:2.0", "c:3.0")
        .stream()
        .map(elem -> elem.split(":"))
        .collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1])));

Of course this solution has no protection against invalid input. Perhaps you should add a filter just in case the split String has no separator :

Map<String, Double> kvs =
    Arrays.asList("a:1.0", "b:2.0", "c:3.0")
        .stream()
        .map(elem -> elem.split(":"))
        .filter(elem -> elem.length==2)
        .collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1])));

This still doesn't protect you against all invalid inputs (for example "c:3r" would cause NumberFormatException to be thrown by parseDouble).

Sign up to request clarification or add additional context in comments.

9 Comments

I don't think that silently ignoring erroneous input is a good advice and this was not requested by OP. I'd better use elem -> elem.split(":", 2) instead of adding the filter step. This way erroneous input will be manifested either by ArrayIndexOutOfBoundsException (if no colon was found) or by NumberFormatException (if more than one colon was found).
Thanks for all the comments and additional input on the error checking. This is what I needed.
If task is to convert a real array to Map, then the expression should start with Arrays.stream(<arrayVariable>)
@Vlad.Bachurin It also works with the current code - Arrays.asList(<arrayVariable>).stream().... The Arrays.asList("a:1.0", "b:2.0", "c:3.0") part was taken as is from the question.
@Eran I got your point, but Arrays.stream(<array>) is shorter anyway. And fits better the subject of the question. Peace. :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.