Javaでクロージャを使いたくなる場面
private JButton getOkButton() { if (okButton == null) { okButton = new JButton(); okButton.setBounds(new Rectangle(30, 23, 55, 21)); okButton.setText("OK"); okButton.addActionListener(getActionListener("ok")); } return okButton; } private ActionListener getActionListener(String name) { return new ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { if(name.equals("ok")) { ok_actionPerformed(e); } else { ng_actionPerformed(e); } } }; }
Appletで、ボタンが増えた場合、上のように、
ActionListnerを取得するメソッド(getActionListener())を汎用化したいときがある。
しかし、このような書き方だと以下のようなコンパイルエラーになる。
異なるメソッドで定義されたインナー・クラス内で非 final 変数 name を参照できません。
簡単に言うと、
『nameなんて読めねーよ。』
ということである。
そこで、以下のように書き換える必要がある。
private ActionListener getActionListener(String name) { return new MyActionListener(name); } class MyActionListener implements ActionListener { private String name = null; public MyActionListener(String name) { this.name = name; } public void actionPerformed(java.awt.event.ActionEvent e) { if(name.equals("ok")) { ok_actionPerformed(e); } else { ng_actionPerformed(e); } } }
つまり、インナークラスを定義する必要がある。
これは、かなりうざい。
以下のようにも書ける。(最初のコードの引数にfinalを付けただけ)
private ActionListener getActionListener(final String name) {
しかし、何か気持ちが悪い。
クロージャがあれば、最初のようなコードは普通に書けることだろう。
ひょっとすると、関数型を使って、こんな書き方もできるかも知れない。
private JButton getOkButton() { if (okButton == null) { okButton = new JButton(); okButton.setBounds(new Rectangle(30, 23, 55, 21)); okButton.setText("OK"); okButton.addActionListener(getActionListener(ok_actionPerformed)); } return okButton; } private ActionListener getActionListener(function _actionPerformed) { return new ActionListener() { public void actionPerformed(java.awt.event.ActionEvent e) { _actionPerformed(e); } }; }
すごすぎる。