문제

Java 컬렉션에 함수를 적용하고 싶습니다.이 경우에는 맵이 있습니다. 이것을하는 좋은 방법이 있습니까? 지도가 있고 맵의 모든 값에서 Trim ()을 실행하고 싶고 맵에 업데이트를 반영합니다.

도움이 되었습니까?

해결책

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

다른 팁

허용 된 응답 이외의 JDK 라이브러리로 그렇게하는 방법을 모르겠지만 Google 컬렉션은 클래스를 사용하여 다음을 수행 할 수 있습니다. 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 상기 맵을 크게 조작하는 경우 방법을 여러 번 호출 할 수 있습니다.

유사한 Collections2.transform(Collection<F>,Function<F,T>) 수집에 대한 방법이 존재합니다.

컬렉션을 현장에서 수정할 수 있는지 여부는 컬렉션의 객체 클래스에 따라 다릅니다.

해당 객체가 불변 (문자열이있는)이라면 (문자열이든) 컬렉션에서 항목을 가져 와서 수정할 수는 없습니다. 대신 컬렉션을 반복하고 관련 기능을 호출 한 다음 결과 값을 다시 넣어야합니다.

이와 같은 것에 대해 과잉 일 수 있지만 이러한 유형의 문제에 대한 많은 유틸리티가 있습니다. 아파치 커먼즈 컬렉션 도서관.

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"));

나는 강력히 추천한다 자카르타 커먼즈 요리 책 오라일리에서.

나는 @erickson의 대답의 돌연변이를 사용하여 다음과 같이 돌연변이했다.

  • 새로 돌아갑니다 Collection, 제자리에 수정되지 않습니다
  • 반품 Collection유형의 요소가 반환 유형과 동일한 s 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;
}

모든 항목을 반복하고 각 문자열 값을 다듬어야합니다. 문자열은 불변이기 때문에지도에 다시 장착해야합니다. 더 나은 접근 방식은 값이 맵에 배치 될 때 값을 다듬는 것일 수 있습니다.

나는 "맵퍼"수업을 생각해 냈습니다.

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

Google 컬렉션을 살펴볼 수도 있습니다

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top