`

异常处理

    博客分类:
  • 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);
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

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

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

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

    MySQL中的异常处理是数据库编程中不可或缺的一部分,它允许开发者预设对可能出现的错误或异常的响应,从而确保程序的稳定性和健壮性。在MySQL中,异常定义和处理主要是通过`DECLARE`语句来实现的。 1. **异常定义**...

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

    异常处理是编程中的一种机制,用于捕获和处理运行时发生的错误或异常情况。异常可以由硬件引发,如硬件异常,也可以由操作系统或应用程序自身触发,即软件异常。当异常发生时,操作系统允许程序有机会检查异常类型并...

    易语言线程结构异常处理

    在易语言中,线程是并发执行的程序单位,线程结构异常处理是编程过程中非常重要的一环,因为线程可能会遇到各种异常情况,如内存访问错误、除零异常等。 线程结构异常处理源码是易语言中处理这些异常的关键部分。当...

    java异常处理习题

    Java 异常处理习题 Java 异常处理是 Java 编程语言中的一种重要机制,用于处理程序在运行时可能出现的错误或异常情况。下面是关于 Java 异常处理的习题和知识点总结: 一、Java 异常处理关键字 * Java 中用来抛出...

    易语言HOOK异常处理

    "New_SE_Handler"可能是一个新的结构化异常处理程序,结构化异常处理(SEH)是Windows操作系统中的一个特性,用于处理硬件和软件异常。 "GetSeAddr"可能是获取异常发生时的地址函数,这对于分析异常原因和定位问题...

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

    在编程领域,异常处理是确保程序健壮性与稳定性的关键技术。对于C、C++以及基于MFC(Microsoft Foundation Classes)的开发来说,异常处理更是不可或缺的一部分。本篇文章将深入浅析C、C++中的异常处理机制以及MFC中...

    详解SpringCloud Finchley Gateway 统一异常处理

    详解 SpringCloud Finchley Gateway 统一异常处理 SpringCloud Finchley Gateway 统一异常处理是指在使用 SpringCloud Finchley 版本的 Gateway 时,如何统一处理系统级异常的方法。默认情况下,SpringCloud ...

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

    【异常处理】是编程中必不可少的一个环节,尤其是在Java这样的面向对象语言中。异常处理机制使得程序在遇到错误时能够优雅地中断执行流程,提供错误信息,并有机会进行恢复操作,而不是简单地崩溃。以下是对异常处理...

    异常处理机制知识点小总结

    异常处理是Java编程中至关重要的一个概念,它确保了程序在遇到错误或异常情况时能够以优雅的方式继续执行或者终止。下面是对Java异常处理机制的详细解析。 在Java中,异常是程序运行时发生的错误,它中断了正常的...

    ARM处理器异常处理步骤

    ARM处理器异常处理是指ARM微处理器对各种异常情况作出响应和处理的过程。异常指的是处理器在正常执行程序时遇到的特殊情况,例如外部中断请求、未对齐的内存访问错误、指令预取终止等。为了保证系统的稳定性和正确性...

    Power builder9异常处理

    在 PowerBuilder 9(简称 PB9)开发过程中,异常处理是一项关键的技术,它能帮助开发者有效地管理和解决程序中出现的错误,确保系统的稳定运行。在实际应用中,开发者经常会遇到各种预知和不可预知的问题,如系统级...

    游标和异常处理 游标和异常处理

    游标和异常处理 游标是 SQL 的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将...

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

    《ADS异常处理详解》 异常处理是嵌入式系统中至关重要的部分,特别是在基于ARM架构的系统中。本文将深入探讨ARM处理器的异常处理机制,包括异常类型、处理流程、异常优先级以及向量表等内容。 一、异常类型 ARM...

    java实验报告4-异常处理

    Java异常处理是编程中至关重要的一个环节,它确保了程序在遇到错误时能够优雅地运行,而不是突然崩溃。本实验报告“java实验报告4-异常处理”旨在帮助初学者掌握Java中的异常处理机制,以及如何利用log4j进行日志...

    reactnative异常处理库

    React Native 异常处理库是专门为在React Native框架下开发的混合移动应用提供错误管理和调试支持的工具。React Native允许开发者使用JavaScript编写原生移动应用,但JavaScript代码的运行环境中可能会遇到各种错误...

    Spring Cloud Gateway的全局异常处理

    ### Spring Cloud Gateway全局异常处理详解 #### 一、引言 在微服务架构中,网关作为服务入口,承担着路由转发、限流熔断、鉴权认证等职责。Spring Cloud Gateway作为一款基于Spring Framework 5、Project Reactor...

    两数计算+异常处理

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

Global site tag (gtag.js) - Google Analytics