SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Java 9で「変わること」と、Javaのこれまで

知っていると得する! Java 9になってより便利になった改善点

Java 9で「変わること」と、Javaのこれまで 第6回

try-with-resources文の改善

 try-with-resources文とは、必ず閉じなければならないリソースについて文の終わりで必ず閉じられるようにするための構文です。

 この構文を使わない場合や、Java 7より以前からのコードになれている方は、finallyでclose()メソッドを必ず実行していたはずです。しかし、Java 7からこの構文が導入されたために、finallyでの記述が必要なくなり、そしてJava 9では、さらに直感的に記述ができるようになりました。実際にJava 7以前とJava 7以降、そしてJava 9での記述可能な方法を示したのが、リスト7です。

リスト7 try-with-resourcesの使い方例(src/main/com/coltware/part6/jep213/TryWithResource.javaの抜粋)
//   (1) Java 7以前
SampleReader r1 = new SampleReader();
try{
  r1.read();
}
catch(Exception ex){
  r1.delete();
}
finally {
  try {
    r1.close();
  }
  catch(Exception ex){
  }
}

//  (2) Java 7以降
try(SampleReader r7 = new SampleReader()){
  r7.read();
}
catch(Exception ex){
  // r7.delete(); 実行できない
}

//  (3) Java 9以降
SampleReader r9 = new SampleReader();
try(r9){
  r9.read();
}
catch(Exception ex){
  r9.delete();
}

public class SampleReader implements AutoCloseable{
  public void read(){
    throw new RuntimeException("error");
  }
  //  エラーが発生した場合にのみ実行したい処理
  public void delete(){
    System.err.println("delete()");
  }
  @Override
  public void close() throws IOException {
    System.err.println("close()");
  }
}

 今回のサンプルでは簡単なSampleReaderというAutoCloseableインターフェースを実装したクラスを使って確認しています。このクラスでは問題がわかりやすいように、readメソッドでは必ずエラーが発生するようにしています。

 (1)はJava 7以前の記述方法でエラーが発生しても必ず実行できるように、finally内にcloseメソッドで実行していました。この記述をしないと、closeメソッドが呼ばれないためリソースを正しく解放できません。

 (2)はJava 7からの記述方法です。try文の中で宣言したリソースだけが自動的にcloseされる対象です。しかし、これでは、try文のスコープ外では利用できないため、例えば、catchやfinally内で特別に別の処理をしたくても利用することができません。今回のサンプルのようにエラーが発生した場合には、delete()メソッドを実行したくてもスコープ外のため記述できません。

 そこでJava 9では、(3)のように変数の宣言をtry文のスコープ外で宣言していても、try文でそのリソースを指定すると自動でリソースを解放してくれるようになりました。

Javaベースモジュール内で利用できるLogger

 Javaにはすでにjava.util.loggingというパッケージがあり、ログについてはこちらで実装されています。では、今回新規に用意されたSystem.Loggerは何が違うのでしょうか。

 例えば、SLF4Jなどを使っている方にとってはわかりやすいと思います。SLF4Jでは、ログの具体的な実装については提供していないため、どのログ実装を使っていても、ログを出力する側のプログラムでは同じように記述できます。

 具体的なログ出力のための実装に何を使うかは、実行時に決めることができます。System.Loggerは、JDK標準のロギングのためのインターフェースです。既存のサードパーティー製のライブラリも、今後、この機構を使って実装されるようになっていくと思います。

 実際にログを記述する際のコードを示したのがリスト8です。

リスト8 ログを出力する側のコード例(src/main/com/coltware/part6/jep264/SystemLog.javaの抜粋)
System.Logger logger = System.getLogger("logname");
logger.log(System.Logger.Level.INFO,"system log");

// 以下、出力例
// 2月 17, 2018 1:36:39 午後 com.coltware.part6.jep264.SystemLog check
// 情報: system log

 ログ出力のための実装はサービス機構を使って提供する必要がありますが、特に何も指定していない場合、java.util.loggingのAPIが利用されます。

 自分でロギング実装を提供するために必要なコードを示したのがリスト9です。

リスト9 ログ実装を指定するときの例(src/main/com/coltware/part6/jep264/SystemLoggerFinder.javaの抜粋)
// (1) 利用するログクラスを指定するクラスを作成する
public class SampleLoggerFinder extends System.LoggerFinder {
    @Override
    public System.Logger getLogger(String name, Module module) {
        return new SampleLogger(name);
    }
}

// (2) module-info.javaで作成したクラスをサービスとして利用できるように指定する
uses System.LoggerFinder;
provides System.LoggerFinder with SampleLoggerFinder;

 (1)ではSystem.LoggerFinderクラスを継承したクラスを作成し、その中で自分で作成、もしくは外部ライブラリなどSystem.Loggerインターフェースを実装したクラスを返すように指定します。

 続いて、サービスとしてそのクラスが利用できるように、module-info.java内でSystem.LoggerFinderを利用する宣言と、そのSystem.LoggerFinderの実装としてSampleLoggerFinderを利用する宣言をします。

その他の注目すべき改善

 ここからは、その他の注目すべき改善点を解説します。

 まず、プロパティファイル(ResourceBundle)として、UTF-8などの文字コードで記述できるようになり、この変更ともにデフォルトのファイルのエンコーディングが ISO-8859-1からUTF-8に変更されました。この問題はすでにフレームワークなどを使っている方は、それらのフレームワークで個別の対策を採っている場合もありますが、標準で問題なく利用できるようになりました。

 また、それ以外としては、String内部のデータ保持形式が変わりました。これまでは1文字につき、2byteでデータを管理していましたが、Latin-1のように1byteで管理できるコードのみの場合には、1byteで管理するようになっています。これは、通常の利用では1byte管理で問題ないということが大きな理由です。ただし、APIとしての振る舞いは変わりませんので、これまでのコードに影響はありません。また、日本語データのような場合には、同様に2byteで管理されます。

 細かい部分での消費メモリの改善は開発者にとってはあまり大きくない変更ともいえますが、ハードウェアやOSへの最適化、もしくは、メモリ効率改善の流れは、Java10以降での「Project Valhalla」や「Project Panama」というプロジェクトにてより本格的な改善が行われる予定です。そのような流れがわかるひとつのトピックスとして、今回のString内部の改善を捉えるとよいでしょう。

最後に

 本連載では第2回以降、Javaのコーディングを中心にJava 9の変更点について紹介してきました。モジュール機能という大きな追加要素に注目しがちですが、細かく既存の部分の改善も行われていることがわかります。

 次回はJavaの実行環境面での変更点である、jlinkコマンドとMulti-Release Jarファイルを中心に紹介します。また、あえて主観的な視点で筆者が感じるJavaについての現在の流れや、今後について解説する予定です。

参考資料

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
Java 9で「変わること」と、Javaのこれまで連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 小林 昌弘(コバヤシ マサヒロ)

WINGSプロジェクト について> 有限会社 WINGSプロジェクト が運営する、テクニカル執筆コミュニティ(代表 ...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/10726 2018/03/29 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー