4

The keys of the map may be values 1 - 5 where each key is not required, but if absent must concatenate something that looks like " - [] ".

I've used Java 8 a bit before and I feel like this can be done more efficiently with stream() and collect() but I feel like the external list requirement is throwing me off. The below code works but feels incorrect.

List<String> ids = Arrays.asList("1", "2", "3", "4", "5");

StringBuilder location = new StringBuilder();

ids.forEach(id -> {
    List<String> addresses = map.get(id);
    if (addresses != null) {
        addresses.forEach(addr -> location.append(addr + " - "));
    } else {
        location.append(" [] - ");
    }
});

Generates something that looks like this for a Colorado location:

US - CO - [] - CENTENNIAL -

In answer to Nicholas K an example of map would be

{1=[US], 2=[CO], 5=[METROPOLITAN FOOTBALL STADIUM DISTRICT, REGIONAL TRANSPORTATION DISTRICT]}

and would be expected to receive output

US - CO - [] - [] - METROPOLITAN FOOTBALL STADIUM DISTRICT - REGIONAL TRANSPORTATION DISTRICT
2
  • 2
    What are the values for map? Commented Nov 14, 2018 at 17:40
  • 1
    Don't assume that stream() and collect() will be more efficient, write the code in the way you're most comfortable with. Commented Nov 14, 2018 at 17:49

4 Answers 4

3

The correct way to handle missing values in a map is computeIfAbsent() which is a new method on Map available since Java 8.

This gives you the below code:

String s = ids.stream()
    .map(id -> map.computeIfAbsent(id, absentKey -> singletonList("[]")))
    .flatMap(Collection::stream)
    .collect(Collectors.joining(" - "));
  • First, let's stream over the keys in the map, which you have stored in the ids list variable.
  • Then, if the value is null, map to a default value ("[]"), else computeIfAbsent() returns the actual value.
  • Since you want to print all the values separated by " - ", let's just flat map the stream of lists and join them by " - ".

s now holds the value (if used with your example map):

"US - CO - [] - [] - METROPOLITAN FOOTBALL STADIUM DISTRICT - REGIONAL TRANSPORTATION DISTRICT"

Notice that there is no trailing " - ". Collectors.joining() makes sure to not append the delimiter before or after the elements.

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

Comments

1

Simpler approach :

    ids.stream().map(l -> map.get(Integer.parseInt(l))).forEach(i -> {
        if (i != null) {
            location.append(i + " - ");
        } else {
            location.append("[] - ");
        }
    });

Here we loop over each element in the list to see whether it is present as a key in the map. Depending on the value we append the appropriate strings.

Note:

Parsing has been done assuming your map is defined as Map<Integer, String>

2 Comments

List<String> addresses = map.get(id); from the question. The assumption is incorrect.
What @nullpointer says is correct so I wouldn't have to do the Integre.parseInt. Is there a way to lose the StringBuilder and collect to Strings at the end. I know about Collectors.joining but can I do that inside the if-else?
1

Maybe not very clean, but you can try :

Map<String, List<String>> inputMap = Map.of("1", List.of(), "2", List.of("l1", "l2"));
List<String> ids = List.of("1", "2", "3", "4", "5");
StringBuilder location = new StringBuilder();
ids.forEach(id -> {
    if (inputMap.get(id) != null) {
        location.append(inputMap.get(id).stream().map(addr -> addr + " - ").collect(Collectors.joining()));
    } else {
        location.append(" [] - ");
    }
});

Comments

1

I am using Stream and Optional to handle null references:

List<String> result = ids.stream()
  .map(index -> format(map.get(index)))
  .collect(Collectors.toList());
System.out.println(result);

And the method format:

  private static String format(List<String> address) {
    return Optional.ofNullable(address)
      .map(a -> a.stream().map(part -> Optional.ofNullable(part).orElse("[]")).collect(Collectors.joining(" - ")))
      .orElse(" [] - ");
  }

Applied on an example:

  public static void main(String[] args) {
    Map<String, List<String>> map = Map.of("1", Arrays.asList("US", "CO", null, "CENTENNIAL"));

    List<String> ids = Arrays.asList("1", "2", "3", "4", "5");

    List<String> result = ids.stream()
      .map(index -> format(map.get(index)))
      .collect(Collectors.toList());
    System.out.println(result);
  }

That prints:

[US - CO - [] - CENTENNIAL,  [] - ,  [] - ,  [] - ,  [] - ]

4 Comments

Looks promising, I've not used Optional before I'll look into this, thanks.
Suggestion - If you've used Map.of, you can also use List.of. Of course considering them to be unmodifiable.
@nullpointer Generally you're right. And I started with List.of(...) but to show the handling of null I switched to Arrays.asList(...) since List.of() "Throws: NullPointerException - if an element is null" (JavaDoc)
@LuCio oh yeah, correct, you're initializing the list within the Map as well and with null and that reveals the picture so clear as to why the List.of throws an NPE.

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.