JavaのSuppressWarnings(「未チェック」)とは何ですか?


443

コードを調べていると、アノテーションを指定する多くのメソッドが見つかります。

@SuppressWarnings("unchecked")

これは何を意味するのでしょうか?

回答:


420

時々 、Javaのジェネリックはちょうどあなたがあなたがやりたいことはできません、あなたは効果的に何をやっている、本当にことをコンパイラに指示する必要があります実行時に法的なことを。

私は通常、ジェネリックインターフェイスをモックするときにこれが面倒だと感じますが、他の例もあります。通常、警告を抑制するのではなく回避する方法を試してみる価値があります(Java Generics FAQがここで役立ちます)が、たとえそれ可能であっても、警告が抑制されないようにコードを曲げてしまう場合があります。その場合は必ず説明コメントを追加してください!

同じジェネリックFAQには、このトピックに関するいくつかのセクションがあり、「 "チェックされていない"警告とは」から始まります。-読む価値があります。


10
場合によっては、YourClazz.class.cast()を使用して回避できます。単一のジェネリックエレメントコンテナで機能しますが、コレクションでは機能しません。
akarnokd

または、できればワイルドカードジェネリックを使用する(YourClazz<?>)ことをお勧めします。Javaはそのようなキャストが安全であるため、警告を出しません。ただし、これは常に機能するとは限りません(詳細については、ジェネリックFAQを参照してください)。
Konrad Borowski、

48

これは、キャストなどのチェックされていない一般的な操作(例外ではない)に関するコンパイル警告を抑制するための注釈です。それは本質的に、プログラマーが特定のコードをコンパイルするときにすでに知っているこれらについて通知されたくないことを意味します。

この特定のアノテーションについて詳しくは、こちらをご覧ください。

SuppressWarnings

さらに、オラクルはここで注釈の使用に関するいくつかのチュートリアルドキュメントを提供します:

注釈

彼らが言うように、

「ジェネリックが登場する前に作成されたレガシーコード(「ジェネリック」というタイトルのレッスンで説明されている)とやり取りすると、「チェックされていない」警告が発生する可能性があります。」


19

また、現在のJava型システムのバージョンでは、ケースに十分対応できない可能性もあります。これを修正するためのいくつかのJSR命題 /ハックがありました:タイプトークン、スーパータイプトークン、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を使用する必要がある状況の良い例です。
ジミー

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は、プログラムの実行中に一般的な型が何であるかを認識していないため、これはコンパイルおよび実行されます。JavaVirtual Machineの場合、これはList型へのキャストです(検証できるのはこれだけなので、それだけを検証します)。

しかし、ここでこの行を追加します。

Integer hello = actualList.get(0);

またClassCastException、Javaコンパイラが暗黙のキャストを挿入したため、JVMは予期しないをスローします。

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

unchecked警告は、キャストがどこか他の例外をスローするプログラムを引き起こす可能性があること、プログラマに伝えます。警告を抑制し@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

1つのトリックは、一般的な基本インターフェースを拡張するインターフェースを作成することです...

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は新しいですか?サービス終了期間のほとんどを完了しています。
トムホーティン-タックライン2009

私はJDK 5がかなり古くなっていることを知っています。つまり、以前はJDK 4で提供されていなかった新しい機能がJavaに導入されたという意味で新しいものです。 JDK 6を採用するために、理由を説明することはできません。
BakerTheHacker 2009

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 s(またはそのスーパータイプ)を含むコレクションである場合、安全です。しかし、生のタイプ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つの組み込みアノテーションの1つであり、Java 1.5で@Overrideおよび@Deprecatedとともに追加されます。

@SuppressWarningsは、注釈付き要素とその要素内のすべてのプログラム要素で指定されたコンパイラ警告を無視または抑制するようにコンパイラーに指示します。たとえば、特定の警告を抑制するようにクラスに注釈が付けられている場合、そのクラス内のメソッドで生成された警告も分離されます。

@SuppressWarnings( "unchecked")と@SuppressWarnings( "serial")は、@ SuppressWarningsアノテーションの最も人気のある2つの例です。Formerは、未チェックのキャストによって生成される警告を抑制するために使用されますが、後者の警告は、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.