[雑談] 試験の役に立たないJava講座 (3)

ということで引き続きインプレス社の「徹底攻略Java SE 11 Silver問題集」の章立てに沿って、少し雑談していきたいと思います。

以前よりお話ししているとおり問題集の内容に沿ったものではなく抜けているところも多々ありますので、認定資格を取得しようというのであれば問題集を購入して、そちらをしっかり勉強してください。

こちらは章立てに沿って適当に書き散らかしているものですので、試験の役には立ちません。

ということで今回は第2章の続き、varを使ったローカル変数の型推論を扱っています。

型推論

Javaは静的な型の安全性を担保したプログラミング言語として設計されています。

ざっくりというと、ソースコードの時点でデータ型の不整合、例えば文字列に3をかけるといった何をやりたいのかわからない式が書かれている、int型の値をshort型の変数に代入するなど桁あふれの危険があるといった場合にはコンパイル時にエラーを発生する仕様となっています。

これを実現するために変数などの容器にはすべてデータ型が結び付けられていて、プリミティブ型の回で示した例のように変数を宣言する際にはどのデータ型の変数であるかを明示する必要があります。

プリミティブ型の型名にそれほど難しいものはありませんが、オブジェクト型の場合、クラス名はユーザが必要に応じてつけるため、長いクラス名になる場合があります。

特にパッケージの項で説明したようにインポートされていない他パッケージのクラス名はパッケージ名とクラス名をつなげたものになるため、非常に長いものになります。

そのほか、あとで出てくるジェネリック型を使用する場合も型名が長くなる傾向があります。

こういったデータ型を使用すると変数宣言の行が非常に長くなり、プログラムが読みにくくなるといったことが問題として提起されてきました。

例えばSupercalifragilisticexpialidocious型のtheSpellという変数を定義して、初期化する場合、以下のようなコードになります。

Supercalifragilisticexpialidocious theSpell = new Supercalifragilisticexpialidocious();

上の式のnew クラス名()という書き方はそのうち説明しますが、とりあえずはクラス名という型で変数を初期化する式だと思ってください。

これ一つだけであれば別に問題はありませんが、このような行がプログラム中にいくつもあると非常に面倒になるということが主張されていました。

特に上の例のようにtheSpellと言えばSupercalifragilisticexpialidociousだとわかる場合 (わからない人は検索してください) には変数の型を明示する必要はないだろうという主張です。

そこで導入されたのがローカル変数宣言における型推論で、上の式は以下のように書けることになりました。

var theSpell = new Supercalifragilisticexpialidocious();

だいぶ短くなって読みやすくなりました。

今回は初期化式の右側が単純なのでプログラムを読む場合に変数の型をすぐに類推することができますが、初期化式の右辺が複雑な式となった場合には変数の型が何になるかを直感的に把握することができないため、プログラムがわかりにくくなる可能性があります。

Javaプログラムで割と使われるSQLデータベースへのアクセスの例を示します。

Connection connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
PreparedStatement preparedStatement = connection.prepareStatement(QUERY_STRING);
ResultSet resultSet = preparedStatement.executeQuery();

こういった決まり切った書き方 (ボイラープレートコードと呼ぶそうです) の場合、型名をいちいち書く必要はないので、型推論が有効になります。

var connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
var preparedStatement = connection.prepareStatement(QUERY_STRING);
var resultSet = preparedStatement.executeQuery();

しかし、わかりやすいのは型名と同じ変数名を付けていることも理由としてあり、変数名を短くしたり、型と関連の薄い変数名を付けるとプログラムが読みにくくなる可能性があります。

ローカル変数宣言における型推論の制限事項

型推論の使用にはいくつかの制限があります。

まず、使用できるのはローカル変数宣言とfor文および拡張for文のインデクスの宣言だけです。それ以外のメソッドの仮引数やフィールド宣言には使用できません (と言ってもこれまで触れていない内容ばかりなので後程出てきたところで説明します)。

そして型推論と呼んでいますが、あなたがやりたいと思っていることを先回りして実現してくれるといった素晴らしい機能ではありません。

コンパイラはvarで始まるローカル変数宣言を見つけると、初期化式の型を判定して、varを該当する型に置き換えるだけです。

このため、var p = null;といった式はnullが型を持たないためエラーになります。

また、var v;のように初期化式を持たないローカル変数宣言も使用できません。

Java仕様の拡張について

最初にも書いたようにローカル変数の型推論は最近になってJava言語仕様に導入された機能です。

Javaはオープンな仕様を標榜していて、新機能の追加や変更などの改訂はオープンなコミュニティで議論され、決定されます。

そして改訂に関する文書はJSR (Java Specification Requests) またはJEP (JDK Enhancement Proposal) で参照することができます。

それぞれに役割があるので2種類の文書群があるわけですが、使い方を導入したそもそもから調べたい場合には検索をかけて見つかったほうの文書を読めばいいかと思います。

なお、ローカル変数の型推論はJEP 286で議論されたもので、今回の文書もそれを参考に書いています。

まとめ

varで始まるローカル変数宣言で宣言された変数は初期化式の型によって型が決まります。

型はコンパイル時に決定できること、言い換えればJavaソースファイルを読むだけで型がわかるものでなければいけません。

また、使い方によってはコードが読みづらくなる恐れがありますので、濫用は慎んでください。

自分で使うことはないかもしれませんが、他人のコードを読む場合などに必要になりますので、一応こういう機能があるということを認識すべきと思います。

0コメント

  • 1000 / 1000