2013-03-21 1 views
3

지도를 사용하여 동일한 클래스/그룹과 관련된 객체의 집합/목록 또는 증가시키려는 AtomicInteger와 같은 값을 루프에 저장합니다. 내가 이렇게 종종 다음 코드 종류를 쓰기 (내지도에 null를 저장하지 않는 가정) :자바를 사용하여지도에서 누락 된 값을 자동으로 생성하는 관용구

/* Example #1 -- aggregation */ 
Map<K, Set<O>> map = new HashMap<K, Set<O>>(); 
for (O o : oList) { 
    K k = o.getK(); 
    Set<O> oSet = map.get(k); 
    if (oSet == null) { 
     oSet = new HashSet<O>(o); 
     map.put(k, oSet); 
    } else { 
     oSet.add(o); 
    } 
} 

/* Example #2 -- counting */ 
Map<K, AtomicInteger> map = new HashMap<K, AtomicInteger>(); 
for (O o : oList) { 
    K k = o.getK(); 
    AtomicInteger i = map.get(k); 
    if (i == null) { 
     i = new AtomicInteger(1); 
     map.put(k, i); 
    } else { 
     i.increment(); 
    } 
} 

나는 즉시 공장/모델 객체에서 값을 만들 수 있습니다 아파치 공통의 컬렉션 DefaultedMap 알고 그것이 없을 때; 하지만 2/3 줄의 코드 작성 (다소 작음)을 피하기 위해 (다른) 외부 라이브러리에만 의존합니다.

더 쉬운 해결책이 있습니까 (특히 # 2). 이 경우 동료 개발자가 사용/권장하는 것은 무엇입니까? 이런 종류의 "기본지도"를 제공하는 다른 도서관이 있습니까? 자신 만의 장식 된지도를 작성합니까?

답변

1

Java WS의 일부로 MultivaluedMap처럼 보입니다.

그래서 귀하의 질문에 대답하는 Spring Framework

에 의해 구현과 같은, 거기에이에 대한 기본 구현하지 않습니다 그리고 당신은 자신의 롤 또는 더 나은 구현 중 하나를 사용합니다.

3

Google의 guava-libraries도 이러한 맵 구현을 제공합니다. 그러나 나는 그런 작은 이익을 위해서만 도서관을 사용하지 않을 것입니다. 그런 라이브러리를 이미 사용하고 있다면 맵 사용에 대해 생각할 수 있습니다. 그러나 일반적으로, 이것은 제 생각으로는 사소한 일에 라이브러리를 사용하는 것을 좋아하지 않습니다.

귀하의 질문에있는 예제가 저에게 잘 보입니다. 나는 또한이 관용구를 사용하고있다.

7

자바 8에서, 상기 방법 computeIfAbsent()Map 인터페이스 첨가 : 지정된 키가 이미 값과 연관되지 않은 (또는 널 (null)에 대응한다) 경우

default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction)

에 시도 지정된 매핑 함수를 사용해 그 값을 계산해, null가 아닌 한 그것을이 맵에 입력합니다.

documentation에 따르면, 가장 일반적인 용도는 새 개체를 초기 매핑 값으로 만들거나 다중 값지도를 구현하는 것입니다. 예를 들어 다음과 같이

map.computeIfAbsent(key, k -> new HashSet<V>()).add(v); 

그래서 당신은 당신의 예를 다시 작성할 수 :

/* Example #1 -- aggregation */ 
Map<K, Set<O>> map = new HashMap<>(); 
oList.forEach(o -> map.computeIfAbsent(o.getK(), k -> new HashSet<>()).add(o)); 

/* Example #2 -- counting */ 
Map<K, AtomicInteger> map = new HashMap<>(); 
oList.forEach(o -> map.computeIfAbsent(o.getK(), k -> new AtomicInteger(0)).incrementAndGet()); 

또 다른 옵션은 Collectors.groupingBy과 함께 스트림 API를 사용하는 것입니다

/* Example #1 -- aggregation */ 
Map<K, Set<O>> map = oList.stream() 
          .collect(Collectors.groupingBy(O::getK, Collectors.toSet())); 

/* Example #2 -- counting using a Long instead of an AtomicInteger */ 
Map<K, Long> map = oList.stream() 
         .map(O::getK) 
         .collect(Collectors.groupingBy(k -> k, Collectors.counting()));