読者です 読者をやめる 読者になる 読者になる

ITお絵かき修行

3歩歩いても忘れないために

Upgrade Java SE 7 to Java SE 8 OCP Programmer(1Z0-810)対策 第一章 ラムダ式(3)

(1)(2)に引き続き、ラムダ式の章を進める。

■試験対策ページ
java.boot.by

■注意
全文が意訳です。正確な情報は下記リンクを参照してください。

■試験
Upgrade Java SE 7 to Java SE 8 OCP Programmer | Oracle Certification Exam

1.3. ラムダ式について説明する 匿名インナークラスを使用したコードをラムダ式を使用するようにリファクタリングする 型推論とターゲット型付けについて説明する

匿名インナークラスとラムダ式で置き換える
開発者のコードの一部には無名インナークラスが含まれており、時として読みづらい。
開発者は匿名インナークラスを、読みやすさとメンテナンスしやすさのために置き換えるべきである。

匿名インナークラスとラムダ式での置き換えによって、定型化したコードの何行かのコードを書くよりも開発時間を短縮できるだろう。
一般的なSwingアプリケーションでは匿名インナークラスをアプリケーションに機能追加する際に必要とする。
例えば匿名クラスはボタンにactionを追加するよく使われる方法である。ここでの問題は内部クラスは読みにくいということであり、多くの定型化したコードを書く必要があることである。

下記のコードはボタンのactionの実装として匿名インナークラスの実装を試している。
まずは下記のラムダ式で置き換える前のコードを見てほしい。

JButton button = ...
JLabel comp = ...

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        comp.setText("Button has been clicked");
    }
});

例えばActionListenerインタフェースクラスの具象クラスを実装する。このインタフェースはactionPerformedという1つのメソッドを保持している。
actionPerformedメソッドはユーザーが実際に画面上のボタンを押下した時に、buttonインスタンスより呼び出されている。
匿名インナークラスはメソッドの実装を提供する。

匿名インナークラスはJavaプログラマーがコード内でデータを受け渡しやすいように設計されている。
だが不幸なことに、それらはコードをわかりにくくしている。ここでは1行の重要なコードを呼び出すために4行の定型化されたコードが必要となる。

定型化されたコードの問題は1つではない。このコードは開発者の意図が明確でなく非常に読みづらい。
開発者が行いたいことはいくつかの振る舞いを実行するすることであり、(メソッドに)オブジェクトを渡したくない。
Java8ではこのコードをラムダ式で書くことができる。下記にサンプルを示す。

JButton button = ...
JLabel comp = ...

button.addActionListener(e -> comp.setText("Button has been clicked"));

・インタフェースを実装したオブジェクトを渡す代わりに、匿名の関数(ブロック化されたコード)を渡している。
・"e"(Javaの修飾子名以外が指定可能)は匿名インナークラスのパラメータのようなパラメータである。
・"->"はラムダ式の関数部からパラメータを分離する。ユーザがボタンをクリックした際に動作する。
・他の匿名インナークラスを使用していたときとの違いは変数eの宣言である。以前は明確に ActionEvent e と型を宣言していた。
 今回の例(※ラムダ式を使った場合)開発者に型となるクラスが渡されていないが、このクラスはコンパイルすることができる。
 内部で何が起こっているかというと、変数eに対してaddActionListenerメソッドシグネチャより型推論が行われている。
 これは、開発者は明確にパラメータの型を記述する必要がないということを意味する。

※WARNING※
いくつかの場面ではJavaコンパイラが型を推論できない場合、変数の型やパラメータの型を明確に記述する必要がある。

下記の例はラムダ式の引数に対して、明示的に型を記述する場合。

JButton button = ...
JLabel comp = ...

button.addActionListener((ActionEvent e) -> comp.setText("Button has been clicked"));

ラムダ式の構文
ラムダ式は下記の構文から構成される。

  • 括弧で囲まれたカンマ区切りのリスト

メモ:ラムダ式のパラメータの型は省略することができる。加えて、パラメータがひとつの場合は括弧を省略することができる。例えば下記のラムダ式は正しい。

s -> s.getAge() >= 18
(Student s) -> s.getAge() >= 18
(s) -> s.getAge() >= 18
  • メソッド本文は「1つの式」もしくは「ブロック」から構成される。
... -> s.getAge() >= 18

1つの式しか記述しない場合、Javaの実行環境は式を戻り値の評価を行う。代わりに「return」句を使うことができる。

... -> { return s.getAge() >= 18; }

return句に型はない。ラムダ式では、式を中括弧{}で囲む必要がある。しかし、voidメソッドは中括弧で囲む必要はない。例えば、下記のラムダ式は正しい。

email -> System.out.println(email)