【コラム】

Java API、使ってますか?

56 Java SE 7の要注目機能"クロージャ"はどうなるのか その4

56/60

クロージャにおける例外のスロー

3回にわたってJava SE 7で導入される予定のクロージャについて紹介してきたが、少しずつ具体的な形が見えてきただろうか。今回はJavaのクロージャにおける例外の扱いについて紹介したい。

クロージャでは例外をスローすることもできる。そのためにはリスト1のように、throwsキーワードを使ってスローしたい例外クラスを戻り値の後に指定すればよい。

リスト1 ExceptionSample.java - 例外の指定

import java.io.*;

class ExceptionSample {
    public static void main(String[] args) {
        try {
            Writer writer = 
                new PrintWriter(new FileWriter("sample.txt"));

            // 例外付きのクロージャ
            { String => void throws IOException } write = 
                { String message => writer.append(message + "\n"); };

            try {
                write.invoke("Good morning!");
                write.invoke("Good afternoon!");
            } finally {
                writer.close();
            }
               } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

このクロージャではWriterのappend()メソッドを呼び出しているが、append()はIOExceptionをスローする可能性がある。そこでthrowsでIOExceptionを指定することによって、通常のメソッドの場合と同様に例外がスローされることを明示している。

クロージャのブロックステートメント内で例外がスローされる可能性がある場合、そのクロージャの関数型は自動的にthrowsで修飾されたものになり、throwsの付かない関数型との互換性はなくなる。たとえば前述の例の場合、リスト2のようにthrowsの指定を外してしまうと、プロンプト1に示すようなコンパイルエラーになる。

リスト2 throws指定のないクロージャ

{ String => void } write = 
    { String message => writer.append(message + "\n"); };

プロンプト1 throwsで修飾されたクロージャとそうでないクロージャは互換性がない

ExceptionSample.java:13: 互換性のない型
検出値  : {java.lang.String => void throws java.io.IOException}
期待値  : {java.lang.String => void}

では、例外をスローするクロージャの実装はどうなっているのか見てみよう。まず、このクロージャの型を表すインタフェースjavax/lang/function/unrestricted/VO.classを逆コンパイルしてみるとリスト3のようになっており、invoke()メソッドにthrowsが指定されていること分かる。このinvoke()の実装はExceptionSample.classを逆コンパイルすれば見られるが、要約するとリスト4のような感じだ。したがってinvoke()呼び出し時にはIOExceptionをcatchしなければならない。

リスト3 VO.classを逆コンパイル

public interface VO {
    public abstract void invoke(Object obj) throws Throwable;
}

リスト4 ExceptionSample.classを逆コンパイル

public final void invoke(String s) throws IOException {
    writer.append((new StringBuilder())
            .append(s).append("\n").toString());
}

型引数の利用

Java SE 7ではクロージャの追加に合わせて、ジェネリクスの型引数で例外のthrow宣言ができるようになるという。これを例外型引数(Exception Type Parameters)と呼び、これを利用することでスローする例外の種類を実行時に決定できるようになる。例外型引数はたとえばリスト5のように記述する。

リスト5 ExceptionSample2.java - 例外型引数の使用例

import java.io.*;

class ExceptionSample2 {
    static <throws E> void todo({ => void throws E } block) throws E {
        block.invoke();
    }

    public static void main(String[] args) {
        // 例外なしでの呼び出し
        todo({ => System.out.println("Hello!"); });

        try {
            Writer writer = 
                new PrintWriter(new FileWriter("sample.txt"));
            // 例外付きの呼び出し
            todo({ => writer.append("Hello!"); });
           } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

この例の場合、todo()メソッドには引数として何らかの例外をスローする可能性のあるクロージャを渡す。その例外の種類は例外型引数で指定されているので実行時に決まる。最初の呼び出しでは単に"Hello!"と表示するだけのクロージャなので、例外はスローされない。2番目の呼び出しではWriterのappend()を使うクロージャなので、IOExceptionがスローされる可能性がある。したがって呼出し時にはこれをcatchする必要がある。

なお、もしクロージャの実行時にスローする例外を明示的に指定したい場合にはリスト6のようにすればいいとのこと。

リスト6 例外を明示的に指定

ExceptionSample2.<throws IOException>todo({ => writer.append("Hello!"); });

複数の例外をスローする

クロージャで複数の例外をスローするように宣言することも可能。それには、通常のthrows宣言と同様にスローしたい例外のクラスをコンマで区切って並べればよい。リスト7はIOExceptionとInterruptedExceptionを同時に指定した例である。これは渡されたた文字列をファイルに書き込むクロージャだが、書き込み後にThread.sleep()で100msスリープさせているため、InterruptedExceptionをスローする可能性がある。したがってInterruptedExceptionのthrows宣言を省略するとコンパイルエラーになる。

なお、catchブロックの「catch (IOException | InterruptedException e)」というのは、Java SE 7で導入される予定のマルチキャッチの機能を用いた記述。キャッチしたい例外を"|"で続けて記述することにより、ひとつのcatchブロックで複数の例外を処理することができるようになる。

リスト7 ExceptionSample3.java - 複数の例外をスローする例

import java.io.*;

class ExceptionSample3 {
    public static void main(String[] args) {
        // 複数の例外をスローする
        { String => 
                void throws IOException, InterruptedException } write = 
            { String message => 
                 Writer writer = 
                     new PrintWriter(new FileWriter("sample.txt"));
                 writer.append(message + "\n");
                 Thread.sleep(100);
                 writer.close();
            };

            try {
                write.invoke("Good morning!");
                write.invoke("Good afternoon!");

            } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

例外型引数を使う場合にも複数の例外をスローするように明示的に指定することができる。この場合、のときのように呼出し側で具体的な例外のクラスを指定するが、その際にマルチキャッチのときと同様に"|"で区切って任意の例外を並べて記述する。たとえば先述のtodo()メソッドの呼び出しならばリスト8のようになる。

リスト8 例外型引数を使う場合に、複数の例外を明示的に指定

try {
    // 複数の例外を明示的にスロー
    ExceptionSample2_3.
            <throws IOException | InterruptedException>todo(
        { => Writer writer = 
                 new PrintWriter(new FileWriter("sample.txt"));
             writer.append("Hello!");
             Thread.sleep(100);
             writer.close();
        });
} catch (IOException | InterruptedException e) {
    e.printStackTrace();
}

この例でtodo()に渡しているのは、リスト7と同様にIOExceptionとInterruptedExceptionの両方をスローする可能性があるクロージャである。したがってこの2つのクラスをthrowsで明示的に宣言している。

56/60

インデックス

連載目次
第60回 どうなる? 今後のJavaプラットフォーム(Java SE編)
第59回 どうなる? 今後のJavaプラットフォーム(Java EE編)
第58回 Java SE 7の要注目機能"クロージャ"はどうなるのか その6
第57回 Java SE 7の要注目機能"クロージャ"はどうなるのか その5
第56回 Java SE 7の要注目機能"クロージャ"はどうなるのか その4
第55回 Java SE 7の要注目機能"クロージャ"はどうなるのか その3
第54回 Java SE 7の要注目機能"クロージャ"はどうなるのか その2
第53回 Java SE 7の要注目機能"クロージャ"はどうなるのか
第52回 Early Draftが公開されたJSF 2.0
第51回 EJBから独立したJava Persistence 2.0
第50回 モバイルJavaの新しい潮流となるか - MSA 2.0のドラフト公開
第49回 やっぱり基本はServlet - Servlet 3.0のEarly Draftを読む
第48回 JOGLで3Dプログラミング その4
第47回 JOGLで3Dプログラミング その3
第46回 JOGLで3Dプログラミング その2
第45回 JOGLで3Dプログラミング
第44回 JARファイルを効率的にネットワーク転送するためのPack200形式
第43回 Early Draftで把握するEJB 3.1の新機能
第42回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その2
第41回 次世代の携帯端末向けJava仕様"MIDP 3.0"はどうなるか その1
第40回 リソースアダプタによる接続の仕組み
第39回 JCAを利用したシステム間接続
第38回 Java EEと外部システムの接続性を支えるJCAがバージョンアップ
第37回 Javaのモジュラリティ強化を担う"スーパーパッケージ"とは
第36回 JSR 308対応のコンパイラを試す
第35回 公開されたJSR 308のEarly Draftを検証する
第34回 スクリプト言語とJavaを結びつけるJSR 223
第33回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その2
第32回 Java EE環境に統一されたコンポーネントモデルを提供するJSR 299 その1
第31回 Javaの文法がそのまま使えるスクリプト言語"BeanShell"
第30回 Javaアプリケーションにオブジェクトのキャッシュ機構を提供するJCache API
第29回 Javaアプリケーションからのリソース管理を可能にするJSR 284
第28回 XMLデータソースへの問い合わせはJSR 225で
第27回 Portlet Specification 2.0をもっと手軽に利用する
第26回 次期Javaポートレット仕様となるJSR 286
第25回 JSFとポートレットをつなげるJSR 301
第24回 Webサービス向けのポートレット仕様「WSRP」
第23回 高い相互運用性を実現するポートレットAPI - JSR 168
第22回 Java EE環境でタスクのスケジューリングを可能にするJSR 236
第21回 Java EE環境でのスレッドプログラミングを可能にするJSR 237
第20回 音声認識/合成のためのAPI - Java Speech APIとJSR 113
第19回 JSR 291でJavaプラットフォームにダイナミックコンポーネントモデルを導入
第18回 JAX-RSで簡単RESTful - JSR 311
第17回 待望のServlet 3.0がJSRに登場 - JSR 315
第16回 アノテーションを使ってバグ退治 - JSR 305
第15回 アノテーションをさらに広い範囲で利用可能にするJSR 308
第14回 Webアプリケーション開発の要となるか - JSF 2.0がJSRに登場
第13回 Webサービス経由でのJMX Agentへの接続を可能にするJSR 262
第12回 Javaアプリケーションのモジュール化をサポートするJava Module System
第11回 "NIO.2"がやってきた - JSR 203: More New I/O APIs for the Java Platform
第10回 JSR 295: Beans Bindingの参照実装を試す
第9回 けっこう便利! 単位を扱うAPI -- JSR 275: Units Specification
第8回 アノテーションでバリデーション - JSR 303: Bean Validator
第7回 Swing開発の救世主となるか - Swing Application Framework
第6回 JavaBeansのプロパティを同期させるバインディングAPI
第5回 誰よりも早く"Java SE 7"を睨む
第4回 日時情報の取り扱いを改善する JSR 310: Date and Time API
第3回 古いAPIも進化している!? - JSR 919: JavaMail 1.4
第2回 JSR 1 リアルタイムJava仕様
第1回 JCPによって進められるJava関連技術の標準化

もっと見る

提供:マイナビ

会員登録はこちら

大学・大学院・短大・専門学生向けの就職情報サイト「マイナビ2010」「マイナビ2009」に今すぐ登録しよう!  大手企業からベンチャー企業までの約13,000社の企業情報を公開、エントリーが可能です。2010年卒予定の方は「マイナビ2010」に、2009年卒予定の方は「マイナビ2009」に登録してください。

毎日コミュニケーションズはプライバシーマークを取得しています。

関連キーワード


人気記事

一覧

イチオシ記事

新着記事