Java collection / map apply方法等效吗?

时间:2009-04-13 16:23:48

标签: java collections apply

我想将一个函数应用于Java集合,在这种特殊情况下是一个映射。有一个很好的方法来做到这一点?我有一张地图,想在地图上的所有值上运行trim()并让地图反映更新。

8 个答案:

答案 0 :(得分:36)

使用Java 8的lambdas,这是一个单行:

map.replaceAll((k, v) -> v.trim());

为了历史,这里是没有lambdas的版本:

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();
  }
});

答案 1 :(得分:11)

除了您接受的回复之外,我不知道如何使用JDK库,但Google Collections允许您使用类com.google.collect.Mapscom.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方法如果你正在大量操纵所述地图的话。

对于集合存在类似的Collections2.transform(Collection<F>,Function<F,T>)方法。

答案 2 :(得分:2)

是否可以就地修改集合取决于集合中对象的类。

如果这些对象是不可变的(字符串是),那么你不能只从集合中获取项目并修改它们 - 而是你需要遍历集合,调用相关函数,然后放置结果价值回归。

答案 3 :(得分:2)

对于类似这样的事情可能有些过分,但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"));

我强烈推荐O'Reilly的Jakarta Commons Cookbook

答案 4 :(得分:2)

我最终使用@ erickson的答案变异,变异为:

  • 返回新的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;
}

答案 5 :(得分:1)

您必须迭代所有条目并修剪每个String值。由于String是不可变的,因此您必须将其重新放入地图中。更好的方法可能是在将值放在地图中时修剪它们。

答案 6 :(得分:1)

我想出了一个“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();

答案 7 :(得分:-1)

您还可以查看Google Collections