@TaikiTkwkbysh (WAKA Engineer)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

addActionListenerの著名クラスとラムダ式について

解決したいこと

下記に記載する文の、ラムダ式の箇所について詳細を教えて頂きたいです。

public class Button extends JPanel{

    JButton login = new JButton("ログイン");//ログインボタン
    JButton clear = new JButton("クリア");//クリアボタン

    //コンストラクタ
    public Button(UserId uid/*ユーザーIDを表示するクラス*/, PassWord pw/*パスワードを表示するクラス*/) {
        this.setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
        this.add(login);
        this.add(clear);

        String id = uid.getText();
        String pass = pw.getPass();

        //問題の箇所
        login.addActionListener(e -> {
            if(id.equals("minato") && pass.equals("yusuke")) {
                JOptionPane.showMessageDialog
                (this,"ログイン成功","ログインに成功しました",JOptionPane.INFORMATION_MESSAGE);
            }else {
                JOptionPane.showMessageDialog
                (this,"ログイン失敗","ログインに失敗しました",JOptionPane.INFORMATION_MESSAGE);
            }
        });

現在勉強している参考書の問題は下記の通りです。
※該当するところを抜粋して記載致します。

①次のような動作をするようイベントハンドラを追加せよ。
・「ログイン」ボタンを押す際、ユーザー名がminatoかつ、パスワードがyusuke場合、ログイン成功のダイアログ、それ以外はログイン失敗のダイアログが表示される。

完成状態

スクリーンショット 2021-12-15 23.55.49.png

該当するソースコード①(ユーザーIDの箇所のクラス)

public class UserId extends JPanel {

    JLabel userID = new JLabel("ユーザー名");
    JTextField idField = new JTextField();

    public UserId() {
        this.setLayout(new BorderLayout());
        this.add(userID,BorderLayout.WEST);
        this.add(idField,BorderLayout.CENTER);
    }

    //getter
    public String getText() {
        return this.idField.getText();
    }

     //setter
    public void setText(String newValue) {
        this.idField.setText(newValue);
    }
}

該当するソースコード②(パスワードの箇所のクラス)

public class PassWord extends JPanel {

    JLabel passWord = new JLabel("パスワード");
    JPasswordField passField = new JPasswordField();

    public PassWord() {
        this.setLayout(new BorderLayout());
        this.hidePass();
        this.add(passWord,BorderLayout.WEST);
        this.add(passField,BorderLayout.CENTER);
    }

    //getter
    public String getPass() {
        return String.valueOf(this.passField.getPassword());
    }

    //setter
    public void setPass(String newValue) {
        this.passField.setText(newValue);
    }
}

自分で試したこと

現在著名クラス・及びラムダ式の部分に関しては、下記のように認識しております。

・著名クラス 
メソッドの呼び出し等の際、クラスの宣言とインスタンス化をするもの。
今回は、addActionListenerクラスを実装した他クラスの作成を省く為に利用している。

login.addActionListener(new ActionListenerをを実装したクラスのインスタンス);

//著名クラス
login.addActionListener(new ActionListener()/* ← クラスの宣言とインスタンス化*/{
  public void actionPerformed(ActionEvent e){// ← メンバの宣言と処理
   //処理したい内容(if文の箇所)
}
})

・ラムダ式
関数の定義と即時生成。
addActionListenerがactionPerformedメソッド一つしか持たないので、
ラムダ式でクラスとメソッドを省略。

//著名クラス
login.addActionListener(e -> {
   //処理したい内容(if文の箇所)
})

そこで、自分が著名クラスにして記載をしようとした内容が下記です。


//宣言はButtonクラスのコンストラクタ内
login.addActionListener(new ActionListener(){
  public void actionPerformed(ActionEvent e){
   if(id.equals("minato") && pass.equals("yusuke")) {
                JOptionPane.showMessageDialog
                (this,"ログイン成功","ログインに成功しました",JOptionPane.INFORMATION_MESSAGE);
            }else {
                JOptionPane.showMessageDialog
                (this,"ログイン失敗","ログインに失敗しました",JOptionPane.INFORMATION_MESSAGE);
            }
  }
})

このように記載すると、showMessageDialogの部分でエラーが出ます。
内容は、thisがJPanelを継承しているButtonクラスのインスタンスではなく、著名クラスで宣言しているnew ActionListener()に向いており、引数が対応していないというエラーです。

コードも自分の認識も恐らく間違っているかと思いますが、ラムダ式だとうまくいき、著名クラスの方法ではエラーが起きる理由がわからない状態で、なぜ処理に差があるのかが知りたいです。

正解のラムダ式はクラスを作らず関数の処理を行なっているからthisがしっかり機能しているという事になるのでしょうか。
また、もしthisを生かしたまま著名クラスで記載をする場合はどのようになるのでしょうか。

長文で申し訳ございませんが、ご教示の程宜しくお願い致します。

0 likes

3Answer

"java lambda this"でググった結果の先頭↓

  • インナークラスとラムダ式は基本同じだが、thisの振る舞いについてはあえて変更していること。
  • 変更理由がエンクロージャクラスにthisを指したいケースの方が多い

とかそんなこと書かれてる。

どうしてもインナークラスを使いたければ、thisをローカル変数に代入するか、
リスナー登録を別メソッドとして切り出し、そのメソッドの実引数にthis渡せばいけるかな?(試さずテキトーなこと言ってるので注意)

1Like

@ktz_alias

この度はご教示頂き、誠にありがとうございます。
ご共有頂いたサイト、拝見致しました。
やはりラムダ式と著名クラスとでは、thisの扱いが違うのですね。

とても良い勉強になりました。
大変助かりました。

また機会がございましたら、何卒ご教示頂けますと幸いでございます。
以上、宜しくお願い致します。

0Like

質問とは関係ないんですが匿名クラスか無名クラスと呼ぶのが一般的な気がしますね。

0Like

Your answer might help someone💌