Funkcja scalania nie ma szansy na uzyskanie klucza, który jest tym samym problemem, wbudowana funkcja ma, gdy pominąć funkcję scalania.
Rozwiązaniem jest użycie innego toMap
realizacji, które nie opierają się na Map.merge
:
public static <T, K, V> Collector<T, ?, Map<K,V>>
toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper) {
return Collector.of(HashMap::new,
(m, t) -> {
K k = keyMapper.apply(t);
V v = Objects.requireNonNull(valueMapper.apply(t));
if(m.putIfAbsent(k, v) != null) throw duplicateKey(k, m.get(k), v);
},
(m1, m2) -> {
m2.forEach((k,v) -> {
if(m1.putIfAbsent(k, v)!=null) throw duplicateKey(k, m1.get(k), v);
});
return m1;
});
}
private static IllegalStateException duplicateKey(Object k, Object v1, Object v2) {
return new IllegalStateException("Duplicate key "+k+" (values "+v1+" and "+v2+')');
}
(jest to w zasadzie co Implementacja Javy 9 z dnia toMap
bez funkcji scalania zrobi)
Wszystko, co musisz zrobić w swoim kodzie, to przekierowanie połączenia toMap
i pominięcie funkcji scalania:
String keyvalp = "test=one\ntest2=two\ntest2=three";
Map<String, String> map = Pattern.compile("\n")
.splitAsStream(keyvalp)
.map(entry -> entry.split("="))
.collect(toMap(split -> split[0], split -> split[1]));
(lub ContainingClass.toMap
jeśli jej nie w tej samej klasy, ani importu statyczne) < \ sup>
Kolektor obsługuje równoległego przetwarzania jak oryginalne toMap
kolektora, chociaż nie jest to bardzo prawdopodobne, aby uzyskać korzyści z przetwarzania równoległego tutaj , nawet z większą ilością elementów do przetworzenia.
przypadku, gdybym cię prawidłowo, wystarczy tylko chcieć, aby wybrać albo, starszej lub nowszej wartości w funkcji korespondencji seryjnej w oparciu o rzeczywistą klucza, można to zrobić za pomocą klucza Predicate
jak ta
public static <T, K, V> Collector<T, ?, Map<K,V>>
toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper,
Predicate<? super K> useOlder) {
return Collector.of(HashMap::new,
(m, t) -> {
K k = keyMapper.apply(t);
m.merge(k, valueMapper.apply(t), (a,b) -> useOlder.test(k)? a: b);
},
(m1, m2) -> {
m2.forEach((k,v) -> m1.merge(k, v, (a,b) -> useOlder.test(k)? a: b));
return m1;
});
}
Map<String, String> map = Pattern.compile("\n")
.splitAsStream(keyvalp)
.map(entry -> entry.split("="))
.collect(toMap(split -> split[0], split -> split[1], key -> condition));
Istnieje kilka sposobów, aby dostosować ten kolektor ...
Możesz później filtrować połączone wartości, czy naprawdę trzeba je filtrować podczas łączenia? –
Czy możesz podać przykład? Podczas scalania muszę zdecydować, które z wartości przyjąć (o1 lub o2). Decyzję należy podjąć na ** kluczu **. Ale klucz nie zawsze występuje dwa razy.Czasem tylko w takim przypadku trzeba zdecydować o fuzji. – membersound
ok, widzę. Możesz stworzyć oddzielną mapę i uruchomić '.map (entry -> entry.split (" = ")). ForEach()' i sprawdzić dla każdego wpisu, czy wartość jest już w Mapie. Jeśli nie - dodaj, w przeciwnym razie - sprawdź, czy wymienić lub nie. –