Java에서 SuppressWarnings ( "체크되지 않은") 란 무엇입니까?


443

때로는 코드를 살펴볼 때 많은 메소드가 주석을 지정하는 것을 볼 수 있습니다.

@SuppressWarnings("unchecked")

이것은 무엇을 의미 하는가?

답변:


420

때로는 자바 제네릭 그냥 당신이 당신이 원하는 일을하지 않으며, 당신은 효과적으로 당신이 정말하고있는 것이 있음을 컴파일러에게 필요 합니다 실행시 법적 될 수 있습니다.

나는 일반적인 인터페이스를 조롱 할 때 일반적 으로이 고통을 발견하지만 다른 예제도 있습니다. 그것은 경고를 피하는 것이 아니라 그것을 억제하는 방법을 해결하려고 노력 일반적으로 가치가합니다 ( 자바 제네릭 FAQ는 여기에 있습니다)하지만 때로는 심지어 경우 입니다 수, 그렇게 많은 경고를 억제하는 깔끔한 것을 모양에서 코드를 굴절. 이 경우 항상 설명 주석을 추가하십시오!

동일한 "제네릭 FAQ "에는 ""확인되지 않은 "경고 란 무엇입니까?"로 시작하는이 주제에 대한 여러 섹션이 있습니다. -읽을 가치가 있습니다.


10
경우에 따라 YourClazz.class.cast ()를 사용하여 피할 수 있습니다. 단일 일반 요소 컨테이너에는 작동하지만 컬렉션에는 작동하지 않습니다.
akarnokd

또는 바람직하게는 와일드 카드 제네릭을 사용하십시오. (YourClazz<?>)Java는 이러한 캐스트가 안전하므로 경고하지 않습니다. 그러나 항상 작동하지는 않습니다 (자세한 내용은 제네릭 FAQ 참조).
Konrad Borowski

48

캐스트와 같은 검사되지 않은 일반 작업 (예외 아님)에 대한 컴파일 경고를 억제하기위한 주석입니다. 그것은 본질적으로 프로그래머가 특정 코드를 컴파일 할 때 이미 알고있는 것에 대해 알리고 싶지 않다는 것을 암시합니다.

이 특정 주석에 대한 자세한 내용은 여기를 참조하십시오.

경고

또한 오라클은 주석 사용법에 대한 튜토리얼 문서를 제공합니다.

주석

그들이 넣을 때

"제네릭이 등장하기 전에 작성된 레거시 코드와 인터페이스 할 때 '확인되지 않은'경고가 발생할 수 있습니다 (제네릭 제목의 단원에서 설명)."


19

또한 현재 Java 유형 시스템 버전이 귀하의 경우에 충분하지 않을 수도 있습니다. 이 문제를 해결하기 위해 JSR 제안 / 해킹 이 몇 가지있었습니다 : Type tokens, Super Type Tokens , Class.cast ().

이 억압이 실제로 필요한 경우 가능한 한 좁히십시오 (예 : 클래스 자체 또는 긴 메소드에 넣지 마십시오). 예를 들면 :

public List<String> getALegacyListReversed() {
   @SuppressWarnings("unchecked") List<String> list =
       (List<String>)legacyLibrary.getStringList();

   Collections.reverse(list);
   return list;
}


8

간단히 말해 : 컴파일러가 형식 안전성을 보장 할 수 없음을 나타내는 경고입니다.

JPA 서비스 방법 예 :

@SuppressWarnings("unchecked")
public List<User> findAllUsers(){
    Query query = entitymanager.createQuery("SELECT u FROM User u");
    return (List<User>)query.getResultList();
}

@SuppressWarnings ( "unchecked")에 주석을 달지 않으면 ResultList를 반환하려는 행에 문제가 있습니다.

바로 가기 형식 안전의 의미 : 프로그램은 오류 및 경고없이 컴파일되고 런타임에 예기치 않은 ClassCastException을 발생시키지 않으면 형식 안전으로 간주됩니다.

나는 http://www.angelikalanger.com/GenericsFAQ/FAQSections/Fundamentals.html에서 빌드합니다 .


2
SuppressWarnings를 사용해야하는 상황에 대한 좋은 예입니다.
Jimmy

8

Java에서 제네릭은 삭제 유형을 통해 구현됩니다. 예를 들어, 다음 코드입니다.

List<String> hello = List.of("a", "b");
String example = hello.get(0);

다음과 같이 컴파일됩니다.

List hello = List.of("a", "b");
String example = (String) hello.get(0);

그리고 List.of으로 정의된다.

static <E> List<E> of(E e1, E e2);

유형 삭제 후 어느 것이됩니다.

static List of(Object e1, Object e2);

컴파일러는 런타임에 제네릭 형식이 무엇인지 알지 못하므로 이와 같이 작성하면됩니다.

Object list = List.of("a", "b");
List<Integer> actualList = (List<Integer>) list;

Java Virtual Machine은 프로그램을 실행하는 동안 일반 유형이 무엇인지 알지 못하므로 Java Virtual Machine과 마찬가지로 컴파일 및 실행됩니다. List .

그러나 이제이 줄을 추가하십시오.

Integer hello = actualList.get(0);

ClassCastExceptionJava 컴파일러가 암시 적 캐스트를 삽입했기 때문에 JVM은 예기치 않은을 발생 시킵니다.

java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer

unchecked경고는 캐스트가 다른 곳에서 예외를 throw하는 프로그램이 발생할 수 있음을 프로그래머를 알려줍니다. 경고를 표시하지 @SuppressWarnings("unchecked")않으면 컴파일러는 프로그래머에게 코드가 안전하다고 생각하고 예기치 않은 예외가 발생하지 않는다고 알립니다.

왜 그렇게 하시겠습니까? Java 유형 시스템은 가능한 모든 유형 사용 패턴을 표현하기에 충분하지 않습니다. 때로는 캐스팅이 안전하다는 것을 알 수 있지만 Java는 그렇게 말하는 방법을 제공하지 않습니다. 이와 같은 경고를 숨기고 @SupressWarnings("unchecked")프로그래머가 실제 경고에 집중할 수 있습니다. 예를 들어Optional.empty() 값을 저장하지 않는 빈 옵션의 할당을 피하기 위해 싱글 톤을 반환합니다.

private static final Optional<?> EMPTY = new Optional<>();
public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}

빈 캐스트 옵션에 저장된 값을 검색 할 수 없으므로 예기치 않은 클래스 캐스트 예외의 위험이 없으므로이 캐스트는 안전합니다.


5

컴파일러 경고를 억제하고 작성한 코드가 그에 따라 합법적임을 제네릭에게 알릴 수 있습니다.

예:

@SuppressWarnings("unchecked")
public List<ReservationMealPlan> retreiveMealPlan() {
     List<ReservationMealPlan> list=new ArrayList<ReservationMealPlan>();
    TestMenuService testMenuService=new TestMenuService(em, this.selectedInstance);
    list = testMenuService.getMeal(reservationMealPlan);
    return list;
 }

5

한 가지 요령은 일반적인 기본 인터페이스를 확장하는 인터페이스를 만드는 것입니다.

public interface LoadFutures extends Map<UUID, Future<LoadResult>> {}

그런 다음 캐스트하기 전에 instanceof로 확인할 수 있습니다 ...

Object obj = context.getAttribute(FUTURES);
if (!(obj instanceof LoadFutures)) {
    String format = "Servlet context attribute \"%s\" is not of type "
            + "LoadFutures. Its type is %s.";
    String msg = String.format(format, FUTURES, obj.getClass());
    throw new RuntimeException(msg);
}
return (LoadFutures) obj;

4

내가 아는 한 지금은 제네릭에 대한 경고를 억제하는 것과 관련이 있습니다. 제네릭은 JDK 5 이전의 JDK 버전에서 지원되지 않는 새로운 프로그래밍 구조이므로 이전 구문과 새 구문을 혼합하면 예기치 않은 결과가 발생할 수 있습니다.

컴파일러는 프로그래머에게 이에 대해 경고하지만 프로그래머가 이미 알고있는 경우 SuppressWarnings를 사용하여 두려운 경고를 끌 수 있습니다.


1
JDK5가 새로운가요? 서비스 종료 수명 대부분을 완료했습니다.
Tom Hawtin-tackline 10

나는 JDK 5가 다소 구식이라는 것을 알고 있습니다. 이는 JDK 4에서 이전에 제공되지 않았던 Java에 새로운 기능을 도입했다는 의미에서 새로운 것입니다. 또한 JDK 5를 떠나기 전에 JDK 7을 기다리는 사람들도 있습니다. JDK 6을 수용하기 위해 이유를 추론 할 수 없습니다!
BakerTheHacker

2

컴파일러가 형식 안전성을 보장 할 수 없음을 나타내는 경고입니다. "확인되지 않은"경고라는 용어는 오해의 소지가 있습니다. 경고가 확인되지 않았다는 의미는 아닙니다. "체크되지 않은"이라는 용어는 컴파일러와 런타임 시스템에 형식 안전성을 보장하는 데 필요한 모든 형식 검사를 수행하기에 충분한 형식 정보가 없다는 사실을 나타냅니다. 이런 의미에서 특정 작업은 "확인되지 않습니다".

"확인되지 않은"경고의 가장 일반적인 원인은 원시 유형을 사용하는 것입니다. 원시 유형이 모든 필요한 유형 확인을 수행하기에 충분한 유형 정보를 제공하지 않기 때문에 원시 유형 변수를 통해 오브젝트에 액세스 할 때 "확인되지 않은"경고가 발행됩니다.

예 (원시 유형과 함께 확인되지 않은 경고의 경우) :

TreeSet set = new TreeSet(); 
set.add("abc");        // unchecked warning 
set.remove("abc");
warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.TreeSet 
               set.add("abc");  
                      ^

add 메소드가 호출되면 컴파일러는 컬렉션에 String 객체를 추가하는 것이 안전한지 알 수 없습니다. TreeSet가 String (또는 그 슈퍼 타입)을 포함한 컬렉션 인 경우는 안전합니다. 그러나 원시 유형 TreeSet에서 제공하는 유형 정보에서 컴파일러는 말할 수 없습니다. 따라서 호출이 안전하지 않을 수 있으며 "확인되지 않은"경고가 발생합니다.

컴파일러가 대상 유형이 매개 변수화 된 유형이거나 유형 매개 변수 인 캐스트를 발견하면 "확인되지 않은"경고도보고됩니다.

예 (매개 변수가있는 유형 또는 유형 변수로의 캐스트와 함께 확인되지 않은 경고의 경우) :

  class Wrapper<T> { 
  private T wrapped ; 
  public Wrapper (T arg) {wrapped = arg;} 
  ... 
  public Wrapper <T> clone() { 
    Wrapper<T> clon = null; 
     try {  
       clon = (Wrapper<T>) super.clone(); // unchecked warning 
     } catch (CloneNotSupportedException e) {  
       throw new InternalError();  
     } 
     try {  
       Class<?> clzz = this.wrapped.getClass(); 
       Method   meth = clzz.getMethod("clone", new Class[0]); 
       Object   dupl = meth.invoke(this.wrapped, new Object[0]); 
       clon.wrapped = (T) dupl; // unchecked warning 
     } catch (Exception e) {} 
     return clon; 
  } 
} 
warning: [unchecked] unchecked cast 
found   : java.lang.Object 
required: Wrapper <T> 
                  clon = ( Wrapper <T>)super.clone();  
                                                ^ 
warning: [unchecked] unchecked cast 
found   : java.lang.Object 
required: T 
                  clon. wrapped = (T)dupl;

런타임시 동적 유형 검사가 관련된 경우 대상 유형이 (콘크리트 또는 바인드 와일드 카드) 매개 변수화 된 유형이거나 유형 매개 변수 인 캐스트는 안전하지 않습니다. 런타임에는 소스 코드에 표시되는 정확한 정적 유형이 아닌 유형 지우기 만 사용할 수 있습니다. 결과적으로, 캐스트의 런타임 부분은 정확한 정적 유형이 아닌 유형 삭제를 기반으로 수행됩니다.

이 예제에서 Wrapper로 캐스트는 super.clone에서 반환 된 객체가 특정 유형의 멤버가있는 래퍼인지 아닌지 Wrapper인지 확인합니다. 마찬가지로, 유형 매개 변수 T에 대한 캐스트는 런타임시 유형 Object에 캐스트되고, 아마도 완전히 최적화됩니다. 유형 삭제로 인해 런타임 시스템은 런타임에 더 유용한 유형 검사를 수행 할 수 없습니다.

어떤 방식으로, 소스 코드는 각 대상 유형에 대한 캐스트가 수행되는 것을 제안하기 때문에 오해의 소지가 있습니다. 실제로 캐스트의 동적 부분은 대상 유형의 유형 삭제에 대해서만 검사합니다. 캐스트의 정적 및 동적 측면 간의 불일치에 대한 프로그래머의주의를 끌기 위해 "확인되지 않은"경고가 발행됩니다.

를 참조하십시오 : 에 "선택 해제"경고가 무엇입니까?


2

@SuppressWarnings 주석은 JDK에서 사용할 수있는 3 개의 내장 주석 중 하나이며 Java 1.5에서 @Override 및 @Deprecated와 함께 추가되었습니다.

@SuppressWarnings는 어노테이션이있는 요소 및 해당 요소 내의 모든 프로그램 요소에서 지정된 컴파일러 경고를 무시하거나 억제하도록 컴파일러에 지시합니다. 예를 들어, 특정 경고를 표시하지 않도록 클래스에 주석을 달면 해당 클래스 내부의 메소드에서 생성 된 경고도 분리됩니다.

@SuppressWarnings 주석의 가장 보편적 인 예인 @SuppressWarnings ( "unchecked") 및 @SuppressWarnings ( "serial")를 보셨을 것입니다. 이전은 확인되지 않은 캐스팅으로 인해 생성 된 경고를 억제하는 데 사용되는 반면, 나중에 경고는 Serializable 클래스에 SerialVersionUID를 추가하는 데 사용됩니다.

더 읽기 : https://javarevisited.blogspot.com/2015/09/what-is-suppresswarnings-annotation-in-java-unchecked-raw-serial.html#ixzz5rqQaOLUa

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.