简体   繁体   中英

What's the best way to optimize these nested for-loops used to create a hashmap in Java 8?

Before I start, I've done tons of research on this and have yet to come to a solution. I have referenced the following threads, as well as many others, but I just wanted to demonstrate that I've searched long and hard for a solution before asking. My situation is more complicated than these:

How to convert nested for loop into Hashmap using java stream

How to iterate nested lists with lambda streams?

What is the proper way of replacing a nested for loop with streams in Java 8?

Okay, so I'm building a service that consumes another service that provides a class that I have no control over. I have to consume the class as it comes because it is dynamically generated from a file every time the project builds. It's a total mess with tons of nested classes and nested lists. The naming conventions were a mess too, but I've cleaned that up a lot here for readability. I need to dig really deep into the lists to get two values (code and cgyCode) from an object (Lower) and create a hashmap using one as the key (code) and one as the value (cgyCode).

I have FUNCTIONING logic that works as so:

//Code passing in object Rpn rpn which contains the nested lists        

HashMap<String, String> codeMap = new HashMap<String, String>();

            for (Object datDtl : rpn.getDatDtlOrRpnDtl()) {

                if (datDtl instanceof Rpn.DatDtl) {

                    for (Rpn.DatDtl.Upper upper : ((Rpn.DatDtl) datDtl).Upper()) {

                        for (Rpn.DatDtl.Upper.Lower lower : Upper.getLower()) {

                            codeMap.put(lower.getCode(), lower.getCgyCode());
                        }
                    }
                }
            }

So I've tried many variations to turn this entire thing into a lambda stream, if that is even the right thing to do. I haven't been able to get the entire thing working, there's always something that gets messed up. So the best I have is to stream the last loop, but nothing above. I feel that it can be consolidated way more than this.

FUNCTIONING:

HashMap<String, String> codeMap = new HashMap<String, String>();
                for (Object datDtl : rpn.getDatDtlOrRpnDtl()) {

                    if (datDtl instanceof Rpn.DatDtl) {

                        for (Rpn.DatDtl.Upper upper : ((Rpn.DatDtl) datDtl).Upper()){

                             upper.getLower().stream().forEach(lower -> codeMap.put(lower.getCode(), lower.getCgyCode()));

              }
         }
    }

I've tried many combinations of filtering, flatMaps, and streams, but I haven't had success converting all the functionality into into a series of lambda statements, nor do I know if that is the best course of action.

So my questions here are: what is the best way to optimize this code in terms of performance, and if not all of it can be optimized using lambdas and streams, from a learning perspective, why not?


Below I will demonstrate some of the other things I've tried that were close, but ultimately I couldn't get the mapping to resolve.

FAILED 1:

HashMap<String, String> codeMap = new HashMap<>();
rpn.getDatDtlOrRpnDtl().stream()
                    .filter(datDtl -> datDtl instanceof Rpn.DatDtl)
                    .flatMap(datDtl -> ((Rpn.DatDtl)datDtl).getUpper().stream()
                    .flatMap(upper -> upper.getLower().stream()
                    .forEach(lower -> codeMap.put(lower.getCode(), lower.getCgyCode()))));

The code above seems to work except for the .forEach function gives the error "no instance(s) of type variable(s) R exist so that void conforms to Stream". This is the same logic that is working in my functioning loop that incorporates the lambda, so that makes me feel the way I am arriving at "lower" is incorrect.

FAILED 2:

HashMap<String, String> codeMap = rpn.getDatDtlOrRpnDtl().stream()
                    .filter(datDtl -> datDtl instanceof Rpn.DatDtl)
                    .flatMap(datDtl -> ((Rpn.DatDtl)datDtl).getUpper().stream()
                    .flatMap(upper -> upper.getLower().stream()
                    .collect(Collectors.toMap(lower -> lower.getCode(), lower -> lower.getCgyCode())));

This code is similar to the one above. The error here is that ".getCode()" and ".getCgyCode()" aren't recognized as valid methods even though they are defined in the Lower class. This further suggests that I am correct in my theory that the way I arrive to "lower" is not the correct way to do so.

I have tried many other variations with .filter, .map, ect. But I am at a total loss here. It may not be possible to accomplish what I am trying to do, but if so, I would like to know why and what the next best thing would be.

Thanks to anyone who has read this far and wants to try to tackle this with me.


EDIT:

The solution led me to the answer, but in order to document for anyone else that may come across this, I will format the solution that ended up working:

Map<String, String> codeMap = rpn.getDatDtlOrRpnDtl().stream()
                    .filter(datDtl -> datDtl instanceof Rpn.DatDtl)
                    .flatMap(datDtl -> ((Rpn.DatDtl) datDtl).Upper().stream())
                    .flatMap(upper -> upper.getLower().stream())
                    .forEach(lower -> codeMap.put(lower.getCode(), lower.getCgyCode());

Both of your attempts are very close.

Your code is not indented to show it, but you are placing some of your closing parentheses after the collect call in your failed attempts.

This isn't the correct order for the stream operations. The last operation should be a call to collect . As written, your code will produce a Stream as its result rather than a Map .

Try the following code instead:

Map<String, String> codeMap = Rpn.getDatDtlOrRpnDtl().stream()
                    .filter(datDtl -> datDtl instanceof Rpn.DatDtl)
                    .flatMap(datDtl -> ((Rpn.DatDtl) datDtl).Upper().stream())
                    .flatMap(upper -> upper.getLower().stream())
                    .collect(Collectors.toMap(lower -> lower.getCode(), lower -> lower.getCgyCode());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM