S-JIS[2007-06-11/2017-09-23] 変更履歴

警告を抑止する方法

Eclipse3.1以降でよく警告が出るようになった。
javacコマンドで直接コンパイルするとデフォルトではその手の警告は出ないが、javacのオプションで-Xlintを付けてコンパイルすると これらの警告が出るようになる。


コンパイルオプションによる抑止

javacのオプションの-Xlintによって警告を抑止できる。(JDK1.5以降)

全ての警告を出す例:

> javac -Xlint Test.java
> javac -Xlint:all Test.java

全く警告を出さない例:

> javac Test.java
> javac -Xlint:none Test.java

シリアライズの警告だけ出す例:

> javac -Xlint:serial Test.java

シリアライズの警告を抑止する例:

> javac -Xlint:-serial Test.java

シリアライズの警告だけ抑止し、他の警告は全て出す例:

> javac -Xlint:all,-serial Test.java

アノテーションによる抑止

JDK1.5から導入されたアノテーションに、@SuppressWarningsというものがある。
引数に抑止したい警告を示す文字列を指定することによって、コンパイラーの該当の警告を出さないようにすることが出来る。

@SuppressWarnings("警告名")
@SuppressWarnings({ "警告名1", "警告名2", … })

警告名は単なる文字列なので、定数(変数)で指定することも出来る。[2010-01-09]

static final String 定数名 = "警告名";
@SuppressWarnings(定数名)

※ローカル変数やstatic finalの付いていないフィールドではダメ


@SuppressWarningsにどういう値が指定できるのかについては、コンパイラーの実装(コンパイラーの種類)によって異なる
Java言語仕様第3版9.6.1.5章に、コンパイラー依存だがコンパイラーベンダー間での協力を推奨していると書いてある)
Eclipseの警告

Sunのjavacの場合、 「javac -X」でjavacのオプションの一覧が見られるが、-Xlintの項で出てくるものをたぶん指定できる。
コンパイルで警告対象に引っ掛かると、「〜:警告:[unchecked] 〜」のように、警告の文字列が表示される。[2008-05-23]
これが-Xlintで指定すべき文字列であり、@SuppressWarningsに指定する文字列であると思う
→Sunのjavacの非標準オプション(-Xlint)

Sunのjavacの警告
JDK メッセージ 警告の概要 更新日
all 1.5   全ての警告を抑制する。
@SuppressWarnings("all")
2008-05-23
cast 1.6 {1} への冗長なキャストです 不要なキャストを行っている。
@SuppressWarnings("cast")
String s = (String)"abc";
2008-08-24
dep-ann 1.5 推奨されない項目は @Deprecated で注釈が付けられていません。 Javadocの@deprecatedタグが付けられているが、@Deprecatedアノテーションが付けられていない。
非推奨はJDK1.5以降ではアノテーションを使う
(@SuppressWarningsをJavadocタグの前に付ければ警告は消えるけれども、素直に@Deprecatedアノテーションを付けるべきでしょう)
@SuppressWarnings("dep-ann")
/** @deprecated */
public void zzz(){ }
/** @deprecated */
@Deprecated
public void zzz(){ }
2008-10-25
deprecation 1.5 {1} は推奨されません 非推奨(deprecated)になっているクラス・メソッドを使用している。
@SuppressWarnings("deprecation")
Date d = new Date("2008/05/23");
2008-05-23
divzero 1.6 ゼロで除算 0で除算している。
@SuppressWarnings("divzero")
int n = 1 / 0;
2008-05-23
empty 1.6 if 以降が空の文です if文において、else部が無く、条件を満たした場合の処理が空文の場合(つまり「if(条件);」)の警告。
空ブロックの場合(「if(条件){}」)や「if(条件);else;」等は警告にならない。
for・while・do等のループも対象外。
@SuppressWarnings("empty")
void if1() {
  if(true);
}
2008-09-23
fallthrough 1.5 case に fall-through する可能性があります switchにおいて、何らかの処理を記述した後にbreakが無く、次のcase(やdefault)に処理が移る場合。
@SuppressWarnings("fallthrough")
void test(int n) {
  switch(n){
    case 1:
      System.out.println("abc");
    default:
      break;
  }
}
2008-05-23
finally 1.5 finally 節が正常に完了できません finally節の中でreturnまたはthrowしている。
(普通はtry及びcatch節の中からreturn/throwするものであり、finallyでそれらを使うとfinallyで返した値が有効になるので、try/catchで返した値がもみ消されてしまう)
@SuppressWarnings("finally")
int test() {
  try {
  } finally {
    return 1;
  }
}
2007-06-12
overrides 1.6 {1}の{2}は {3}の{4}を上書きします。; オーバーライドしているメソッドには {5} がありません。 定義したメソッド({1}クラスの{2})が、シグニチャーの異なる親クラス{3}のメソッド{4}のオーバーライドになってしまう、という警告。
class Super {
  void method(String[] s){}
}
class Sub extends Super {
  @SuppressWarnings("overrides")
  void method(String... s){}
}
2008-08-24
path 1.5   コンパイルオプションのclasspathやsourcepathでパスが存在しない場合の警告らしい   2008-05-23
serial 1.5 直列化可能なクラス {1} には、serialVersionUID が定義されていません Serializableインターフェースを実装した場合はserialVersionUIDという定数を定義すべきなのに、定義されていない。
@SuppressWarnings("serial")
class Test implements Serializable {
}
2007-06-11
unchecked 1.5   未チェック変換(unchecked conversion)に対する警告。   2008-08-30
raw 型 {1} のメンバとしての {2} への無検査呼び出しです 総称型(ジェネリクス)で型引数を指定せずにメソッドを使っている。
raw型
@SuppressWarnings("unchecked")
void test(List list) {
  list.add("abc");
}
2008-05-23
無検査キャストです 型引数を使ったキャストは、実行時には型チェックされない。
つまり右の例だと、「Class<Date> c = strClass();」ではコンパイルエラーにも警告にもならないし実行も通る(実際に返ってきているのはClass<String>だが、チェックされない)。
しかし「Data d = c.newInstance();」でキャストの例外が発生する。
コレクションの動的型保証
@SuppressWarnings("unchecked")
static <T> Class<T> strClass() {
  return (Class<T>)"".getClass();
}
2008-08-21

@SuppressWarningsを付けたまま警告の原因を解消しても、@SuppressWarningsは何も反応しない。
(つまり警告が出なくなったので@SuppressWarningsは不要になったのだが、それを知る術が無い(それに対して警告を出してくれたりはしない(苦笑)))

Eclipseでは不要な@SuppressWarningsは警告になることもあるけど。


@SafeVarargs

@java.lang.SafeVarargsは、JDK1.7で導入されたアノテーション。[2014-08-09]
安全でない可変長引数(var args)に対する警告を抑止する。

例えば以下のようなコーディングを行うと、警告が出る。

	public void varArgsMethod(List<String>... args) {	// Type safety: Potential heap pollution via varargs parameter args
		System.out.println(args);
	}

“ジェネリクス付きのクラスの可変長引数”の場合、実体としては“ジェネリクス付きクラスの配列”になるが、配列は共変なので、安全でない操作が(やろうと思えば)出来てしまう。
ので、こういった警告が出ているらしい。


安全でない操作というのは、例えば以下のようなコード。

	public void varArgsMethod(List<String>... args) {
		Object[] objs = args;
		objs[0] = Arrays.asList(123); // List<Integer>

		List<String> list = args[0];
		String s = list.get(0); // ClassCastException
	}

配列は共変なので、argsをObject配列の変数に代入できてしまう。
すると、本来の型と異なる型の値を代入できてしまう。
すると、それを使おうとした箇所でClassCastExceptionが発生してしまう。

まぁ、可変長引数の変数の中身を書き換えるコーディングなんて、まずしないだろうけど(苦笑)


そういう訳で、上記のような警告が出ている場合、@SuppressWarnings("unchecked")または@SafeVarargsで警告を抑止することが出来る。

	@SafeVarargs
//	@SuppressWarnings("unchecked")
	public final void varArgsMethod(List<String>... args) {
		System.out.println(args);
	}

@SafeVarargsを付ける場合、そのメソッドはfinalもしくはstaticである必要がある。
(オーバーライドされた先まで影響を及ぼせないからだろうか?)
この条件を満たしていない場合、「@SafeVarargs annotation cannot be applied to non-final instance method varArgsMethod」というエラーになる。
(オーバーライドの影響ならprivateメソッドは問題ないはずだが、privateメソッドでもfinalが付いていないとエラーになる)
※Java9で、privateメソッドにも@SafeVarargsを付けられるようになった。[2017-09-23]

Eclipseの場合、上記の警告に対するクイックフィックスで@SafeVarargsや@SuppressWarningsを付けることが出来るが、finalもしくはstaticメソッドでない場合は、補完候補に@SafeVarargsは出てこない。


@SuppressWarnings("unchecked")@SafeVarargsの違いは、@SafeVarargsだとそのメソッドの呼び出し側の警告まで抑止されること。

上記の警告が出ているメソッドを呼び出すコーディングをすると、呼び出し側でも以下のような警告が出る。

	public void caller() {
		List<String> list = new ArrayList<>();
		varArgsMethod(list);	// Type safety: A generic array of List<String> is created for a varargs parameter
	}

呼び出すメソッドに@SafeVarargsが付いていると、この警告も抑止される。
(呼び出すメソッドが@SuppressWarningsを付けているだけだと、こちらの警告は抑止されない)


Java目次へ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま