Map을 반환해야하는 메서드를 작성하고 있다고 가정 해 보겠습니다 . 예를 들면 :
public Map<String, Integer> foo() {
return new HashMap<String, Integer>();
}
잠시 생각한 끝에이 맵이 생성되면 수정할 이유가 없다고 판단했습니다. 따라서 ImmutableMap 을 반환하고 싶습니다 .
public Map<String, Integer> foo() {
return ImmutableMap.of();
}
반환 유형을 일반 맵으로 두어야합니까, 아니면 ImmutableMap을 반환하도록 지정해야합니까?
한쪽에서, 이것이 바로 인터페이스가 만들어진 이유입니다. 구현 세부 정보를 숨 깁니다.
반면에 이렇게두면 다른 개발자들은이 객체가 불변이라는 사실을 놓칠 수 있습니다. 따라서 불변 객체라는 주요 목표를 달성하지 못할 것입니다. 변경할 수있는 개체의 수를 최소화하여 코드를 더 명확하게 만듭니다. 최악의 경우라도 잠시 후 누군가이 객체를 변경하려고 시도 할 수 있으며 이로 인해 런타임 오류가 발생합니다 (컴파일러가 이에 대해 경고하지 않음).
답변
-
공개용 API를 작성 중이고 불변성이 디자인의 중요한 측면 인 경우 메서드 이름이 반환 된 맵이 불변이라는 것을 명확하게 나타내거나 구체적인 유형을 반환하여 명시 적으로 만들 것입니다. 지도. 제 생각에는 javadoc에서 언급하는 것만으로는 충분하지 않습니다.
분명히 Guava 구현을 사용하고 있으므로 문서를 살펴 보았고 추상 클래스이므로 실제 구체적인 유형에 약간의 유연성을 제공합니다.
-
내부 도구 / 라이브러리를 작성하는 경우 일반
Map
. 사람들은 자신이 호출하는 코드의 내부에 대해 알거나 최소한 쉽게 액세스 할 수 있습니다.
내 결론은 명시적인 것이 좋다는 것입니다. 일을 우연에 맡기지 마십시오.
답변
ImmutableMap
반환 유형으로 가지고 있어야 합니다. Map
구현에 의해 지원되지 않는 방법을 포함 ImmutableMap
(예 put
) 및 표시된 @deprecated
하여 ImmutableMap
.
더 이상 사용되지 않는 메서드를 사용하면 컴파일러 경고가 발생하며 대부분의 IDE는 사람들이 더 이상 사용되지 않는 메서드를 사용하려고 할 때 경고합니다.
이 고급 경고는 무언가 잘못되었다는 첫 번째 힌트로 런타임 예외를 갖는 것보다 낫습니다.
답변
반면에 이렇게두면 다른 개발자들은이 객체가 불변이라는 사실을 놓칠 수 있습니다.
javadocs에서 언급해야합니다. 개발자들은 그것들을 읽습니다.
따라서 불변 객체라는 주요 목표를 달성하지 못할 것입니다. 변경할 수있는 개체의 수를 최소화하여 코드를 더 명확하게 만듭니다. 최악의 경우라도 잠시 후 누군가이 객체를 변경하려고 시도 할 수 있으며 이로 인해 런타임 오류가 발생합니다 (컴파일러가 이에 대해 경고하지 않음).
테스트되지 않은 코드를 게시하는 개발자는 없습니다. 그리고 그가 그것을 테스트 할 때, 그는 이유뿐만 아니라 그가 불변의 맵에 쓰려고 한 파일과 줄을 볼 때 예외가 발생합니다.
하지만 Map
포함 된 객체가 아닌 자체 만 변경할 수 없습니다.
답변
이렇게두면 다른 개발자가이 객체가 불변이라는 사실을 놓칠 수 있습니다.
사실이지만 다른 개발자는 자신의 코드를 테스트하고 적용되는지 확인해야합니다.
그럼에도 불구하고이 문제를 해결할 수있는 두 가지 옵션이 더 있습니다.
-
Javadoc 사용
@return a immutable map
-
설명이 포함 된 메서드 이름을 선택했습니다.
public Map<String, Integer> getImmutableMap() public Map<String, Integer> getUnmodifiableEntries()
구체적인 사용 사례의 경우 메서드 이름을 더 잘 지정할 수도 있습니다. 예
public Map<String, Integer> getUnmodifiableCountByWords()
너는 어떤 다른 일을 할 수 있니?!
당신은 반환 할 수 있습니다
-
부
private Map<String, Integer> myMap; public Map<String, Integer> foo() { return new HashMap<String, Integer>(myMap); }
이 방법은 많은 클라이언트가 맵을 수정할 것으로 예상하고 맵에 몇 개의 항목 만 포함되어있는 한 사용해야합니다.
-
CopyOnWriteMap
COW 컬렉션은 일반적으로
동시성 을 처리해야 할 때 사용됩니다 . 그러나 CopyOnWriteMap은 변경 작업 (예 : 추가, 제거)에서 내부 데이터 구조의 복사본을 생성하기 때문에이 개념은 상황에서도 도움이 될 것입니다.이 경우 변경 작업을 제외하고 모든 메서드 호출을 기본 맵에 위임하는 맵 주위에 얇은 래퍼가 필요합니다. 변경 작업이 호출되면 기본 맵의 복사본이 생성되고 모든 추가 호출이이 복사본에 위임됩니다.
일부 클라이언트가 맵을 수정할 것으로 예상되는 경우이 접근 방식을 사용해야합니다.
슬프게도 Java에는 그러한
CopyOnWriteMap
. 그러나 제 3자를 찾거나 직접 구현할 수 있습니다.
마지막으로지도의 요소는 여전히 변경 가능할 수 있다는 점을 기억해야합니다.
답변
ImmutableMap을 확실히 반환합니다. 이유는 다음과 같습니다.
- 메서드 서명 (반환 유형 포함)은 자체 문서화되어야합니다. 의견은 고객 서비스와 같습니다. 고객이 의견에 의존해야하는 경우 주요 제품에 결함이있는 것입니다.
- 어떤 것이 인터페이스인지 클래스인지는 확장하거나 구현할 때만 관련이 있습니다. 인스턴스 (객체)가 주어지면 클라이언트 코드의 99 %는 무언가가 인터페이스인지 클래스인지 알거나 신경 쓰지 않습니다. 처음에는 ImmutableMap이 인터페이스라고 가정했습니다. 링크를 클릭 한 후에야 그것이 수업이라는 것을 깨달았습니다.
답변
수업 자체에 따라 다릅니다. 구아바 ImmutableMap
는 변경 가능한 클래스에 대한 변경 불가능한보기를 의도하지 않습니다. 클래스가 불변하고 기본적으로 인 구조가 있다면 ImmutableMap
반환 유형을 만드십시오 ImmutableMap
. 그러나 클래스가 변경 가능하면하지 마십시오. 이 경우 :
public ImmutableMap<String, Integer> foo() {
return ImmutableMap.copyOf(internalMap);
}
Guava는 매번지도를 복사합니다. 느립니다. 그러나 internalMap
이미 이면 ImmutableMap
완전히 괜찮습니다.
클래스를 returning으로 제한하지 않으면 ImmutableMap
대신 다음 Collections.unmodifiableMap
과 같이 반환 할 수 있습니다 .
public Map<String, Integer> foo() {
return Collections.unmodifiableMap(internalMap);
}
이것은 지도에 대한 변경 불가능한 보기 입니다. 경우 internalMap
변경, 그래서의 복사 캐시합니다 Collections.unmodifiableMap(internalMap)
. 그러나 나는 여전히 게터에게 그것을 선호합니다.
답변
정확한 질문에 대한 답은 아니지만지도를 반환해야하는지 여부를 고려해 볼 가치가 있습니다. 맵이 변경 불가능한 경우 제공되는 기본 메소드는 get (key)를 기반으로합니다.
public Integer fooOf(String key) {
return map.get(key);
}
이것은 API를 훨씬 더 단단하게 만듭니다. 맵이 실제로 필요한 경우 항목 스트림을 제공하여 API 클라이언트에 맡길 수 있습니다.
public Stream<Map.Entry<String, Integer>> foos() {
map.entrySet().stream()
}
그런 다음 클라이언트는 필요에 따라 자체 불변 또는 변경 가능한 맵을 만들거나 항목을 자체 맵에 추가 할 수 있습니다. 클라이언트가 값이 존재하는지 알아야하는 경우 대신 선택 사항이 리턴 될 수 있습니다.
public Optional<Integer> fooOf(String key) {
return Optional.ofNullable(map.get(key));
}