JavaのCallableはExceptionがcatchできない？

仕事でCallableスレッドの処理がExceptionを拾えないのでRunnableに替えるという作業があったので本当にExceptionが取れないのか試してみました。

### Callableの実装

```java
package example;

import java.util.concurrent.Callable;

public class Call1 implements Callable<String> {

    // callの中に実際の処理を書く。
    public String call(){
	String nonNum = "null";
	System.out.println("init Call1");
	// Exceptionを発生させる
	System.out.println("print call " + Integer.parseInt(nonNum));
        return "Call";
    }
}
```

### Runnableの実装

```java
package example;

public class Run1 implements Runnable {

    // callの中に実際の処理を書く。

    public void run(){
	String nonNum = "run";
	System.out.println("init Run1");
	// Exceptionを発生させる
	System.out.println("print run " + Integer.parseInt(nonNum));
    }
}

```

### CallableとRunnableの呼び出し

```java
package example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello World");
        // ExecutorServiceを生成
        ExecutorService ex = Executors.newSingleThreadExecutor();

	try {
	    // Executorにスレッド Call1() の実行を依頼
	    Future<String> futureResult = ex.submit(new Call1());
	} catch (Exception e) {
	    System.out.println("Catched Call1 Exception:" + e.getMessage());
	}

	try {
	    // Run1を実行
	    Run1 run = new Run1();
	    Thread thread = new Thread(run);
	    thread.start();
	} catch (Exception e) {
	    System.out.println("Catched Run Exception:" + e.getMessage());
	}
    }
}
```

### コンパイル

```shell
$ javac example/Hello.java example/Run1.java example/Call1.java 
```

### 実行

```shell
$ java example.Hello                         
Hello World
init Call1
init Run1
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "run"
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.base/java.lang.Integer.parseInt(Integer.java:652)
	at java.base/java.lang.Integer.parseInt(Integer.java:770)
	at example.Run1.run(Run1.java:13)
	at java.base/java.lang.Thread.run(Thread.java:834)
```

RunnableのExceptionが表示されるが、CallableのExceptionはキャッチできないし、mainのtry catchでもキャッチできない。

----

しかし、Callableはget()した時にExceptionがキャッチできるとご指摘があり再度試してみました。
ご指摘くださった方々ありがとうございました。

mainは次の様に修正。

```java
package example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutionException;
    
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello World");
        // ExecutorServiceを生成
        ExecutorService ex = Executors.newSingleThreadExecutor();

	try {
	    // Executorにスレッド Call1() の実行を依頼
	    Future<String> futureResult = ex.submit(new Call1());
	    String ret; 
	    ret = futureResult.get();
	    System.out.println("ret=" + ret);
	} catch (InterruptedException|ExecutionException e) {
	    System.out.println("Catched Call1 Exception:" + e.getMessage());
	}

	// Run1を実行
	Run1 run = new Run1();
	Thread thread = new Thread(run);
	thread.start();
    }
}
```

コンパイルして実行すると。両方のExceptionを取得することができました。

```shell
 $ java example.Hello       
Hello World
init Call1
Catched Call1 Exception:java.lang.NumberFormatException: For input string: "null"
init Run1
Exception in thread "Thread-0" java.lang.NumberFormatException: For input string: "run"
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.base/java.lang.Integer.parseInt(Integer.java:652)
	at java.base/java.lang.Integer.parseInt(Integer.java:770)
	at example.Run1.run(Run1.java:13)
	at java.base/java.lang.Thread.run(Thread.java:834)
```

うーむ。なぜCallableをRunnableに替える必要があったのか。