`

异常处理

    博客分类:
  • Java
 
阅读更多

一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误。

 

异常处理正确的做法: 

低层次的方法抛出异常,让高层次的方法去捕获异常并通告用户发生了错误

  

未检查(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的全局异常处理 Spring Cloud Gateway中的全局异常处理不能直接用@ControllerAdvice来处理,通过跟踪异常信息的抛出,找到对应的源码,自定义一些处理逻辑来符合业务的需求。 网关都是给接口做...

    C#异常处理总结及简单实例

    C#异常处理总结及简单实例 一、异常处理的理解? 异常处理是指程序在运行过程中,发生错误会导致程序退出,这种错误,就叫做异常。 因此处理这种错误,就称为异常处理。 二、异常处理如何操作? C# 异常处理时建立在...

    异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt

    异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt异常处理.ppt

    两数计算+异常处理

    课程作业,实现两数计算及其异常处理,异常处理机制能让程序在异常发生时,按照代码的预先设定的异常处理逻辑,针对性地处理异常,让程序尽最大可能恢复正常并继续执行,且保持代码的清晰。 Java中的异常可以是函数...

    精讲RestTemplate自定义请求失败异常处理.docx

    在开始进行自定义的异常处理逻辑之前,我们有必要看一下异常处理的默认实现。也就是:为什么会产生上面小节提到的现象? ResponseErrorHandler是RestTemplate请求结果的异常处理器接口 o接口的第一个方法hasError...

    异常处理 异常处理 异常处理

    关于异常处理的word文档 关于异常处理的word文档 关于异常处理的word文档

    Springboot全局异常处理demo.zip

    Springboot全局异常处理demo 项目的开发中,不管是对底层的数据库操作过程,还是业务层的处理过程,还是控制层的处理过程,都不可避免会遇到各种可预知的、不可预知的异常需要处理。每个过程都单独处理异常,系统的...

    MySQL定义异常和异常处理详解

    主要为大家详细介绍了MySQL定义异常和异常处理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

    C和C++中的异常处理

    2. Microsoft 对异常处理方法的扩展 3. 标准 C++异常处理的基本语法和语义 4. 实例剖析 EH 5. C++的 new 和 delete 操作时的异常处理 6. Microsoft 对于的实现版本中的异常处理 7. 部分构造及 placement delete 8. ...

    C++ 异常处理 C++ 异常处理

    C++ 异常处理 C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理C++ 异常处理

    java异常处理java异常处理

    java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理java异常处理

    c/vc++/MFC异常处理/结构化异常处理 浅析

    c/vc++/结构化异常处理 浅析 C语言异常处理 C++语言异常处理 异常处理函数 MFC异常处理 结构化异常处理

    spingmvc+mybatis+统一异常处理机制

    统一异常处理会区分前端是否ajax请求,自动返回json数据格式,要求开发人员在处理ajax请求时统一封装成一个对象返回,以符合代码统一规范。 此工程在idea环境编写,导入请自己新建工程手工复制代码导入。

    易语言线程结构异常处理

    易语言线程结构异常处理源码,线程结构异常处理,SE保护内存读写,除0异常,十到十六,到十六进制文本,汇编_写到内存,指针到EXCEPTION_RECORD结构,指针到CONTEXT结构

    ADS异常处理.pptADS异常处理.pptADS异常处理.ppt

    ADS异常处理.pptADS异常处理.pptADS异常处理.ppt

    ARM异常处理机制ARM异常处理机制

    ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制ARM异常处理机制

    详解SpringCloud Finchley Gateway 统一异常处理

    主要介绍了详解SpringCloud Finchley Gateway 统一异常处理,非常具有实用价值,需要的朋友可以参考下

    工作流系统异常处理实现方法

    中的异常处理问题显得尤为突出[1-3]。传统上将异常处理包含于正常流程中的方法不仅不能 有效的处理各类异常,同时使得整个系统流程复杂化;而完全的人工参与也使得异常处理过 程效率低下,形式极不规范。所以,工作...

    第7章 java异常处理

    第7章 java异常处理

    SQLserver存储过程异常处理.txt

    SQLserver存储过程异常处理

Global site tag (gtag.js) - Google Analytics