1

I have a the following container in Java that I need to work on

Map<String, List<Entry<Parameter, String>>>

Where Parameter is an enumerated type defined as follows:

public enum Parameter {
    Param1,
    Param2,
    Param3
}

The code below shows how I initialize the map structure - effectively putting 2 rows in the container.

    Map<String, List<Entry<Parameter, String>>> map2 = new HashMap<String, List<Entry<Parameter, String>>>() {{
        put("SERVICE1", new ArrayList<Entry<Parameter, String>>(){{
            add (new AbstractMap.SimpleEntry<>(Parameter.Param1,"val1"));
            add (new AbstractMap.SimpleEntry<>(Parameter.Param2,"val2"));
            add (new AbstractMap.SimpleEntry<>(Parameter.Param3,"val3"));
        }});
        put("SERVICE2", new ArrayList<Entry<Parameter, String>>(){{
            add (new AbstractMap.SimpleEntry<>(Parameter.Param1,"val4"));
            add (new AbstractMap.SimpleEntry<>(Parameter.Param2,"val5"));
            add (new AbstractMap.SimpleEntry<>(Parameter.Param3,"val6"));
        }});
    }};

I need to use the java 8 streams api to find the val1 and val2 values from "SERVICE1" but I do not know the correct java streams filter and mapping syntax.

The nearest thing I can come up with is the following, but this only filters at the top level and it returns a list of lists rather than the list of Parameter.Param1,"val1" & Parameter.Param2,"val3" that I am looking for from the SERVICE1 row.

    List<List<Entry<Parameter, String>>> listOfLists = myMap.entrySet().stream()
            .filter(next -> next.getKey().equals("SERVICE1"))
            .map(Map.Entry::getValue)
            .collect(Collectors.toList());
    listOfLists.size();
johnco3
  • 2,401
  • 4
  • 35
  • 67

1 Answers1

3

If you only need the "val1" and "val2" values, you can first use getOrDefault to get the corresponding list, and then filter on the entries' keys to get entries with Param1 or Param2 as key, and finally apply map again to get the values of these entries.

List<String> list =
    myMap.getOrDefault("SERVICE1", Collections.emptyList())
         .stream()
         .filter(e -> e.getKey() == Parameter.Param1 || e.getKey() == Parameter.Param2)
         .map(Map.Entry::getValue)
         .collect(Collectors.toList());

Also you might be interested to look at Efficiency of Java "Double Brace Initialization"?

Community
  • 1
  • 1
Alexis C.
  • 91,686
  • 21
  • 171
  • 177
  • Nice, but is there some way of achieving the same result leaving in the current top level filter(next -> next.getKey().equals("SERVICE1")) that I currently have in place or is that always going to return a list of lists. I think the code I wrote is almost there but there is some sort of way of just returning the first of these list of lists. – johnco3 Sep 14 '16 at 18:40
  • 2
    @johnco3 Well yes, use `flatMap` instead of `map`, and filter the entries the same way `.filter(next -> next.getKey().equals("SERVICE1")).flatMap(e -> e.getValue().stream()) .filter(e -> e.getKey() == Parameter.Param1 || e.getKey() == Parameter.Param2).map(Map.Entry::getValue).collect(...)`. But there is no benefit to go with this approach since you will only have one list because you are interested in a mapping with a specific key. – Alexis C. Sep 14 '16 at 18:45
  • 2
    ... unless the filtering on the keys might lead multiple lists like `next -> next.getKey().startsWith("SERVICE")` for instance. – Alexis C. Sep 14 '16 at 18:46
  • Yes you got it right, In fact the actual case will be when next.getKey() is not SERVICE1, I will need to filter different Params – johnco3 Sep 14 '16 at 18:52