Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions user/super/com/google/gwt/emul/java/util/stream/Collectors.java
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,11 @@ public static <T> Collector<T,?,List<T>> toList() {
public static <T, K, U> Collector<T, ?, Map<K, U>> toMap(
final Function<? super T, ? extends K> keyMapper,
final Function<? super T, ? extends U> valueMapper) {
return toMap(
keyMapper,
valueMapper,
(m1, m2) -> {
throw new IllegalStateException("Can't assign multiple values to the same key");
});
return toMap(keyMapper, valueMapper, null, HashMap::new, true);
}

private static RuntimeException getDuplicateKeyException(Object key) {
return new IllegalStateException("Duplicate key " + key);
}

public static <T, K, U> Collector<T, ?, Map<K, U>> toMap(
Expand Down Expand Up @@ -419,18 +418,32 @@ private static <T, R> Function<T, R> disallowNulls(Function<T, R> func) {
final Function<? super T, ? extends U> valueMapper,
final BinaryOperator<U> mergeFunction,
final Supplier<M> mapSupplier) {
return toMap(keyMapper, valueMapper, mergeFunction, mapSupplier, false);
}

/*
* If unique flag is true, mergeFunction can safely be null.
*/
private static <T, K, U, M extends Map<K, U>> Collector<T, ?, M> toMap(
final Function<? super T, ? extends K> keyMapper,
final Function<? super T, ? extends U> valueMapper,
final BinaryOperator<U> mergeFunction,
final Supplier<M> mapSupplier, final boolean unique) {
return Collector.of(
mapSupplier,
(map, item) -> {
K key = keyMapper.apply(item);
U newValue = valueMapper.apply(item);
U newValue = Objects.requireNonNull(valueMapper.apply(item));
if (map.containsKey(key)) {
if (unique) {
throw getDuplicateKeyException(key);
}
map.put(key, mergeFunction.apply(map.get(key), newValue));
} else {
map.put(key, newValue);
}
},
(m1, m2) -> mergeAll(m1, m2, mergeFunction),
(m1, m2) -> unique ? mergeAllUnique(m1, m2) : mergeAll(m1, m2, mergeFunction),
Collector.Characteristics.IDENTITY_FINISH);
}

Expand Down Expand Up @@ -467,6 +480,17 @@ private static <K, V, M extends Map<K, V>> M mergeAll(
return m1;
}

private static <K, V, M extends Map<K, V>> M mergeAllUnique(
M m1, M m2) {
for (Map.Entry<K, V> entry : m2.entrySet()) {
if (m1.get(entry.getKey()) != null) {
throw getDuplicateKeyException(entry.getKey());
}
m1.put(entry.getKey(), entry.getValue());
}
return m1;
}

private static <T, C extends Collection<T>> C addAll(C collection, Collection<T> items) {
collection.addAll(items);
return collection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.util.IntSummaryStatistics;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -406,28 +407,31 @@ public void testList() {
}

public void testMap() {
Collector<String, ?, Map<String, String>> c = toMap(Function.identity(), Function.identity());
Function<String, String> toUpper = s -> s.toUpperCase(Locale.ROOT);
Collector<String, ?, Map<String, String>> c = toMap(Function.identity(), toUpper);

// two distinct items
Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("a", "A");
map.put("b", "B");
applyItems(map, c, "a", "b");

// inline applyItems and test each to confirm failure for duplicates
try {
applyItemsWithoutSplitting(c, "a", "a");
fail("expected IllegalStateException");
} catch (IllegalStateException expected) {
assertEquals("Duplicate key a", expected.getMessage());
}
try {
applyItemsWithSplitting(c, "a", "a");
fail("expected IllegalStateException");
} catch (IllegalStateException expected) {
assertEquals("Duplicate key a", expected.getMessage());
}

assertZeroItemsCollectedAs(Collections.emptyMap(), c);
assertSingleItemCollectedAs(Collections.singletonMap("a", "a"), c, "a");
assertSingleItemCollectedAs(Collections.singletonMap("a", "A"), c, "a");

List<String> seen = new ArrayList<>();
c = toMap(Function.identity(), Function.identity(), (s, s2) -> {
Expand All @@ -441,6 +445,24 @@ public void testMap() {
assertEquals(Arrays.asList("first: a", "second: a", "first: a", "second: a"), seen);
}

public void testMapInvalid() {
Collector<String, ?, Map<String, String>> c = toMap(Function.identity(), ignore -> null);

// inline applyItems and test each to confirm failure for duplicates
try {
applyItemsWithoutSplitting(c, "a", "b");
fail("expected NullPointerException");
} catch (NullPointerException expected) {
// expected
}
try {
applyItemsWithSplitting(c, "a", "a");
fail("expected NullPointerException");
} catch (NullPointerException expected) {
// expected
}
}

public void testSet() {
Collector<String, ?, Set<String>> c = toSet();

Expand Down
Loading