异常
+-------------------------------+
| Throwable |
| / |
| / |
| Error Exception |
| / |
| / |
| Runtime Other |
+-------------------------------+
-
Runtime Exception是unchecked未受检异常,Other是checked检查异常。通常在程序中处理的都是受检异常。
-
Exception类是应该被程序捕获处理的;而Error同样也可以被捕获,但通常是JVM出现异常,这些严重的问题程序不应该捕获。所以不能直接捕获Throwable,而应该具体到Exception类。
受检异常和非受检异常
-
受检异常 Other Exception
Java 在编译时就验证受检异常。 因此我们需要抛出或者捕获处理这些异常。
常见的受检异常有IOException 、 SQLException 和 ParseException
我们可以通过继承 Exception 类来实现自定义的受检异常
-
非受检异常 Runtime Exception
Java 不会在编译时验证非经受检的异常。这类异常通常反映了程序逻辑的一些错误。
不受检我们也就不用捕获和抛出,但是运行时如果有错将会抛出异常。
常见的是是 NullPointerException 、 ArrayIndexOutOfBoundsException 和 IllegalArgumentException 、ArithmeticException
我们可以通过继承 RuntimeException 来实现自定义的非受检异常
-
什么时候使用受检异常,什么时候使用非受检异常?
“如果可以合理地期望客户端从异常中恢复,请将其设为已检查的异常。 如果客户端无法从异常中恢复,请将其设为非经检查的异常。” -Oracle
try-with-source
java7引入,我们可以在try后括号内声明和初始化资源,执行完try块资源将自动关闭。
- 资源必须实现了AutoCloseable或Closeable接口
- 要自动关闭,必须在括号内声明和初始化资源
- 可以声明多个资源,用分号分隔
- 先声明的资源先初始化,但最后关闭
全局异常捕获
自从1.5开始,Java 的 Thread 类中提供了 UncaughtExceptionHandler 接口。
@FunctionalInterface
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(
new RuntimePermission("setDefaultUncaughtExceptionHandler")
);
}
defaultUncaughtExceptionHandler = eh;
}
要使用java提供的全局异常处理,我们需要实现一个 UncaughtExceptionHandler 的 Handler 类,并实现 uncaughtException 方法,该线程非被捕获的异常都将在这里处理,通常我们进行日志记录。然后线程有一个 defaultUncaughtExceptionHandler 属性,我们要将其设置为我们实现的 Handler 类。看看具体怎么做:
public class Test {
public static void main(String[] args) {
Handler globalExceptionHandler = new Handler();
Thread.setDefaultUncaughtExceptionHandler(globalExceptionHandler);
System.out.println(10/0);
}
}
class Handler implements Thread.UncaughtExceptionHandler {
private static Logger LOGGER = LoggerFactory.getLogger(Handler.class);
public void uncaughtException(Thread t, Throwable e) {
LOGGER.info("Unhandled exception caught!");
}
}
Runtime异常都可以被捕获,受检异常也可以抛出给它处理。
不过,这打破了就近捕获和处理异常的规则,在很多框架中都使用了全局异常。