Java小技能:异常处理

97 阅读5分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 27 天,点击查看活动详情

前言

exception是java中的完美机制之一。 方法在执行的过程中由于某种原因而不能正常的达到目的,这样的现象称为异常。

本文主要介绍异常的处理方式、异常的分类、自定义异常。

I 异常的处理方式

1.1 抛异常

在发生的方法行为中,将异常传递出去,交由其他地方处理。

修饰符  返回值类型 方法名(参数列表) throws 异常类名,异常类名{
//类体
}

在方法定义中声明throws异常类名。

1.2 捕捉异常

异常在方法中发生后,立即对其采取处理。

try{
//语句块
}catch(异常类名 变量名){
//异常的处理,替代方案
}catch(异常类名 变量名){
//异常的处理,替代方案
}finally{
//代码块
}  
  1. 捕捉异常的优先顺序:

catch块中是需要捕捉的异常,捕捉按照小类型到大类型的顺序捕捉,不能倒置;

如果捕捉的异常存在继承关系,应该先捕捉小类型,再捕捉大类型的异常。若不存在继承关系,那么无捕捉的优先顺序。

  1. try, catch ,finally的个数:

try只能有一个;catch可以有,也可以没有;finally也可以有没有;

但catch和finally至少出现一个。

  1. catch块的执行顺序:

如果在捕捉异常的过程中,若有多个catch块,按照从上到下的顺序执行catch块;

若有一个catch块被执行,其他catch就不会被执行;finally总是会被执行。

1.3 抛异常和捕获异常的区别

  • 捕获异常:当前行为发生异常之后,能够寻求替代方案,继续完成当前的行为。
  • 抛异常:当行为发生异常之后,在当前行为中,无法寻找替代方案,需要将异常抛出。

1.4 产生异常

throw new 异常类名();

有很多的异常在API中已产生

发生异常,代码以后的执行顺序:

  1. 如果使用try{}catch 方式处理异常,当前代码位于try块中;如果当前代码发生了异常后,在try块且位于当前代码之后的代码不会被执行,直接进入catch块中;执行完catch块,继续执行后面的代码。
  2. 若使用throws处理异常时,当前代码在执行过程中发生异常之后,位于当前代码以后的所有语句都将不会被执行。
package com.csuinfosoft.grammer.exceptionDemo;
/**
 * 
 * @author 工号:ios逆向
 * try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会被执行,
 * finally {}里的code在return执行后,finally {}执行完在返回结果。
 * 具体看test1和test2的区别。 
 * 如果finally,有return语句,就直接结束方法。
 * 如果finally,没return语句,就再次返回return处来结束方法。
 */
public class ExceptionDemo {
	     public static void main(String[] args) {
			System.out.println(ExceptionDemo.test1());//1
			System.out.println(ExceptionDemo.test2());//2
	     }
	     static int test1(){
	          int x = 1;
	          int y=1;
	          try
	          {
	              return x;//执行后,跳到finally执行。此时放回结果已经压入的栈中,结果为1
	          }
	          finally
	          {
	        	  x=x+1;//finally执行完又跳回来执行return语句。此时的局部变量x=2.
	          }
	     }
	     static int test2(){
	          int x = 1;
	          try
	          {
	              return x;//执行后,跳到finally执行。此时放回结果已经压入的栈中,结果为1
	          }
	          finally
	          {
	        	  return x=x+1;//finally执行完,直接返回结果。此时再次向栈中压入放回结果2。
	          }
	     }
}

II 异常分类

2.1 异常的选择

  • 跟内存有关的异常,通常使用运行时异常;
  • 跟内存以外有关的异常,通常使用编译时异常。

2.2 编译时异常与运行时异常的语法检查区别

  • 编译时异常
  1. 编译时异常的javac过程的语法检查步骤:

a. 检查代码中是否有异常产生 b. 检查异常是否被处理 注:以上两步缺一不可,如果缺失就会提示语法错误。

  1. 编译时异常,如果没有产生异常,就不能去捕捉。在IDE中,如果产生捕捉时将提示如此信息:

Unreachable catch block for ActivationException. This exception is never thrown from the try statement body。

  • 运行时异常
  1. 运行时异常,可以在没产生异常时,在代码中可以进行捕获。
  2. 因为运行时异常不参与语法检查, 运行时异常无论在代码中产生异常或者处理异常都可通过语法检查。

III 自定义的异常

目的:能够给用户提供更准确的提示信息,改善用户体验。

3.1 如何自定义异常?

  • 需要继承异常父类(Exception或RuntimeException)
  • 提供对应的构造器
  • 在对应的构造器调用父类对应的构造器

3.2 自定义异常示例

package exception;
/**
 * 
 * @author 张坤楠
 *自定义DAO层的异常,一般DAO层的异常,都封装成统一的DAOException在抛向BIZ层。
 *这里定义的是编译时异常。
 */
public class DAOException extends Exception {
	/**
	 *  构造详细消息为 null 的新异常
	 */
	public DAOException() {
		super();
	}
	/**
	 * 
	 * @param message
	 * @param cause
	 * @param enableSuppression
	 * @param writableStackTrace
	 */
	public DAOException(String message, Throwable cause,
			boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
	}
	/**
	 * 构造带指定详细消息和原因的新异常。
	 * @param message
	 * @param cause
	 */
	public DAOException(String message, Throwable cause) {
		super(message, cause);
	}
	/**
	 * 构造带指定详细消息的新异常。
	 * @param message
	 */
	public DAOException(String message) {
		super(message);
	}
	/**
	 * 根据指定的原因和 (cause==null ? null : cause.toString()) 的详细消息构造新异常(它通常包含 cause 的类和详细消息)。
	 * @param cause
	 */
	public DAOException(Throwable cause) {
		super(cause);
	}
}

IV http请求返回详细错误信息

@ExceptionHandler拦截500服务器错误,自定义数据回前端。


@ControllerAdvice
public class CommonExceptionAdvice {

@ResponseBody
    @ExceptionHandler(value = {Exception.class})
    public ServerResponse globalError(HttpServletRequest request, Exception e) {
        if (userSentinel) {
            Tracer.trace(e);
        }
        // 输出控制台打印日志
        log.error(CommonMethod.getTrace(e));

        // 返回前端提示信息
        //return ServerResponse.createByError("500", "未知错误!");
        //开发阶段先返回详细错误信息
        return ServerResponse.createByError("500", CommonMethod.getTrace(e));
    }
}

获取详细错误信息

    public static String getTrace(Throwable t) {
        StringWriter stringWriter = new StringWriter();
        PrintWriter writer = new PrintWriter(stringWriter);
        t.printStackTrace(writer);
        StringBuffer buffer = stringWriter.getBuffer();
        return buffer.toString();
    }