Skip to content

Latest commit

 

History

History
80 lines (69 loc) · 4.63 KB

비검사_경고를_제거하라.md

File metadata and controls

80 lines (69 loc) · 4.63 KB

아이템 27: 비검사 경고를 제거하라

  • 비검사 경고는 중요하니 무시하지 말자.
  • 모든 비검사 경고는 런타임에 ClassCastException을 일으킬 수 있는 잠재적 가능성을 뜻하니 최선을 다해 제거해야 한다.
  • 다행히도 대부분의 비검사 경고는 쉽게 제거할 수 있다.
  • 하지만 제거하기 어려운 경고도 있는데 이는 어떻게 처리하는지 이번 장에서 함께 살펴보자

쉬운 비검사 경고 제거 예시

  • 먼저 쉬운 비검사 경고를 제거하는 과정을 예시로 살펴보자.
Set<Integer> numbers = new HashSet();
  • 위의 코드는 컴파일러가 경고하는 코드

  • 컴파일러는 무엇이 잘못됐는지 친절하게 설명해준다.

  • image
  • 위 코드 Set<Integer> numbers = new HashSet(); 에서 경고가 발생하는 이유는 HashSet 생성자를 사용할 때 제네릭 타입을 명시하지 않았기 때문

  • 제네릭 타입을 명시하지 않으면 'raw type'을 사용하는 것이 되고, 이는 제네릭이 도입된 Java 5 이후로 권장되지 않는 방식이기 때문에 경고했던 것.

  • 따라서 코드를 다음과 같이 수정하면 경고가 사라진다.

Set<Integer> numbers = new HashSet<Integer>();
  • Java 7 이상을 사용하는 경우, 다이아몬드 연산자(<>)를 사용하여 타입 파라미터를 생략할 수도 있음
  • 이렇게 하면 컴파일러가 문맥을 바탕으로 적절한 타입 인수를 추론할 수 있다
Set<Integer> numbers = new HashSet<>();
  • 이제 경고는 제거되었다.
  • 경고가 제거된 코드는 ClassCastException이 방지되는 장점을 가진다.

경고를 제거할 수 없다면?

  • 다음과 같은 경우도 있을 수 있겠다.

경고를 제거할 수는 없지만 타입 안전하다고 확신할 수 있다.

  • 이럴 경우는 안전함을 확신할 수 있는 경우이기에 경고를 숨기는 것이 해결이 될 수 있다.
  • 단 타입 안전함을 검증하지 않은 채 경고를 숨기면 스스로에게 잘못된 보안 인식을 심어주는 꼴이다.
  • 그러한 코드는 경고 없이 컴파일되겠지만, 런타임에는 여전히 ClassCastException을 던질 수 있기 때문이다.
  • 또 반대로, 안전하다고 검증된 비검사 경고를 그대로 두면, 진짜 문제를 알리는 새로운 경고가 나와도 눈치채지 못할 수 있다.
  • 제거하지 않은 수많은 거짓 경고 속에 중요한 경고가 파묻힐 수 있기 때문이다.
  • 경고는 필요한 맥락에 적절히 등장하도록 해야 한다는 얘기

경고를 숨기는 방법 @SuppressWarnings

  • @SuppressWarnings애너테이션을 통해서 경고를 숨길 수 있다.
  • 이 애너테이션은 개별 지역변수 선언부터 클래스 전체까지 어떤 선언에도 달 수 있다.
  • 하지만 @SuppressWarnings애너테이션은 항상 가능한 좁은 범위에 적용하자.
  • 클래스 전체 등, 더 넓게 적용되면 자칫 심각한 경고를 놓칠수도 있기 때문이다.
  • 그리고 @SuppressWarnings애너테이션은 지역 변수든 클래스든 선언에만 달 수 있기 때문에 return문 등에 애너테이션을 달고 싶은 경우 다른 방법을 사용하자
  • 가장 쉬운 방법은 메서드의 선언 부로 애너테이션을 옮기는 것이겠지만 가능한 좁은 범위에 적용하기 위해서 지역변수를 추출할 수 있다.

리턴 문에 애너테이션을 달 수 없어 지역변수로 추출한 예시 코드

public <T> T[] toArray(T[] a) {
	if(a.length < size) {
		@SuppressWarnings("unchecked") T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass());
		return result;
	}
		...
		...
}
  • 위의 코드는 깔끔하게 컴파일되고 비검사 경고를 숨기는 범위도 최소로 좁혔다.
  • 다만 또하나 명심하자
  • @SuppressWarnings 애너테이션을 사용할 때면 그 경고를 무시해도 안전한 이유를 항상 주석으로 남기자.
  • 다른 사람이 코드를 이해하는 데 도움이 되며, 더 중요하게는, 다른 사람이 코드를 잘못 수정하여 타입 안전성을 잃는 상황을 줄여주기 때문이다.

주석이 추가된 ver

public <T> T[] toArray(T[] a) {
	if(a.length < size) {
		// 생성한 배열과 매개변수로 받은 배열의 타입이 모두 T[]로 같으므로 올바른 형변환
		@SuppressWarnings("unchecked") T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass());
		return result;
	}
		...
		...
}