Я хотел бы применить функцию к коллекции Java, в данном конкретном случае - к карте. Есть ли хороший способ сделать это? У меня есть карта, и я хотел бы просто запустить trim() для всех значений на карте и отобразить карту обновлений.Java collection/map применить метод эквивалент?
ответ
С лямбды Java 8, это является один лайнер:
map.replaceAll((k, v) -> v.trim());
Ради истории, вот версия без лямбды:
public void trimValues(Map<?, String> map) {
for (Map.Entry<?, String> e : map.entrySet()) {
String val = e.getValue();
if (val != null)
e.setValue(val.trim());
}
}
Или, в более общем плане:
interface Function<T> {
T operate(T val);
}
public static <T> void replaceValues(Map<?, T> map, Function<T> f)
{
for (Map.Entry<?, T> e : map.entrySet())
e.setValue(f.operate(e.getValue()));
}
Util.replaceValues(myMap, new Function<String>() {
public String operate(String val)
{
return (val == null) ? null : val.trim();
}
});
Можете ли вы изменить свою коллекцию на месте или нет, зависит от класса объектов в коллекции.
Если эти объекты неизменяемы (какие строки), вы не можете просто взять элементы из коллекции и изменить их - вместо этого вам нужно будет перебирать коллекцию, вызывать соответствующую функцию, а затем возвращаемое значение.
Вам придется перебирать все записи и обрезать каждое значение строки. Поскольку String неизменен, вам придется переложить его на карту. Лучшим подходом может быть обрезка значений по мере их размещения на карте.
Возможно, это слишком много, но есть ряд действительно хороших утилит для этих проблем в библиотеке Apache Commons Collections.
Map<String, String> map = new HashMap<String, String>();
map.put("key1", "a ");
map.put("key2", " b ");
map.put("key3", " c");
TransformedMap.decorateTransform(map,
TransformerUtils.nopTransformer(),
TransformerUtils.invokerTransformer("trim"));
Я настоятельно рекомендую Jakarta Commons Cookbook от O'Reilly.
Просто хотел упомянуть неизменяемую версию в библиотеке Apache Commons Collections: CollectionUtils.collect (коллекция inputCollection, трансформатор трансформатора) – Jakub
Вы также могли бы взглянуть на Google Коллекции
Тип неопределенного ... по крайней мере, предоставляет ссылку и описание/пример того, как использовать Коллекции Google для решать проблему? –
Я не знаю способ сделать это с JDK библиотеки, кроме вашего принятого ответа, однако Google Collections позволяет сделать следующие вещи, с классами com.google.collect.Maps
и com.google.common.base.Function
:
Map<?,String> trimmedMap = Maps.transformValues(untrimmedMap, new Function<String, String>() {
public String apply(String from) {
if (from != null)
return from.trim();
return null;
}
}
Самой большая разница этого метода с предложенным является то, что он обеспечивает вид на исходную карту, что означает, что, в то время как он всегда находится в синхронизации с оригинальной картой, методом apply
может быть вызвано много раз, если вы манипулируете сайтом d в значительной степени.
Подобный Collections2.transform(Collection<F>,Function<F,T>)
способ существует для коллекций.
Я пришел с классом "Mapper"
public static abstract class Mapper<FromClass, ToClass> {
private Collection<FromClass> source;
// Mapping methods
public abstract ToClass map(FromClass source);
// Constructors
public Mapper(Collection<FromClass> source) {
this.source = source;
}
public Mapper(FromClass ... source) {
this.source = Arrays.asList(source);
}
// Apply map on every item
public Collection<ToClass> apply() {
ArrayList<ToClass> result = new ArrayList<ToClass>();
for (FromClass item : this.source) {
result.add(this.map(item));
}
return result;
}
}
Что я использую так:
Collection<Loader> loaders = new Mapper<File, Loader>(files) {
@Override public Loader map(File source) {
return new Loader(source);
}
}.apply();
Я закончил с использованием мутацию ответа @ Эриксона, мутировавший в:
- вернуть новый
Collection
, не изменять на месте - вернуться
Collection
с с элементами типа, равными возвращаемым типа отображения вспомогательногоFunction
- над либо значениями карты или элементами списка
Код:
public static interface Function<L, R> {
L operate(R val);
}
public static <K, L, R> Map<K, L> map(Map<K, R> map, Function<L, R> f) {
Map<K, L> retMap = new HashMap<K, L>();
for (Map.Entry<K, R> e : map.entrySet()) retMap.put(e.getKey(), f.operate(e.getValue()));
return retMap;
}
public static <L, R> List<L> map(List<R> list, Function<L, R> f) {
List<L> retList = new ArrayList<L>();
for (R e : list) retList.add(f.operate(e));
return retList;
}
+1 для шаблон лямбда-функции – Alnitak
Эй эриксон - где я могу узнать об этом синтаксисе: Карта , String> map ?? Я просто изучаю java и не сталкивался с чем-либо подобным ... любое направление было бы оценено! –
@jamesemanon Это означает, что карта, которую вы передаете этому методу, может иметь любой тип ключа, но значение должно быть «String». Вы можете получить основы из [Java Tutorial] (https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html). [Общие сведения о пользователе Angelika Langer] (http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html) содержит гораздо более подробную информацию обо всех аспектах Java Generics. – erickson