4

I have a List<POJO> that I want to extract data from and the variables I'm interested in are:

  • Environment: String
  • Application: String
  • Throughput: Double

There are 7 Environment objects and each Environment has 18 Application objects, which each have multiple values.

I'm trying to iterate over the List<POJO> and store these values in a Hashmap<Environment.ToString, Hashmap<Applications.ToString, List<Double>>

I'm trying to use Java 8's Lambda features; my code so far:

private HashMap<String, List<BigDecimal>> appMap = new HashMap<String, List<BigDecimal>>();
private HashMap<String, HashMap> envMap = new HashMap<String, HashMap>();

for(POJO chartModel: List<POJO>) {
    appMap.computeIfAbsent(chartModel.getName(), v -> new ArrayList<BigDecimal>())
          .add(BigDecimal.valueOf(chartModel.getThroughput()));
    envMap.put(chartModel.getEnvironment(), appMap);
}

Firstly, is there a shorthand way to iterate over the List inside the inner Map using Java8?

Secondly, my code isn't quite right, so currently the map adds all the Throughput values to its Application key, so I end up with 18 keys with a list of values.

What I need it to do is in my envMap I should have 7 Environment objects, with each having its 18 Application objects and values, so there would be 126 Application objects in total. Can this be achieved the way I'm attempting it, is there a Lambda way to achieve this?

1
  • 1
    Well, for starters, you only have one instance of appMap, and that's going to be inserted into the envMap 7 times, once for each Environment. Commented Mar 8, 2016 at 18:40

2 Answers 2

6

You need to use 2 grouping by operations: the first one groups according to the environment and the second one groups according to the name. Finally, you need to map each values to the BigDecimal value of their throughput.

Assuming pojo is a List<POJO>:

Map<String, Map<String, List<BigDecimal>>> result =
    pojo.stream()
        .collect(Collectors.groupingBy(
            POJO::getEnvironment,
            Collectors.groupingBy(
                POJO::getName,
                Collectors.mapping(p -> BigDecimal.valueOf(p.getThroughput()), Collectors.toList())
            )
        ));
Sign up to request clarification or add additional context in comments.

Comments

4

You are creating only one Map, appMap, which you are putting into envMap for every key. You obviously want to create a new Map for each distinct key and you already know the right tool, computeIfAbsent. But you should also mind the “diamond operator”. While not being a new Java 8 feature, your code will clearly benefit from removing the repetitions of the type parameters. Putting it all together, the operation will look like:

HashMap<String, Map<String, List<BigDecimal>>> envMap = new HashMap<>();
for(POJO chartModel: list) {
    envMap.computeIfAbsent(chartModel.getEnvironment(), env -> new HashMap<>())
        .computeIfAbsent(chartModel.getName(), name -> new ArrayList<>())
        .add(BigDecimal.valueOf(chartModel.getThroughput()));
}

You can also express the same logic using the Stream API, as shown by Tunaki, but you don’t need to.

3 Comments

Is there any advantage to using one method over the other?
In this specific case, there are no important differences. You can use whatever you like but it’s worth knowing both ways.
I would actually prefer this solution, as here we have less nested calls. Five closing parentheses in a row is too much.

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.