一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误。
异常处理正确的做法:
低层次的方法抛出异常,让高层次的方法去捕获异常并通告用户发生了错误
未检查(unchecked)异常:
派生于Error类或RuntimeException类的所有异常
异常处理方式:
声明异常(推荐做法),即在方法上声明可能发生的已检查异常,交给上层方法去处理。
捕获异常,可以捕获后对异常进行包装,抛给上层方法;或者对异常进行适当处理后不抛出。
一般原则:应该捕获那些知道如何处理的异常,而将那些不知道怎样处理的异常传递出去
子类中覆盖了超类的一个方法,子类方法中声明的已检查异常不能超过超类方法中声明的异常范围。
不允许在子类的throws说明符中出现超过超类方法所列出的异常类范围:
如,Runnable中的run()就不能抛出任何已检查的异常,必须捕获所有checkedException并处理。
catch块捕获异常后如何处理?
1. 直接处理异常
2. 直接抛出,或者包装后抛出,或者抛出自定义异常
3. 异常链,通过堆栈记录所有异常信息
finally 确保系统资源被释放
finally中如果包含return语句:
方法返回的是finally中return的值(try块中return的值被覆盖了)。
处理异常的几个例子:
sample1:资源释放与异常捕捉分开写,结构更清晰
public static void main(String[] args) { try { InputStream in = null; try { in = new FileInputStream(new File("")); //read data from stream } finally { in.close(); } } catch(Exception e) { e.printStackTrace(); } }
sample2:InterruptedException的两种处理方式
public static void t1() { Thread t = new Thread(new Runnable() { int i = 1; @Override public void run() { //循环检测线程是否已被中断 while(!Thread.currentThread().isInterrupted() && i<1000) { System.out.println(i++); try { Thread.sleep(100); } catch (InterruptedException e) { //设置中断标记,下次检测此标记结束循环 Thread.currentThread().interrupt(); } } } }); t.start(); for(int i=0;i<10000;i++){System.out.print("");} t.interrupt(); } public static void t2() { Thread t = new Thread(new Runnable() { int i = 1; @Override public void run() { try { while(i<1000) { System.out.println(i++); Thread.sleep(100); } } catch (InterruptedException e) { //没有状态检测的情况下,打印异常,直接退出 e.printStackTrace(); } } }); t.start(); for(int i=0;i<10000;i++){System.out.print("");} t.interrupt(); }
sample3, 自定义异常
public class AppException extends Throwable { private static final long serialVersionUID = 9168776604038242476L; public AppException() { super(); } //异常消息+异常链 public AppException(String message, Throwable cause) { super(message, cause); } //异常消息【如果不想打印出异常链,就使用这个构造方法】 public AppException(String message) { super(message); } //异常链 public AppException(Throwable cause) { super(cause); } }
未捕获异常处理器
线程的run方法不能抛出任何被检测的异常, 这些异常必须被处理。
但是,仍然会发生一些不被检测的异常,最终导致线程终止。
现在就要开始处理这些未捕获的异常。
Java对这些unchecked异常(RuntimeException、Error)是怎么处理的呢?
在线程死亡之前,异常被传递到一个用于未捕获异常的处理器。
该处理器必须实现一个接口:Thread.UncaughtExceptionHandler
从Java SE 5.0起, 可以用setUncaughtExceptionHandler方法为任何线程安装一个处理器;
Thread类的静态方法setDefaultUncaughtExceptionHandler为所有线程安装一个默认的处理器。
独立线程默认的处理器就是该线程的ThreadGroup对象。默认所有线程都在同一个线程组。
ThreadGroup类实现Thread.UncaughtExceptionHandler接口,uncaughtException方法做如下操作:
1)如果该线程组有父线程组,那么父线程组的uncaughtException方法被调用。
2)否则,如果Thread设置了默认处理器,则调用该处理器。
3)否则,如果Throwable是ThreadDeath的一个实例(由stop方法生成),什么都不做。
4)否则,线程的名字以及Throwable的栈踪迹被输出到System.err上。
/** * 实现接口Thread.UncaughtExceptionHandler * 未捕获异常处理器 */ public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { static { //为所有线程设置默认处理器【对线程池中的线程,此设置无效】 Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); } public static void main(String[] args) { int i = Integer.parseInt("Hello"); System.out.println(i); } @Override public void uncaughtException(Thread t, Throwable e) { //处理未被捕获的异常 if(e!=null) logToFile(e); } public static void logToFile(Throwable t) { try { File log = new File("exception.log"); FileWriter fw = new FileWriter(log, true); PrintWriter pw = new PrintWriter(fw,true); t.printStackTrace(pw); } catch (IOException e) { e.printStackTrace(); } } }
线程池中未捕获的异常消失了
线程池中未捕获异常的处理(即catch块没有捕获到的异常)
普通线程池,如singlePool,cachedPool,fixedPool
如果通过execute()执行任务,未检查异常会被自动抛出
如果通过submit()提交任务,异常只能通过future.get()被调用时才会抛出,如果没有调用get(),异常将不会出现,即异常消失了!
对于任务调度线程池执行任务时发生的异常,如scheduledPool
execute() 不会抛出异常信息,如果catch块没有捕获,则发生的异常将消失
submit(), schedule() 异常信息将在get()被调用时抛出
还有一种更好的处理方式:对上述2种不同的线程池都可以获取到异常。
线程池对未捕获异常的处理提供了外部接口,通过覆盖afterExecute()来自定义未捕获异常的处理行为:
第一步,自定义线程池类,继承concurrent包中某个线程池即可;
第二步,覆盖afterExecute(),处理未捕获的异常。
import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class MyThreadPoolExecutor extends ThreadPoolExecutor { public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> blockingQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, blockingQueue); } //处理未捕获异常 protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (t == null && r instanceof Future) { try { Object result = ((Future) r).get(); } catch (CancellationException ce) { t = ce; } catch (ExecutionException ee) { t = ee.getCause(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // ignore/reset } } if (t != null) ExcRecorder.logAll(t); } } class MyScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor { public MyScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize); } //处理未捕获异常 protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); if (t == null && r instanceof Future) { try { Object result = ((Future) r).get(); } catch (CancellationException ce) { t = ce; } catch (ExecutionException ee) { t = ee.getCause(); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); // ignore/reset } } if (t != null) ExcRecorder.logAll(t); } } class ExcRecorder { public static void logCosole(Throwable t) { t.printStackTrace(); } public static void logToFile(Throwable t) { try { File log = new File("exception.log"); FileWriter fw = new FileWriter(log, true); PrintWriter pw = new PrintWriter(fw,true); t.printStackTrace(pw); } catch (IOException e) { e.printStackTrace(); } } public static void listStackTace(Throwable t) { StringBuilder builder = new StringBuilder(); @SuppressWarnings("restriction") String newLine = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("line.separator")); builder.append(t.getClass().getName()+":"+t.getMessage()).append(newLine); for(StackTraceElement st : t.getStackTrace()) { builder.append("\t"); builder.append(st.toString()); builder.append(newLine); } System.out.println(builder.toString()); } public static void logAll(Throwable t) { logCosole(t); logToFile(t); listStackTace(t); } }
相关推荐
Spring Cloud Gateway的全局异常处理 Spring Cloud Gateway中的全局异常处理不能直接用@ControllerAdvice来处理,通过跟踪异常信息的抛出,找到对应的源码,自定义一些处理逻辑来符合业务的需求。 网关都是给接口做...
C#异常处理总结及简单实例 一、异常处理的理解? 异常处理是指程序在运行过程中,发生错误会导致程序退出,这种错误,就叫做异常。 因此处理这种错误,就称为异常处理。 二、异常处理如何操作? C# 异常处理时建立在...
异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt
课程作业,实现两数计算及其异常处理,异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。 Java中的异常可以是函数...
在开始进行自定义的异常处理逻辑之前,我们有必要看一下异常处理的默认实现。也就是:为什么会产生上面小节提到的现象? ResponseErrorHandler是RestTemplate请求结果的异常处理器接口 o接口的第一个方法hasError...
关于异常处理的word文档 关于异常处理的word文档 关于异常处理的word文档
Springboot全局异常处理demo 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的...
主要为大家详细介绍了MySQL定义异常和异常处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
2. Microsoft 对异常处理方法的扩展 3. 标准 C++异常处理的基本语法和语义 4. 实例剖析 EH 5. C++的 new 和 delete 操作时的异常处理 6. Microsoft 对于的实现版本中的异常处理 7. 部分构造及 placement delete 8. ...
C++ 异常处理 C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理
java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理
c/vc++/结构化异常处理 浅析 C语言异常处理 C++语言异常处理 异常处理函数 MFC异常处理 结构化异常处理
统一异常处理会区分前端是否ajax请求,自动返回json数据格式,要求开发人员在处理ajax请求时统一封装成一个对象返回,以符合代码统一规范。 此工程在idea环境编写,导入请自己新建工程手工复制代码导入。
易语言线程结构异常处理源码,线程结构异常处理,SE保护内存读写,除0异常,十到十六,到十六进制文本,汇编_写到内存,指针到EXCEPTION_RECORD结构,指针到CONTEXT结构
ADS异常处理.pptADS异常处理.pptADS异常处理.ppt
ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制
主要介绍了详解SpringCloud Finchley Gateway 统一异常处理,非常具有实用价值,需要的朋友可以参考下
中的异常处理问题显得尤为突出[1-3]。传统上将异常处理包含于正常流程中的方法不仅不能 有效的处理各类异常,同时使得整个系统流程复杂化;而完全的人工参与也使得异常处理过 程效率低下,形式极不规范。所以,工作...
第7章 java异常处理
SQLserver存储过程异常处理