Subscribed unsubscribe Subscribe Subscribe

Kengo's blog

Technical articles about original projects, JVM, Static Analysis and JavaScript.

Goodbye, checkNotNull

 Precondition checking like null-checking is very important element for program, but sometimes it becomes boring because it's a defensive technique and far apart from our purpose -- hacking.
 nullチェックのような前提条件確認はプログラムにおいて非常に大切な要素ではありますが、防御的であり目的を実現するためのコードではないため、時につまらない作業になりがちです。

public MyClass(String name) {
	if (name == null) {
		throw new IllegalArgumentException();
	}
	this.name = name;
}

 Yes, I know the Guava library makes it easy. Preconditions class is my favorite, and we can use it to simplify checkings. For example, we can code precondition checking and assignment etc. in same line.
 ひとつの解決として、Guavaライブラリを使うのはたしかに有効です。Preconditionsクラスを使うことで前提条件チェックと代入を同じ行に書くなど、前提条件確認をシンプルに記述することができるようになります。

public MyClass(String name) {
	this.name = checkNotNull(name);
}

 But I still have some problems. At 1st, users of this class have to read this implementation to know 'name should be non-null value'. Do you want to write '@param name should not be null' or '@throw NullPointerException if name == null' in your Javadoc? I don't! I've already written it in the code.
 しかしまだいくつか解決したい問題が残っています。1つめは、クラスの実装を読んでもらわないとnameがnullであってはならないということが伝わらないことです。Javadoc'@param name nullは渡さないで!'とか'@throw NullPointerException nameがnullの場合に投げる'とか書きたくはありません。コードの中の情報と重複しています。

 At 2nd, we cannot select its exception. I know that throwing NullPointerException at null checking is traditional way for Java, but the IllegalArgumentException is more meaningful option*1 I think. We can avoid this problem to use checkArgument(name != null) instead of for a while.
 2つめは、NullPointerException以外の例外を投げられないということです。ヌルチェックに引っかかった場合はNPEを投げるのが伝統的とは言え、より例外として意味を持っているIllegalArgumentExceptionを投げたくなる*2ときもあります。まぁcheckArgument(name != null)と書けばこの問題はひとまず回避できますが……。


 To solve these problems, I created a maven plugin and pushed it to the GitHub. With this plugin, we can rewrite it like below.
 これらの問題を解決する手段として、Mavenプラグインを書いてGitHubにpushしてみました。このプラグインを使えば、上記のコードは以下のように書くことができます。

public MyClass(@Nonnull String name) {
	this.name = name;
}

 The @Nonnull is one of annotations defined in JSR 305. This maven plugin injects precondition checking to compiled class files. @Nullable, @Nonnegative and @MatchesPattern are ready to inject.
 この@NonnullはJSR 305で定義されているアノテーションの1つです。このMavenプラグインは@Nonnullや@Nullable、@Nonnegativeに@MatchesPatternといったJSR 305のアノテーションをもとに事前条件確認のコードをクラスファイルに埋め込みます。

 These annotations are annotated by @Documented, so they are documented in Javadoc by default. And tools like FindBugs will tell 'don't pass null' to users. 1st problem is solved by them. This plugin has a feature to change exception to throw, so our 2nd problem is solved too.
 @Documentedの働きにより、これらのアノテーションはデフォルトでJavadocに記載されます。FindBugsのような静的解析ツールもnullを渡してはならないことをユーザーに指摘してくれるでしょう。これらにより、実装を読まなければ制限がわからないという1つめの問題が解決されます。例外を変更する機能によって2つめの問題も解決できます。
 This plugin is not mainstream as how to use JSR 305 annotations, but is very useful for me. I'm using this for some projects and brushing up. I'm happy if you try to use and like it. Happy hacking!
 これはJSR 305の使い方としては異端だと思いますが、今のところ便利に使えています。今後も自分のプロジェクトで使いながら改善していくつもりです。よろしければお試しいただければ幸いです。

*1:NPE means 'Oops! It's null!' but IAE means 'Your argument is wrong'.

*2:NPEだとインスタンスの内部状態などにも疑いがかかるがIAEなら引数だけが疑わしい