From bd5dbc2e5e357d18edf42177de3a62619ae99028 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Tue, 11 Jun 2019 12:20:42 +0200 Subject: [PATCH] [New] Added getOrDefault() computeIfAbsent() and forEach() to MapOf* --- .../strolch/utils/collections/MapOfLists.java | 37 ++++ .../strolch/utils/collections/MapOfMaps.java | 37 ++++ .../strolch/utils/collections/MapOfSets.java | 37 ++++ .../strolch/utils/collections/MapOfTest.java | 163 ++++++++++++++++++ 4 files changed, 274 insertions(+) create mode 100644 li.strolch.utils/src/test/java/li/strolch/utils/collections/MapOfTest.java diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfLists.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfLists.java index 3abf8084e..65f65086e 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfLists.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfLists.java @@ -17,6 +17,8 @@ package li.strolch.utils.collections; import java.util.*; import java.util.Map.Entry; +import java.util.function.BiConsumer; +import java.util.function.Function; /** * @author Robert von Burg <eitch@eitchnet.ch> @@ -117,4 +119,39 @@ public class MapOfLists { } return this; } + + List getListOrDefault(T key, List defaultValue) { + List u; + return (((u = getList(key)) != null) || containsList(key)) ? u : defaultValue; + } + + public List computeIfAbsent(T key, Function> mappingFunction) { + Objects.requireNonNull(mappingFunction); + List u; + if ((u = getList(key)) == null) { + List newValue; + if ((newValue = mappingFunction.apply(key)) != null) { + addList(key, newValue); + return newValue; + } + } + + return u; + } + + void forEach(BiConsumer> action) { + Objects.requireNonNull(action); + for (Map.Entry> entry : this.mapOfLists.entrySet()) { + T k; + List u; + try { + k = entry.getKey(); + u = entry.getValue(); + } catch (IllegalStateException ise) { + // this usually means the entry is no longer in the map. + throw new ConcurrentModificationException(ise); + } + action.accept(k, u); + } + } } diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfMaps.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfMaps.java index 93afbf35e..7bfd6054d 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfMaps.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfMaps.java @@ -17,6 +17,8 @@ package li.strolch.utils.collections; import java.util.*; import java.util.Map.Entry; +import java.util.function.BiConsumer; +import java.util.function.Function; /** *

@@ -162,4 +164,39 @@ public class MapOfMaps { } return this; } + + Map getMapOrDefault(T key, Map defaultValue) { + Map u; + return (((u = getMap(key)) != null) || containsMap(key)) ? u : defaultValue; + } + + public Map computeIfAbsent(T key, Function> mappingFunction) { + Objects.requireNonNull(mappingFunction); + Map u; + if ((u = getMap(key)) == null) { + Map newValue; + if ((newValue = mappingFunction.apply(key)) != null) { + addMap(key, newValue); + return newValue; + } + } + + return u; + } + + void forEach(BiConsumer> action) { + Objects.requireNonNull(action); + for (Map.Entry> entry : this.mapOfMaps.entrySet()) { + T k; + Map u; + try { + k = entry.getKey(); + u = entry.getValue(); + } catch (IllegalStateException ise) { + // this usually means the entry is no longer in the map. + throw new ConcurrentModificationException(ise); + } + action.accept(k, u); + } + } } diff --git a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfSets.java b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfSets.java index bda7f39df..452b4e438 100644 --- a/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfSets.java +++ b/li.strolch.utils/src/main/java/li/strolch/utils/collections/MapOfSets.java @@ -17,6 +17,8 @@ package li.strolch.utils.collections; import java.util.*; import java.util.Map.Entry; +import java.util.function.BiConsumer; +import java.util.function.Function; /** * @author Robert von Burg <eitch@eitchnet.ch> @@ -117,4 +119,39 @@ public class MapOfSets { } return this; } + + Set getSetOrDefault(T key, Set defaultValue) { + Set u; + return (((u = getSet(key)) != null) || containsSet(key)) ? u : defaultValue; + } + + public Set computeIfAbsent(T key, Function> mappingFunction) { + Objects.requireNonNull(mappingFunction); + Set u; + if ((u = getSet(key)) == null) { + Set newValue; + if ((newValue = mappingFunction.apply(key)) != null) { + addSet(key, newValue); + return newValue; + } + } + + return u; + } + + void forEach(BiConsumer> action) { + Objects.requireNonNull(action); + for (Map.Entry> entry : this.mapOfSets.entrySet()) { + T k; + Set u; + try { + k = entry.getKey(); + u = entry.getValue(); + } catch (IllegalStateException ise) { + // this usually means the entry is no longer in the map. + throw new ConcurrentModificationException(ise); + } + action.accept(k, u); + } + } } diff --git a/li.strolch.utils/src/test/java/li/strolch/utils/collections/MapOfTest.java b/li.strolch.utils/src/test/java/li/strolch/utils/collections/MapOfTest.java new file mode 100644 index 000000000..d5c9b6272 --- /dev/null +++ b/li.strolch.utils/src/test/java/li/strolch/utils/collections/MapOfTest.java @@ -0,0 +1,163 @@ +package li.strolch.utils.collections; + +import static java.util.Arrays.asList; +import static java.util.Collections.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.*; + +import org.junit.Test; + +public class MapOfTest { + + @Test + public void shouldTestMapOfLists() { + + MapOfLists mapOfLists = new MapOfLists<>(); + mapOfLists.addElement("a", "1"); + mapOfLists.addElement("a", "2"); + mapOfLists.addElement("b", "3"); + mapOfLists.addElement("b", "4"); + + List list; + list = mapOfLists.getList("a"); + assertNotNull(list); + assertEquals(2, list.size()); + assertEquals("1", list.get(0)); + assertEquals("2", list.get(1)); + + list = mapOfLists.getList("b"); + assertNotNull(list); + assertEquals(2, list.size()); + assertEquals("3", list.get(0)); + assertEquals("4", list.get(1)); + + mapOfLists.computeIfAbsent("c", s -> { + List items = new ArrayList<>(); + items.add("5"); + return items; + }); + + list = mapOfLists.getList("c"); + assertNotNull(list); + assertEquals(1, list.size()); + assertEquals("5", list.get(0)); + + list = mapOfLists.getListOrDefault("a", emptyList()); + assertNotNull(list); + assertEquals(2, list.size()); + assertEquals("1", list.get(0)); + assertEquals("2", list.get(1)); + + list = mapOfLists.getListOrDefault("d", emptyList()); + assertNotNull(list); + assertEquals(list, emptyList()); + + mapOfLists.forEach((key, items) -> { + if (key.equals("a")) { + assertNotNull(items); + assertEquals(2, items.size()); + assertEquals("1", items.get(0)); + assertEquals("2", items.get(1)); + } + }); + } + + @Test + public void shouldTestMapOfMaps() { + + MapOfMaps mapOfMaps = new MapOfMaps<>(); + mapOfMaps.addElement("a", "1", 1); + mapOfMaps.addElement("a", "2", 2); + mapOfMaps.addElement("b", "3", 3); + mapOfMaps.addElement("b", "4", 4); + + Map map; + map = mapOfMaps.getMap("a"); + assertNotNull(map); + assertEquals(2, map.size()); + assertEquals(Integer.valueOf(1), map.get("1")); + assertEquals(Integer.valueOf(2), map.get("2")); + + map = mapOfMaps.getMap("b"); + assertNotNull(map); + assertEquals(2, map.size()); + assertEquals(Integer.valueOf(3), map.get("3")); + assertEquals(Integer.valueOf(4), map.get("4")); + + mapOfMaps.computeIfAbsent("c", s -> { + Map items = new HashMap<>(); + items.put("5", 5); + return items; + }); + + map = mapOfMaps.getMap("c"); + assertNotNull(map); + assertEquals(1, map.size()); + assertEquals(Integer.valueOf(5), map.get("5")); + + map = mapOfMaps.getMapOrDefault("a", emptyMap()); + assertNotNull(map); + assertEquals(2, map.size()); + assertEquals(Integer.valueOf(1), map.get("1")); + assertEquals(Integer.valueOf(2), map.get("2")); + + map = mapOfMaps.getMapOrDefault("d", emptyMap()); + assertNotNull(map); + assertEquals(map, emptyMap()); + + mapOfMaps.forEach((key, items) -> { + if (key.equals("a")) { + assertNotNull(items); + assertEquals(2, items.size()); + assertEquals(Integer.valueOf(1), items.get("1")); + assertEquals(Integer.valueOf(2), items.get("2")); + } + }); + } + + @Test + public void shouldTestMapOfSets() { + + MapOfSets mapOfSets = new MapOfSets<>(); + mapOfSets.addElement("a", "1"); + mapOfSets.addElement("a", "2"); + mapOfSets.addElement("b", "3"); + mapOfSets.addElement("b", "4"); + + Set set; + set = mapOfSets.getSet("a"); + assertNotNull(set); + assertEquals(new HashSet<>(asList("1", "2")), set); + + set = mapOfSets.getSet("b"); + assertNotNull(set); + assertEquals(new HashSet<>(asList("3", "4")), set); + + mapOfSets.computeIfAbsent("c", s -> { + Set items = new HashSet<>(); + items.add("5"); + return items; + }); + + set = mapOfSets.getSet("c"); + assertNotNull(set); + assertEquals(new HashSet<>(asList("5")), set); + + set = mapOfSets.getSetOrDefault("a", emptySet()); + assertNotNull(set); + assertEquals(new HashSet<>(asList("1", "2")), set); + + set = mapOfSets.getSetOrDefault("d", emptySet()); + assertNotNull(set); + assertEquals(set, emptySet()); + + mapOfSets.forEach((key, items) -> { + if (key.equals("a")) { + assertNotNull(items); + assertEquals(new HashSet<>(asList("1", "2")), items); + } + }); + } +}