diff --git a/javaslang/src/main/java/javaslang/collection/TreeMap.java b/javaslang/src/main/java/javaslang/collection/TreeMap.java index 2c942a1856..d80ad41c87 100644 --- a/javaslang/src/main/java/javaslang/collection/TreeMap.java +++ b/javaslang/src/main/java/javaslang/collection/TreeMap.java @@ -51,7 +51,7 @@ private TreeMap(RedBlackTree> entries) { * @return A {@link TreeMap} Collector. */ public static , V> Collector, ArrayList>, TreeMap> collector() { - return collector((Comparator & Serializable) K::compareTo); + return createCollector(EntryComparator.natural()); } /** @@ -65,15 +65,7 @@ public static , V> Collector, Array * @return A {@link TreeMap} Collector. */ public static Collector, ArrayList>, TreeMap> collector(Comparator keyComparator) { - Objects.requireNonNull(keyComparator, "keyComparator is null"); - final Supplier>> supplier = ArrayList::new; - final BiConsumer>, Tuple2> accumulator = ArrayList::add; - final BinaryOperator>> combiner = (left, right) -> { - left.addAll(right); - return left; - }; - final Function>, TreeMap> finisher = list -> ofEntries(keyComparator, list); - return Collector.of(supplier, accumulator, combiner, finisher); + return createCollector(EntryComparator.of(keyComparator)); } /** @@ -84,7 +76,7 @@ public static Collector, ArrayList>, TreeMap, V> TreeMap empty() { - return empty((Comparator & Serializable) K::compareTo); + return new TreeMap<>(RedBlackTree.empty(EntryComparator.natural())); } /** @@ -97,7 +89,7 @@ public static , V> TreeMap empty() { */ public static TreeMap empty(Comparator keyComparator) { Objects.requireNonNull(keyComparator, "keyComparator is null"); - return new TreeMap<>(RedBlackTree.empty(new EntryComparator<>(keyComparator))); + return new TreeMap<>(RedBlackTree.empty(EntryComparator.of(keyComparator))); } /** @@ -127,7 +119,22 @@ public static TreeMap narrow(TreeMap tree * @return A new TreeMap containing the given entry. */ public static , V> TreeMap of(Tuple2 entry) { - return of((Comparator & Serializable) K::compareTo, entry); + Objects.requireNonNull(entry, "entry is null"); + return createFromTuple(EntryComparator.natural(), entry); + } + + /** + * Returns a singleton {@code TreeMap}, i.e. a {@code TreeMap} of one entry using a specific key comparator. + * + * @param The key type + * @param The value type + * @param entry A map entry. + * @param keyComparator The comparator used to sort the entries by their key. + * @return A new TreeMap containing the given entry. + */ + public static TreeMap of(Comparator keyComparator, Tuple2 entry) { + Objects.requireNonNull(entry, "entry is null"); + return createFromTuple(EntryComparator.of(keyComparator), entry); } /** @@ -140,26 +147,20 @@ public static , V> TreeMap of(Tuple2, V> TreeMap ofAll(java.util.Map map) { Objects.requireNonNull(map, "map is null"); - RedBlackTree> result = RedBlackTree.empty(new EntryComparator<>((Comparator & Serializable) K::compareTo)); - for (java.util.Map.Entry entry : map.entrySet()) { - result = result.insert(Tuple.of(entry.getKey(), entry.getValue())); - } - return new TreeMap<>(result); + return createFromMap(EntryComparator.natural(), map); } /** - * Returns a singleton {@code TreeMap}, i.e. a {@code TreeMap} of one entry using a specific key comparator. + * Returns a {@code TreeMap}, from a source java.util.Map. * - * @param The key type - * @param The value type - * @param entry A map entry. - * @param keyComparator The comparator used to sort the entries by their key. - * @return A new TreeMap containing the given entry. + * @param map A map entry. + * @param The key type + * @param The value type + * @return A new Map containing the given map */ - public static TreeMap of(Comparator keyComparator, Tuple2 entry) { - Objects.requireNonNull(keyComparator, "keyComparator is null"); - Objects.requireNonNull(entry, "entry is null"); - return TreeMap. empty(keyComparator).put(entry); + public static TreeMap ofAll(Comparator keyComparator, java.util.Map map) { + Objects.requireNonNull(map, "map is null"); + return createFromMap(EntryComparator.of(keyComparator), map); } /** @@ -172,7 +173,7 @@ public static TreeMap of(Comparator keyComparator, Tuple * @return A new Map containing the given entry */ public static , V> TreeMap of(K key, V value) { - return of((Comparator & Serializable) K::compareTo, key, value); + return createFromPairs(EntryComparator.natural(), key, value); } /** @@ -187,7 +188,7 @@ public static , V> TreeMap of(K key, V val * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2); } /** @@ -204,7 +205,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3); } /** @@ -223,7 +224,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3, k4, v4); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3, k4, v4); } /** @@ -244,7 +245,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); } /** @@ -267,7 +268,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6); } /** @@ -292,7 +293,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7); } /** @@ -319,7 +320,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8); } /** @@ -348,7 +349,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9); } /** @@ -379,7 +380,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entries */ public static , V> TreeMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) { - return of((Comparator & Serializable) K::compareTo, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10); + return createFromPairs(EntryComparator.natural(), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10); } /** @@ -393,8 +394,7 @@ public static , V> TreeMap of(K k1, V v1, * @return A new Map containing the given entry */ public static TreeMap of(Comparator keyComparator, K key, V value) { - Objects.requireNonNull(keyComparator, "keyComparator is null"); - return TreeMap. empty(keyComparator).put(key, value); + return createFromPairs(EntryComparator.of(keyComparator), key, value); } /** @@ -410,7 +410,7 @@ public static TreeMap of(Comparator keyComparator, K key * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2) { - return of(keyComparator, k1, v1).put(k2, v2); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2); } /** @@ -428,7 +428,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3) { - return of(keyComparator, k1, v1, k2, v2).put(k3, v3); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3); } /** @@ -448,7 +448,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { - return of(keyComparator, k1, v1, k2, v2, k3, v3).put(k4, v4); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3, k4, v4); } /** @@ -470,7 +470,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { - return of(keyComparator, k1, v1, k2, v2, k3, v3, k4, v4).put(k5, v5); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); } /** @@ -494,7 +494,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) { - return of(keyComparator, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5).put(k6, v6); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6); } /** @@ -520,7 +520,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) { - return of(keyComparator, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6).put(k7, v7); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7); } /** @@ -548,7 +548,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) { - return of(keyComparator, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7).put(k8, v8); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8); } /** @@ -578,7 +578,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) { - return of(keyComparator, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8).put(k9, v9); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9); } /** @@ -610,7 +610,7 @@ public static TreeMap of(Comparator keyComparator, K k1, * @return A new Map containing the given entries */ public static TreeMap of(Comparator keyComparator, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) { - return of(keyComparator, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9).put(k10, v10); + return createFromPairs(EntryComparator.of(keyComparator), k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9, k10, v10); } /** @@ -694,44 +694,39 @@ public static , V> TreeMap fill(int n, Sup @SuppressWarnings("varargs") @SafeVarargs public static , V> TreeMap ofEntries(Tuple2... entries) { - return ofEntries((Comparator & Serializable) K::compareTo, entries); + return createFromTuples(EntryComparator.natural(), entries); } /** - * Creates a {@code TreeMap} of the given entries using the natural key comparator. + * Creates a {@code TreeMap} of the given entries using the given key comparator. * - * @param The key type - * @param The value type - * @param entries Map entries + * @param The key type + * @param The value type + * @param entries Map entries + * @param keyComparator A key comparator * @return A new TreeMap containing the given entries. */ - @SuppressWarnings("varargs") + @SuppressWarnings({"unchecked", "varargs"}) @SafeVarargs - public static , V> TreeMap ofEntries(java.util.Map.Entry... entries) { - return ofEntries((Comparator & Serializable) K::compareTo, entries); + public static TreeMap ofEntries(Comparator keyComparator, Tuple2... entries) { + return createFromTuples(EntryComparator.of(keyComparator), entries); } /** - * Creates a {@code TreeMap} of the given entries using the given key comparator. + * Creates a {@code TreeMap} of the given entries using the natural key comparator. * - * @param The key type - * @param The value type - * @param entries Map entries - * @param keyComparator A key comparator + * @param The key type + * @param The value type + * @param entries Map entries * @return A new TreeMap containing the given entries. */ - @SuppressWarnings("unchecked") + @SuppressWarnings("varargs") @SafeVarargs - public static TreeMap ofEntries(Comparator keyComparator, Tuple2... entries) { - Objects.requireNonNull(keyComparator, "keyComparator is null"); - Objects.requireNonNull(entries, "entries is null"); - RedBlackTree> tree = RedBlackTree.empty(new EntryComparator<>(keyComparator)); - for (Tuple2 entry : entries) { - tree = tree.insert((Tuple2) entry); - } - return tree.isEmpty() ? empty(keyComparator) : new TreeMap<>(tree); + public static , V> TreeMap ofEntries(java.util.Map.Entry... entries) { + return createFromMapEntries(EntryComparator.natural(), entries); } + /** * Creates a {@code TreeMap} of the given entries using the given key comparator. * @@ -741,15 +736,10 @@ public static TreeMap ofEntries(Comparator keyComparator * @param keyComparator A key comparator * @return A new TreeMap containing the given entries. */ + @SuppressWarnings("varargs") @SafeVarargs public static TreeMap ofEntries(Comparator keyComparator, java.util.Map.Entry... entries) { - Objects.requireNonNull(keyComparator, "keyComparator is null"); - Objects.requireNonNull(entries, "entries is null"); - RedBlackTree> tree = RedBlackTree.empty(new EntryComparator<>(keyComparator)); - for (java.util.Map.Entry entry : entries) { - tree = tree.insert(Tuple.of(entry.getKey(), entry.getValue())); - } - return tree.isEmpty() ? empty(keyComparator) : new TreeMap<>(tree); + return createFromMapEntries(EntryComparator.of(keyComparator), entries); } /** @@ -761,7 +751,7 @@ public static TreeMap ofEntries(Comparator keyComparator * @return A new TreeMap containing the given entries. */ public static , V> TreeMap ofEntries(Iterable> entries) { - return ofEntries((Comparator & Serializable) K::compareTo, entries); + return createTreeMap(EntryComparator.natural(), entries); } /** @@ -775,22 +765,20 @@ public static , V> TreeMap ofEntries(Itera */ @SuppressWarnings("unchecked") public static TreeMap ofEntries(Comparator keyComparator, Iterable> entries) { - Objects.requireNonNull(keyComparator, "keyComparator is null"); - Objects.requireNonNull(entries, "entries is null"); - if (entries instanceof TreeMap) { - return (TreeMap) entries; - } else { - RedBlackTree> tree = RedBlackTree.empty(new EntryComparator<>(keyComparator)); - for (Tuple2 entry : entries) { - tree = tree.insert((Tuple2) entry); - } - return new TreeMap<>(tree); - } + return createTreeMap(EntryComparator.of(keyComparator), entries); } + // -- TreeMap API + @Override public TreeMap bimap(Function keyMapper, Function valueMapper) { - return bimap(naturalComparator(), keyMapper, valueMapper); + return bimap(this, EntryComparator.natural(), keyMapper, valueMapper); + } + + @Override + public TreeMap bimap(Comparator keyComparator, + Function keyMapper, Function valueMapper) { + return bimap(this, EntryComparator.of(keyComparator), keyMapper, valueMapper); } @Override @@ -803,15 +791,6 @@ public Tuple2, TreeMap> computeIfPresent(K key, BiFunction TreeMap bimap(Comparator keyComparator, - Function keyMapper, Function valueMapper) { - Objects.requireNonNull(keyMapper, "keyMapper is null"); - Objects.requireNonNull(valueMapper, "valueMapper is null"); - return createTreeMap(new EntryComparator<>(keyComparator), - entries.iterator().map(entry -> Tuple.of(keyMapper.apply(entry._1), valueMapper.apply(entry._2)))); - } - @Override public boolean containsKey(K key) { final V ignored = null; @@ -875,15 +854,14 @@ public TreeMap filterValues(Predicate predicate) { @Override public TreeMap flatMap(BiFunction>> mapper) { - return flatMap(naturalComparator(), mapper); + return flatMap(this, EntryComparator.natural(), mapper); } @Override public TreeMap flatMap(Comparator keyComparator, BiFunction>> mapper) { - Objects.requireNonNull(mapper, "mapper is null"); - return createTreeMap(new EntryComparator<>(keyComparator), - entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2))); + Objects.requireNonNull(keyComparator, "keyComparator is null"); + return flatMap(this, EntryComparator.of(keyComparator), mapper); } @Override @@ -944,7 +922,7 @@ public Iterator> iterator() { @SuppressWarnings("unchecked") @Override public Comparator keyComparator() { - return ((EntryComparator) entries.comparator()).keyComparator; + return ((EntryComparator) entries.comparator()).keyComparator(); } @Override @@ -954,15 +932,14 @@ public SortedSet keySet() { @Override public TreeMap map(BiFunction> mapper) { - return map(naturalComparator(), mapper); + return map(this, EntryComparator.natural(), mapper); } @Override public TreeMap map(Comparator keyComparator, BiFunction> mapper) { - Objects.requireNonNull(mapper, "mapper is null"); - return createTreeMap(new EntryComparator<>(keyComparator), - entries.iterator().map(entry -> mapper.apply(entry._1, entry._2))); + Objects.requireNonNull(keyComparator, "keyComparator is null"); + return map(this, EntryComparator.of(keyComparator), mapper); } @Override @@ -1177,25 +1154,6 @@ public Seq values() { return iterator().map(Tuple2::_2).toStream(); } - /** - * Internal factory method, used with Tuple2 comparator instead of a key comparator. - * - * @param comparator An Tuple2 comparator - * @param entries Map entries - * @param Key type - * @param Value type - * @return A new TreeMap. - */ - @SuppressWarnings("unchecked") - private static TreeMap createTreeMap(Comparator> comparator, - Iterable> entries) { - RedBlackTree> tree = RedBlackTree.empty(comparator); - for (Tuple2 entry : entries) { - tree = tree.insert((Tuple2) entry); - } - return tree.isEmpty() ? (TreeMap) empty() : new TreeMap<>(tree); - } - // -- Object @Override @@ -1225,34 +1183,201 @@ public String toString() { return mkString(stringPrefix() + "(", ", ", ")"); } + // -- private helpers + + private static TreeMap bimap(TreeMap map, EntryComparator entryComparator, + Function keyMapper, Function valueMapper) { + Objects.requireNonNull(keyMapper, "keyMapper is null"); + Objects.requireNonNull(valueMapper, "valueMapper is null"); + return createTreeMap(entryComparator, map.entries, entry -> entry.map(keyMapper, valueMapper)); + } + + private static TreeMap flatMap(TreeMap map, EntryComparator entryComparator, + BiFunction>> mapper) { + Objects.requireNonNull(mapper, "mapper is null"); + return createTreeMap(entryComparator, map.entries.iterator().flatMap(entry -> mapper.apply(entry._1, entry._2))); + } + + private static TreeMap map(TreeMap map, EntryComparator entryComparator, + BiFunction> mapper) { + Objects.requireNonNull(mapper, "mapper is null"); + return createTreeMap(entryComparator, map.entries, entry -> entry.map(mapper)); + } + + // -- internal factory methods + + private static Collector, ArrayList>, TreeMap> createCollector(EntryComparator entryComparator) { + final Supplier>> supplier = ArrayList::new; + final BiConsumer>, Tuple2> accumulator = ArrayList::add; + final BinaryOperator>> combiner = (left, right) -> { + left.addAll(right); + return left; + }; + final Function>, TreeMap> finisher = list -> createTreeMap(entryComparator, list); + return Collector.of(supplier, accumulator, combiner, finisher); + } + + @SuppressWarnings("unchecked") + private static TreeMap createTreeMap(EntryComparator entryComparator, + Iterable> entries) { + Objects.requireNonNull(entries, "entries is null"); + RedBlackTree> tree = RedBlackTree.empty(entryComparator); + for (Tuple2 entry : (Iterable>) entries) { + tree = tree.insert(entry); + } + return new TreeMap<>(tree); + } + + private static TreeMap createTreeMap(EntryComparator entryComparator, + Iterable> entries, Function, Tuple2> entryMapper) { + RedBlackTree> tree = RedBlackTree.empty(entryComparator); + for (Tuple2 entry : entries) { + tree = tree.insert(entryMapper.apply(entry)); + } + return new TreeMap<>(tree); + } + + @SuppressWarnings("unchecked") + private static TreeMap createFromMap(EntryComparator entryComparator, java.util.Map map) { + Objects.requireNonNull(map, "map is null"); + RedBlackTree> tree = RedBlackTree.empty(entryComparator); + for (java.util.Map.Entry entry : ((java.util.Map) map).entrySet()) { + tree = tree.insert(Tuple.of(entry.getKey(), entry.getValue())); + } + return new TreeMap<>(tree); + } + + @SuppressWarnings("unchecked") + private static TreeMap createFromTuple(EntryComparator entryComparator, Tuple2 entry) { + Objects.requireNonNull(entry, "entry is null"); + return new TreeMap<>(RedBlackTree.of(entryComparator, (Tuple2) entry)); + } + + @SuppressWarnings("unchecked") + private static TreeMap createFromTuples(EntryComparator entryComparator, Tuple2... entries) { + Objects.requireNonNull(entries, "entries is null"); + RedBlackTree> tree = RedBlackTree.empty(entryComparator); + for (Tuple2 entry : entries) { + tree = tree.insert((Tuple2) entry); + } + return new TreeMap<>(tree); + } + + @SafeVarargs + private static TreeMap createFromMapEntries(EntryComparator entryComparator, java.util.Map.Entry... entries) { + Objects.requireNonNull(entries, "entries is null"); + RedBlackTree> tree = RedBlackTree.empty(entryComparator); + for (java.util.Map.Entry entry : entries) { + final K key = entry.getKey(); + final V value = entry.getValue(); + tree = tree.insert(Tuple.of(key, value)); + } + return new TreeMap<>(tree); + } + + @SuppressWarnings("unchecked") + private static TreeMap createFromPairs(EntryComparator entryComparator, Object... pairs) { + RedBlackTree> tree = RedBlackTree.empty(entryComparator); + for (int i = 0; i < pairs.length; i += 2) { + final K key = (K) pairs[i]; + final V value = (V) pairs[i + 1]; + tree = tree.insert(Tuple.of(key, value)); + } + return new TreeMap<>(tree); + } + private TreeMap createFromEntries(Iterable> tuples) { - return createTreeMap(entries.comparator(), tuples); + return createTreeMap((EntryComparator) entries.comparator(), tuples); } private TreeMap emptyInstance() { return isEmpty() ? this : new TreeMap<>(entries.emptyInstance()); } - /** - * Used to compare entries by key and store the keyComparator for later access. - * - * @param key type - * @param value type, needed at compile time for the Comparator interface - */ - static class EntryComparator implements Comparator>, Serializable { + // -- internal types + + private interface EntryComparator extends Comparator>, Serializable { - private static final long serialVersionUID = 1L; + long serialVersionUID = 1L; - final Comparator keyComparator; + static EntryComparator of(Comparator keyComparator) { + Objects.requireNonNull(keyComparator, "keyComparator is null"); + return new Specific<>(keyComparator); + } - @SuppressWarnings("unchecked") - EntryComparator(Comparator keyComparator) { - this.keyComparator = (Comparator) keyComparator; + static EntryComparator natural() { + return Natural.instance(); } - @Override - public int compare(Tuple2 e1, Tuple2 e2) { - return keyComparator.compare(e1._1, e2._1); + Comparator keyComparator(); + + // -- internal impls + + final class Specific implements EntryComparator { + + private static final long serialVersionUID = 1L; + + private final Comparator keyComparator; + + @SuppressWarnings("unchecked") + Specific(Comparator keyComparator) { + this.keyComparator = (Comparator) keyComparator; + } + + @Override + public int compare(Tuple2 e1, Tuple2 e2) { + return keyComparator.compare(e1._1, e2._1); + } + + @Override + public Comparator keyComparator() { + return keyComparator; + } + } + + final class Natural implements EntryComparator { + + private static final long serialVersionUID = 1L; + + private static final Natural INSTANCE = new Natural<>(); + + // hidden + private Natural() { + } + + @SuppressWarnings("unchecked") + public static Natural instance() { + return (Natural) INSTANCE; + } + + @SuppressWarnings("unchecked") + @Override + public int compare(Tuple2 e1, Tuple2 e2) { + final K key1 = e1._1; + final K key2 = e2._1; + if (key1 == null) { + return (key2 == null) ? 0 : -1; + } else if (key2 == null) { + return 1; + } else { + return ((Comparable) key1).compareTo(key2); + } + } + + @Override + public Comparator keyComparator() { + return Comparators.naturalComparator(); + } + + /** + * Instance control for object serialization. + * + * @return The singleton instance of NaturalEntryComparator. + * @see java.io.Serializable + */ + private Object readResolve() { + return INSTANCE; + } } } } diff --git a/javaslang/src/test/java/javaslang/collection/AbstractMapTest.java b/javaslang/src/test/java/javaslang/collection/AbstractMapTest.java index 82a7d61389..19b3ded75b 100644 --- a/javaslang/src/test/java/javaslang/collection/AbstractMapTest.java +++ b/javaslang/src/test/java/javaslang/collection/AbstractMapTest.java @@ -27,6 +27,7 @@ import java.util.stream.Collector; import static java.util.Arrays.asList; +import static javaslang.API.Some; import static javaslang.Serializables.deserialize; import static javaslang.Serializables.serialize; @@ -1056,6 +1057,30 @@ public void shouldReplaceAllValuesWithFunctionResult() { assertThat(actual).isEqualTo(expected); } + @Test + public void shouldGetValueOfNullKeyWhenPutFirstHavingTwoEntries() { + final Map map = mapOf(null, "a", 2, "b"); + assertThat(map.get(null)).isEqualTo(Some("a")); + } + + @Test + public void shouldGetValueOfNullKeyWhenPutLastHavingTwoEntries() { + final Map map = mapOf(1, "a", null, "b"); + assertThat(map.get(null)).isEqualTo(Some("b")); + } + + @Test + public void shouldGetAPresentNullValueWhenPutFirstHavingTwoEntries() { + final Map map = mapOf(1, null, 2, "b"); + assertThat(map.get(1)).isEqualTo(Some(null)); + } + + @Test + public void shouldGetAPresentNullValueWhenPutLastHavingTwoEntries() { + final Map map = mapOf(1, "a", 2, null); + assertThat(map.get(2)).isEqualTo(Some(null)); + } + // -- getOrElse public void shouldReturnDefaultValue() { diff --git a/javaslang/src/test/java/javaslang/collection/AbstractTraversableTest.java b/javaslang/src/test/java/javaslang/collection/AbstractTraversableTest.java index 0e0ff86662..9364628efa 100644 --- a/javaslang/src/test/java/javaslang/collection/AbstractTraversableTest.java +++ b/javaslang/src/test/java/javaslang/collection/AbstractTraversableTest.java @@ -970,12 +970,12 @@ public void shouldComputeMaxOfBigDecimal() { @Test(expected = NullPointerException.class) public void shouldThrowNPEWhenMaxOfNullAndInt() { - System.out.println(of(null, 1).max()); + of(null, 1).max(); } @Test(expected = NullPointerException.class) public void shouldThrowNPEWhenMaxOfIntAndNull() { - System.out.println(of(1, null).max()); + of(1, null).max(); } // -- maxBy(Comparator) @@ -1101,7 +1101,7 @@ public void shouldThrowNPEWhenMinOfNullAndInt() { @Test(expected = NullPointerException.class) public void shouldThrowNPEWhenMinOfIntAndNull() { - System.out.println(of(1, null).min()); + of(1, null).min(); } // -- minBy(Comparator) diff --git a/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java b/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java index fcbcf194e0..b3b6c7aa3a 100644 --- a/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java +++ b/javaslang/src/test/java/javaslang/collection/PriorityQueueTest.java @@ -155,7 +155,7 @@ public void shouldScanWithNonComparable() { @SuppressWarnings("unchecked") @Test - public final void shouldNarrowPriorityQueue() { + public void shouldNarrowPriorityQueue() { final PriorityQueue doubles = PriorityQueue.of(toStringComparator(), 1.0d); final PriorityQueue numbers = PriorityQueue.narrow(doubles); final int actual = numbers.enqueue(new BigDecimal("2.0")).sum().intValue(); diff --git a/javaslang/src/test/java/javaslang/collection/TreeMapTest.java b/javaslang/src/test/java/javaslang/collection/TreeMapTest.java index 811a7447ea..b0b2e53b55 100644 --- a/javaslang/src/test/java/javaslang/collection/TreeMapTest.java +++ b/javaslang/src/test/java/javaslang/collection/TreeMapTest.java @@ -5,12 +5,10 @@ */ package javaslang.collection; - import javaslang.Tuple; import javaslang.Tuple2; import org.junit.Test; -import java.io.Serializable; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; @@ -20,8 +18,10 @@ import java.util.function.Supplier; import java.util.stream.Collector; +import static javaslang.API.*; import static javaslang.Serializables.deserialize; import static javaslang.Serializables.serialize; +import static javaslang.collection.Comparators.naturalComparator; public class TreeMapTest extends AbstractSortedMapTest { @@ -37,7 +37,7 @@ java.util.Map javaEmptyMap() { @Override protected , T2> TreeMap emptyMap() { - return TreeMap.empty(nullsFirst()); + return TreeMap.empty(); } @Override @@ -59,39 +59,48 @@ protected boolean emptyShouldBeSingleton() { @SafeVarargs @Override protected final , V> TreeMap mapOfTuples(Tuple2... entries) { - return TreeMap.ofEntries(nullsFirst(), entries); + return TreeMap.ofEntries(entries); } @SuppressWarnings("varargs") @SafeVarargs @Override protected final , V> TreeMap mapOfEntries(java.util.Map.Entry... entries) { - return TreeMap.ofEntries(nullsFirst(), entries); + return TreeMap.ofEntries(entries); } @Override protected , V> TreeMap mapOf(K key, V value) { - return TreeMap.of(nullsFirst(), key, value); + return TreeMap.of(key, value); } @Override protected , V> Map mapOf(K k1, V v1, K k2, V v2) { - return TreeMap.of(nullsFirst(), k1, v1, k2, v2); + return TreeMap.of(k1, v1, k2, v2); } @Override protected , V> Map mapOf(K k1, V v1, K k2, V v2, K k3, V v3) { - return TreeMap.of(nullsFirst(), k1, v1, k2, v2, k3, v3); + return TreeMap.of(k1, v1, k2, v2, k3, v3); } @Override protected , V> TreeMap mapTabulate(int n, Function> f) { - return TreeMap.tabulate(nullsFirst(), n, f); + return TreeMap.tabulate(n, f); } @Override protected , V> TreeMap mapFill(int n, Supplier> s) { - return TreeMap.fill(nullsFirst(), n, s); + return TreeMap.fill(n, s); + } + + // -- static factories + + @Test + public void shouldCreateOfEntries() { + final List> entries = List(Tuple(1, "a"), Tuple(2, "b")); + final TreeMap map = TreeMap.ofEntries(naturalComparator(), entries); + assertThat(map.toList()).isEqualTo(entries); } // -- static narrow @@ -149,29 +158,37 @@ public void shouldSerializeDeserializeNonEmptyMap() { assertThat(actual).isEqualTo(expected); } - // -- obsolete tests + // -- flatMap - @Override - public void shouldPreserveSingletonInstanceOnDeserialization() { - // The empty TreeMap encapsulates a comparator and therefore cannot be a singleton + @Test + public void shouldReturnATreeMapWithCorrectComparatorWhenFlatMappingToEmpty() { + + final TreeMap testee = TreeMap.of(Comparator.naturalOrder(), 1, "1", 2, "2"); + assertThat(testee.head()).isEqualTo(Tuple(1, "1")); + + final TreeMap actual = testee.flatMap(Comparator.reverseOrder(), (k, v) -> List.empty()); + assertThat(actual).isEmpty(); + + final TreeMap actualSorted = actual.put(1, "1").put(2, "2"); + assertThat(actualSorted.head()).isEqualTo(Tuple(2, "2")); } // -- map @Test public void shouldReturnModifiedKeysMapWithNonUniqueMapperAndPredictableOrder() { - final Map actual = TreeMap - .of(3, "3").put(1, "1").put(2, "2") + final TreeMap actual = TreeMap + .of(3, "3", 1, "1", 2, "2") .mapKeys(Integer::toHexString).mapKeys(String::length); - final Map expected = TreeMap.of(1, "3"); + final TreeMap expected = TreeMap.of(1, "3"); assertThat(actual).isEqualTo(expected); } - // -- helpers + // -- obsolete tests - // A comparator that allows null to be inserted into a TreeMap - private static > Comparator nullsFirst() { - return Comparator.nullsFirst((Comparator & Serializable) K::compareTo); + @Override + public void shouldPreserveSingletonInstanceOnDeserialization() { + // The empty TreeMap encapsulates a comparator and therefore cannot be a singleton } }