- PR -

catch を書かなくても例外発生時にエラーメッセージを出したい

投稿者投稿内容
Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2004-04-23 10:47
こんな感じ?
コード:

import java.awt.event.*;
import javax.swing.*;
public class ExceptionHandler extends JFrame {
static final Thread shutdownHock = new Thread("ShutdownHock") {
public void run() {
System.err.println("shutdown!");
}
};

public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(shutdownHock);

ThreadGroup group =
new ThreadGroup(
Thread.currentThread().getThreadGroup(),
"ExceptionHandlingGroup") {
public void uncaughtException(Thread t, Throwable e) {

System.err.println(
"Uncaught Exception : " + e.getLocalizedMessage());
super.uncaughtException(t, e);
System.exit(1);
}

};

new Thread(group, "main2") {
public void run() {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
ExceptionHandler f =
new ExceptionHandler("ExceptionHander");
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}.start();
}

public ExceptionHandler(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().add(new JButton(new AbstractAction("Exception") {
public void actionPerformed(ActionEvent e) {
throw new RuntimeException("Exception!!!");
}
}));
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
Runtime.getRuntime().removeShutdownHook(shutdownHock);
System.out.println("Exit");
}
});
}
}


EventThreadの例外をハンドリングするのは無理かと思いましたが、
やればできるものですね。勉強になりました
ShutdownHockはなくてもよさそうですけど。

[ メッセージ編集済み 編集者: Wata 編集日時 2004-04-23 10:52 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-04-25 08:38
unibon です。こんにちわ。

引用:

sauceさんの書き込み (2004-04-23 09:40) より:
もしや、統一的なControllerが無い、ViewとModelが密結合した構造ですか?
そうなると確かに「個所が多い」ですね…


耳が痛いお言葉です。そうですね、そのような Controller を設けるべきだろうとは思ってはいますが、なかなかできないでいます。

引用:

sauceさんの書き込み (2004-04-23 09:40) より:
ところで先程提示したリンク先のサイトでmonitorコマンドなる物が紹介されてますが、
これは使えませんかね?


jdb の中で run を実行すると、
コード:
uncaught java.lang.Throwable を設定しました
保留した uncaught java.lang.Throwable を設定しました


と表示されることから、やはり uncaught 関連の機能が密に絡んで来るのだろうと思います。ただ、私は jdb をほとんど知らないこともあり、monitor の使い方も良く分かりませんでした。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-04-25 08:46
unibon です。こんにちわ。

引用:

お犬様さんの書き込み (2004-04-23 10:30) より:
1.4以前の場合だと、標準エラー出力には例外のスタックトレースしか出力しない、と決めておいて、スタックトレースを受け取り、その内容をダイアログに表示した後に強制終了するような OutputStream なりを作って System#setErr(java.io.PrintStream) するとかしか思いつきません。


これは、意外でした。こんなことができるとは思いもよりませんでした。java.exe の出力をリダイレクトして別プロセスに入力させるなどは考えたことはあったのですが、setErr というメソッドがあるとは知りませんでした。ありがとうございます。
以下、長いですが、setErr を使ってみた実例です。
コード:
import java.io.*;
import java.awt.event.*;
import javax.swing.*;

public class StdErrCatcher {

    private static class MyPrintStream extends PrintStream {

        private final Runnable runnable;
        private boolean done = false;

        private void hook() {
            if (!done) {
                done = true;
                if (runnable != null) {
                    SwingUtilities.invokeLater(runnable);
                }
            }
        }

        public MyPrintStream(OutputStream out, Runnable aRunnable) {
            super(out);
            runnable = aRunnable;
        }

        public void print(boolean b) {
            hook();
            super.print(b);
        }

        public void print(char c) {
            hook();
            super.print(c);
        }

        public void print(char[] s) {
            hook();
            super.print(s);
        }

        public void print(double d) {
            hook();
            super.print(d);
        }

        public void print(float f) {
            hook();
            super.print(f);
        }

        public void print(int i) {
            hook();
            super.print(i);
        }

        public void print(long l) {
            hook();
            super.print(l);
        }

        public void print(Object obj) {
            hook();
            super.print(obj);
        }

        public void print(String s) {
            hook();
            super.print(s);
        }

        public void println() {
            hook();
            super.println();
        }

        public void println(boolean x) {
            hook();
            super.println(x);
        }

        public void println(char x) {
            hook();
            super.println(x);
        }

        public void println(char[] x) {
            hook();
            super.println(x);
        }

        public void println(double x) {
            hook();
            super.println(x);
        }

        public void println(float x) {
            hook();
            super.println(x);
        }

        public void println(int x) {
            hook();
            super.println(x);
        }

        public void println(long x) {
            hook();
            super.println(x);
        }

        public void println(Object x) {
            hook();
            super.println(x);
        }

        public void println(String x) {
            hook();
            super.println(x);
        }

        public void write(byte[] buf, int off, int len) {
            hook();
            super.write(buf, off, len);
        }

        public void write(byte[] b) throws IOException {
            hook();
            super.write(b);
        }

        public void write(int b) {
            hook();
            super.write(b);
        }
    }

    private static JFrame frame;

    public static void main(String[] args) {
        Runnable finish = new Runnable() {
            public void run() {
                JOptionPane.showMessageDialog(frame, "不正処理発覚",
                "StdErrCatcher", JOptionPane.ERROR_MESSAGE);
                frame.dispose();
                // System.exit(1);
            }
        };
        PrintStream printStream = new MyPrintStream(System.err, finish);
        System.setErr(printStream);
        final Runnable gui = new Runnable() {
            public void run() {
                frame = new JFrame("StdErrCatcher");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                JButton button = new JButton("push");
                button.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        throw new RuntimeException("Hello");
                    }
                });
                frame.getContentPane().add(button);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(gui);
    }
}


unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2004-04-25 08:55
unibon です。こんにちわ。

引用:

Wataさんの書き込み (2004-04-23 10:47) より:

EventThreadの例外をハンドリングするのは無理かと思いましたが、
やればできるものですね。勉強になりました
ShutdownHockはなくてもよさそうですけど。


教えていただいたコードを、下記のように少しだけ変形して修了間際のダイアログを出せるようにしてみました。提示した目的は達成できました。ありがとうございます。
ただし、なぜこれでできるのかがまだ良く分かっていません。

#以下は、とくに質問ではありませんが持っている疑問です。
GUI のイベントディスパッチを uncaughtException のハンドラーを定義したスレッドグループ内の別スレッドでおこなうかどうかに依存するのでしょうか。
また、ShutdownHook はなくても良いのでしょうか。

コード:
import java.awt.event.*;
import javax.swing.*;

public class ExceptionHandler {

    private static JFrame frame;

    public static void main(String[] args) {
        ThreadGroup group =  new ThreadGroup(
                Thread.currentThread().getThreadGroup(),
                "ExceptionHandlingGroup") {

            public void uncaughtException(Thread t, Throwable e) {
                System.err.println("Uncaught Exception : " + e.getLocalizedMessage());
                super.uncaughtException(t, e);
                Runnable finish = new Runnable() {
                    public void run() {
                        JOptionPane.showMessageDialog(frame, "不正処理発覚",
                        "ExceptionHandler", JOptionPane.ERROR_MESSAGE);
                        frame.dispose();
                        // System.exit(1);
                    }
                };
                SwingUtilities.invokeLater(finish);
            }
        };

        final Runnable gui = new Runnable() {
            public void run() {
                frame = new JFrame("ExceptionHander");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
               JButton button = new JButton("push");
                button.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        throw new RuntimeException("Hello");
                    }
                });
                frame.getContentPane().add(button);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        };

        Thread main2 = new Thread(group, "main2") {
            public void run() {
                SwingUtilities.invokeLater(gui);
            }
        };
        main2.start();
    }
}


Wata
ぬし
会議室デビュー日: 2003/05/17
投稿数: 279
投稿日時: 2004-04-26 09:54
引用:

unibonさんの書き込み (2004-04-25 08:55) より:
unibon です。こんにちわ。
GUI のイベントディスパッチを uncaughtException のハンドラーを定義したスレッドグループ内の別スレッドでおこなうかどうかに依存するのでしょうか。


そうですね、スレッドグループをスレッドのコンストラクタに指定して、
スレッドを作ると、そのスレッド内で処理されなかった例外は、スレッドグループ
のuncaughtException()で処理されることになります。

src.zip内の範囲でソースを追ってみたところ、java.awt.EventDispatchThread
のインスタンスは、java.awt.EventQueueのinitDispatchThread()メソッドで
つくられていて、EventQueueは自身のインスタン化を行ったスレッドのグループを
EventDispatchThreadのコンストラクタに渡しています。
EventQueueはjava.awt.Toolkitの初期化時にいっしょに行われるので、
最初にAWT関連の呼び出し(この場合は invokeLater)を行ったスレッドが
使われることになるようです。

あと、shutdownHockはAWTのイベントディスパッチと特に関係ないです。
「こんなのもあるよ」って感じでソースに乗せただけです。

スキルアップ/キャリアアップ(JOB@IT)