2

I have function which returns a Map<String, Set<String>>, Code before java 8:

Map<String, Set<String>> degreeMap = new HashMap<>();
for(Course  course : courses){
    Set<String> cList = degreeMap.get(course.getCourseLevel().toString());
    if(Objects.nonNull(cList)){
        cList.addAll(course.getMasterDegree()); //this is what i want to append to the old set
        degreeMap.put(course.getCourseLevel().toString(), cList);
    } else{
        degreeMap.put(course.getCourseLevel().toString(), new HashSet<>(course.getMasterDegree()));
    }
} 
return degreeMap;

Which return a map of courselevel -> set of degrees.

For example, it read all the courses and return a map like:

{"undergraduate" : ["BTech", "BSc", "BE"],
"masters": ["MTech", "MBA"],
"Executive": ["PGDBM", "EECP"]}

Here is my Course class:

public class Course {
    private List<String> masterDegree;
    private CourseLevel courseLevel;
}

But I want to write this piece of code in Java 8 style. For that, I tried this:

Map<String, Set<String>> degreeMap = courses.stream().collect(
        Collectors.groupingBy(c -> c.getCourseLevel().toString(),
                Collectors.mapping(c -> c.getMasterDegree(), Collectors.toSet()))
);

which is not working and I am getting the following compile-time error on this:

no instance(s) of type variable(s) exist so that List conforms to String inference variable T has incompatible bounds: equality constraints: String lower bounds: List

Any suggestion, how to achieve this?

4
  • It sounds to me that you're looking for a flatMapping equivalent of Java-9 in an older version. Commented Apr 12, 2019 at 9:12
  • 1
    @GhostCat tried editing the question to be relevant enough. hope its clear now. Commented Apr 12, 2019 at 9:35
  • 1
    @Naman thanks for resolving this battle :P Commented Apr 12, 2019 at 9:35
  • 1
    for(Course course : courses) degreeMap.computeIfAbsent(course.getCourseLevel() .toString(), x -> new HashSet<>()) .addAll(course.getMasterDegree()); By the way, even in your pre-Java 8 version, there never was a reason to put the same list into the Map again after addAll. Commented Apr 12, 2019 at 12:27

3 Answers 3

3

Not tested, but looks like, you're looking for something like:

    return courses.stream()
            .collect(Collectors.toMap(course -> course.getCourseLevel().toString(),
                    course -> new HashSet<>(course.getMasterDegree()),
                    (set1, set2) -> Stream.of(set1, set2)
                            .flatMap(Set::stream).collect(Collectors.toSet())));
Sign up to request clarification or add additional context in comments.

1 Comment

In this case, (set1, set2) -> { set1.addAll(set2); return set1; } clearly is the preferable merge function…
0

You might be interested in the Collectors.toMap() method.

Here is an example that you may need to tweak as I did not test it.

Map<String, Set<String>> degreeMap = courses.stream()
    .collect(
        Collectors.toMap(
            item -> item.getCourseLevel().toString(), //your key mapping
            item -> item.getMasterDegree(), //your value mapping
            (oldValue, newValue) -> { //your process of aggregation
                if (null == oldValue) {
                    return newValue;
                } else {
                    oldValue.addAll(newValue);
                    return oldValue;
                }
            },
            LinkedHashMap::new //your result initialiser
        )
    );

Also, another tip: you do not need to get by key and check for null, you can use the .compute(), .computeIfAbsent(), .computeIfPresent() methods on the map

Comments

-1

I don't think you need lamda expression, you should refactor your codes to make it clear instead.

        // supposed to be initialied with non-empty values
        // Map<String, Set<String>> degreeMap = ...

        for(Course  course : courses){
            // something like below
            String key = course.getCourseLevel().toString();
            // degreeSet should not be null
            Set<String> degreeSet = course.getMasterDegree();

            // TODO: check nullable
            degreeSet.putAll(degreeMap.get(key));

            degreeMap.put(key, degreeSet);
        } 

        return degreeMap;

Comments

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.