diff --git a/spring-core/src/main/java/org/springframework/util/MultiValueMapCollector.java b/spring-core/src/main/java/org/springframework/util/MultiValueMapCollector.java
new file mode 100644
index 000000000000..83e0f46a62c0
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/util/MultiValueMapCollector.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2002-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.util;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collector;
+
+/**
+ * A {@link Collector} for building a {@link MultiValueMap} from a {@link java.util.stream.Stream}.
+ *
+ * Moved from {@code org.springframework.data.util.MultiValueMapCollector}.
+ *
+ * @author Jens Schauder
+ *
+ * @param – the type of input elements to the reduction operation
+ * @param – the type of the key elements
+ * @param – the type of the value elements
+ */
+public class MultiValueMapCollector implements Collector, MultiValueMap> {
+ private final Function keyFunction;
+ private final Function valueFunction;
+
+ public MultiValueMapCollector(Function keyFunction, Function valueFunction) {
+ this.keyFunction = keyFunction;
+ this.valueFunction = valueFunction;
+ }
+
+ public static MultiValueMapCollector indexingBy(Function indexer) {
+ return new MultiValueMapCollector<>(indexer, Function.identity());
+ }
+
+ @Override
+ public Supplier> supplier() {
+ return () -> CollectionUtils.toMultiValueMap(new HashMap>());
+ }
+
+ @Override
+ public BiConsumer, T> accumulator() {
+ return (map, t) -> map.add(this.keyFunction.apply(t), this.valueFunction.apply(t));
+ }
+
+ @Override
+ public BinaryOperator> combiner() {
+ return (map1, map2) -> {
+ for (Entry> entry : map2.entrySet()) {
+ map1.addAll(entry.getKey(), entry.getValue());
+ }
+ return map1;
+ };
+ }
+
+ @Override
+ public Function, MultiValueMap> finisher() {
+ return Function.identity();
+ }
+
+ @Override
+ public Set characteristics() {
+ return EnumSet.of(Characteristics.IDENTITY_FINISH, Characteristics.UNORDERED);
+ }
+}
diff --git a/spring-core/src/test/java/org/springframework/util/MultiValueMapCollectorTests.java b/spring-core/src/test/java/org/springframework/util/MultiValueMapCollectorTests.java
new file mode 100644
index 000000000000..de9c080fce8e
--- /dev/null
+++ b/spring-core/src/test/java/org/springframework/util/MultiValueMapCollectorTests.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2002-present the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.util;
+
+import java.util.stream.Stream;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link MultiValueMapCollector}.
+ *
+ * @author Florian Hof
+ */
+class MultiValueMapCollectorTests {
+
+ @Test
+ void indexingBy() {
+ MultiValueMapCollector collector = MultiValueMapCollector.indexingBy(String::length);
+ MultiValueMap content = Stream.of("abc", "ABC", "123", "1234", "abcdef", "ABCDEF").collect(collector);
+ assertThat(content.get(3)).containsOnly("abc", "ABC", "123");
+ assertThat(content.get(4)).containsOnly("abcdef", "ABCDEF");
+ assertThat(content.get(6)).containsOnly("1234");
+ assertThat(content.get(1)).isNull();
+ }
+}