diff --git a/core-java-modules/core-java-collections-maps-8/README.md b/core-java-modules/core-java-collections-maps-8/README.md
new file mode 100644
index 0000000000..0dd8c780d6
--- /dev/null
+++ b/core-java-modules/core-java-collections-maps-8/README.md
@@ -0,0 +1 @@
+## Relevant Articles:
\ No newline at end of file
diff --git a/core-java-modules/core-java-collections-maps-8/pom.xml b/core-java-modules/core-java-collections-maps-8/pom.xml
new file mode 100644
index 0000000000..8c4454cf0f
--- /dev/null
+++ b/core-java-modules/core-java-collections-maps-8/pom.xml
@@ -0,0 +1,29 @@
+
+
+ 4.0.0
+ core-java-collections-maps-8
+ core-java-collections-maps-8
+ jar
+
+
+ core-java-modules
+ com.baeldung.core-java-modules
+ 0.0.1-SNAPSHOT
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ --add-opens java.base/java.util=ALL-UNNAMED
+
+
+
+
+
+
diff --git a/core-java-modules/core-java-collections-maps-8/src/test/java/com/baeldung/map/valuetokeyset/ConvertMapKeyValueToMapValueKeySetUnitTest.java b/core-java-modules/core-java-collections-maps-8/src/test/java/com/baeldung/map/valuetokeyset/ConvertMapKeyValueToMapValueKeySetUnitTest.java
new file mode 100644
index 0000000000..a7491fd257
--- /dev/null
+++ b/core-java-modules/core-java-collections-maps-8/src/test/java/com/baeldung/map/valuetokeyset/ConvertMapKeyValueToMapValueKeySetUnitTest.java
@@ -0,0 +1,127 @@
+package com.baeldung.map.valuetokeyset;
+
+import static java.util.stream.Collectors.collectingAndThen;
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.mapping;
+import static java.util.stream.Collectors.toSet;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimaps;
+import com.google.common.collect.SetMultimap;
+
+public class ConvertMapKeyValueToMapValueKeySetUnitTest {
+
+ private static final Map INPUT_MAP = Map.of(
+ // @formatter:off
+ "Kai", "Linux",
+ "Eric", "MacOS",
+ "Kevin", "Windows",
+ "Liam", "MacOS",
+ "David", "Linux",
+ "Saajan", "Windows",
+ "Loredana", "MacOS"
+ // @formatter:on
+ );
+
+ private static final Map> EXPECTED = Map.of(
+ // @formatter:off
+ "Linux", Set.of("Kai", "David"),
+ "Windows", Set.of("Saajan", "Kevin"),
+ "MacOS", Set.of("Eric", "Liam", "Loredana")
+ // @formatter:on
+ );
+
+ private static final Map INPUT_MAP_WITH_NULLS = new HashMap(INPUT_MAP) {{
+ put("Tom", null);
+ put("Jerry", null);
+ put(null, null);
+ }};
+
+ private static final Map> EXPECTED_WITH_NULLS = new HashMap>(EXPECTED) {{
+ put(null, new HashSet() {{
+ add("Tom");
+ add("Jerry");
+ add(null);
+ }});
+ }};
+
+ public static Map> transformMap(Map input) {
+ Map> resultMap = new HashMap<>();
+ for (Map.Entry entry : input.entrySet()) {
+ if (!resultMap.containsKey(entry.getValue())) {
+ resultMap.put(entry.getValue(), new HashSet<>());
+ }
+ resultMap.get(entry.getValue())
+ .add(entry.getKey());
+ }
+ return resultMap;
+ }
+
+ @Test
+ void whenUsingClassicLoopBasedSolution_thenGetExpectedResult() {
+ Map> result = transformMap(INPUT_MAP);
+ assertEquals(EXPECTED, result);
+
+ Map> result2 = transformMap(INPUT_MAP_WITH_NULLS);
+ assertEquals(EXPECTED_WITH_NULLS, result2);
+ }
+
+ @Test
+ void whenUsingJava8StreamGroupingBy_thenGetExpectedResult() {
+ Map> result = INPUT_MAP.entrySet()
+ .stream()
+ .collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toSet())));
+ assertEquals(EXPECTED, result);
+
+ assertThrows(NullPointerException.class, () -> INPUT_MAP_WITH_NULLS.entrySet()
+ .stream()
+ .collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toSet()))));
+ }
+
+ @Test
+ void whenUsingJava8ForEach_thenGetExpectedResult() {
+ Map> result = new HashMap<>();
+ INPUT_MAP.forEach((key, value) -> result.computeIfAbsent(value, k -> new HashSet<>())
+ .add(key));
+ assertEquals(EXPECTED, result);
+
+ Map> result2 = new HashMap<>();
+ INPUT_MAP_WITH_NULLS.forEach((key, value) -> result2.computeIfAbsent(value, k -> new HashSet<>())
+ .add(key));
+ assertEquals(EXPECTED_WITH_NULLS, result2);
+ }
+
+ @Test
+ void whenUsingGuavaMultiMapCollector_thenGetExpectedResult() {
+ Map> result = INPUT_MAP.entrySet()
+ .stream()
+ .collect(collectingAndThen(Multimaps.toMultimap(Map.Entry::getValue, Map.Entry::getKey, HashMultimap::create), Multimaps::asMap));
+ assertEquals(EXPECTED, result);
+
+ Map> result2 = INPUT_MAP_WITH_NULLS.entrySet()
+ .stream()
+ .collect(collectingAndThen(Multimaps.toMultimap(Map.Entry::getValue, Map.Entry::getKey, HashMultimap::create), Multimaps::asMap));
+ assertEquals(EXPECTED_WITH_NULLS, result2);
+ }
+
+ @Test
+ void whenUsingGuavaInvertFromAndForMap_thenGetExpectedResult() {
+ SetMultimap multiMap = Multimaps.invertFrom(Multimaps.forMap(INPUT_MAP), HashMultimap.create());
+ Map> result = Multimaps.asMap(multiMap);
+ assertEquals(EXPECTED, result);
+
+ SetMultimap multiMapWithNulls = Multimaps.invertFrom(Multimaps.forMap(INPUT_MAP_WITH_NULLS), HashMultimap.create());
+ Map> result2 = Multimaps.asMap(multiMapWithNulls);
+ assertEquals(EXPECTED_WITH_NULLS, result2);
+ }
+
+}
\ No newline at end of file
diff --git a/core-java-modules/pom.xml b/core-java-modules/pom.xml
index 85df51457c..bd7aae6410 100644
--- a/core-java-modules/pom.xml
+++ b/core-java-modules/pom.xml
@@ -99,6 +99,7 @@
core-java-collections-maps-2
core-java-collections-maps-3
core-java-collections-maps-7
+ core-java-collections-maps-8
core-java-compiler
core-java-concurrency-2
core-java-concurrency-advanced