【Java基础】异常

常见异常

NullPointerException(空指针异常)

  • 当发现异常如s的值为null,启动异常处理机制,首先创建一个异常对象,查找看谁能处理这个异常,如果没有,则java启动默认处理机制,即打印异常栈信息到屏幕,并退出程序。
  • 异常栈信息包括了从异常发生点到最上层调用者的轨迹,还包括行号。

NumberFormatException(数字格式异常)

  • throw关键字可以与return关键字进行对比。return代表正常退出,throw代表异常
  • 异常处理机制会从当前函数开始查找看谁"捕获"了异常,当前函数没有就查看上一层,直到主函数,如果主函数也没有,就是用默认处理机制,即输出异常栈信息并退出。

异常类

NullPointerExcwption和NumberFormatException都是异常类,所有异常类都有一个公共的父类Throwable。

Throwable

  • Throwable有四个构造方法
public Throwable()
public Throwable(String message)
public Throwable(String message, Throwbale cause)
public Throwable(Throwable cause)
  • Throwable类有两个主要参数:一个是message,表示异常消息;另一个是cause,表示出发该异常的其他异常。
  • 异常可以形成一个异常链,上层的异常由底层异常触发,cause表示底层异常。
  • Throwable还有一个public方法用于设置cause:
  • Throwable initCause(Throwable cause)
  • Throwable的某些子类没有带cause参数的构造方法,就可以通过这个方法来设置,这个方法最多只能被调用一次。在所有构造方法的内部,都有一句重要的函数调用:
    • fillInStackTrace();
  • 它会将异常栈信息保存下来,这是我们看到异常栈的关键。
  • Throwable有一些常用方法用于获取异常信息,比如:
    • void printStackaTrace(PrintStream s)
    • void printStackTrace(PrintWriter s)
    • String getMessage() //获取设置的异常message
    • Throwable getCause() //获取异常的cause
    • //获取异常栈每一层的信息,每个StackTraceElement包括文件名、类名、函数名、行号等信息
    • StackTraceElement[] getStackTrace()

异常类体系:

  • Throwable是所有异常类的基类,它由两个子类:Error和Exception
    • Error表示系统错误或内存耗尽,由Java系统自己使用。
    • Exception表示应用程序错误,它有很多子类,也可以继承或其子类创建自定义异常。
  • Exception三个直接子类:
  • IOException(输入输出I/O异常)、Runtime Exception(运行时异常)、SQLException(数据库SQL异常)
  • 其中RuntimeException是未受检异常、Exception其他子类和它自身是受检异常(checked exception),Error子类及其自身也是未受检异常。
  • 受检和未受检区别在于Java如何处理这两种异常。
    • 受检异常,Java会强制要求程序员进行处理,否则会有编译错误。
    • 未受检异常,无此要求

自定义异常

  • 如果继承的是Exception及其子类,那么自定义异常是受检异常
  • 如果继承的是RuntimeException或其子类,那么自定义异常是未受检异常

异常处理

Java语言对异常处理的支持包括:

  • catch
  • throw
  • finally
  • try-with-resources
  • throws

catch匹配

  • 异常处理机制将根据抛出的异常类型找第一个匹配的catch块,找到后,执行catchk块内的岱庙,不再执行其他catchk块,如果没有找到,会继续到上层方法中查找。
  • 注:抛出的异常类型是catch种声明异常的子类也算匹配,所以需要将最具体的子类放在前面。
  • e.getMessage() //获取异常消息
  • e.printStackTrace() //打印异常栈到标准错误输出流
  • Java7的新语法,多个异常之间可以用"|"操作符

重新抛出异常

  • catch块内处理完后,可以重新抛出异常,异常可以是原来的,也可以是新建的。
  • 为什么重新抛出异常:当前代码不能够完全处理该异常,需要调用者进一步处理。
  • 为什么抛出新的异常:当前异常不合适,信息不够,需要补充信息;过于细节,不便于调用者理解和使用。

finally

  • finally内的代码不管有无异常发生,都会执行
    • 如果没有异常发生,再try内的代码执行结束后执行
    • 如果有异常发生且被catch捕获,再catch内的代码执行结束后执行。
    • 如果有异常发生但没被捕获,则在异常被抛给上层之前执行。
  • finally一般用于释放资源,如数据库连接、文件流等。

注:return和finally

  • 在tryh或者catch语句中有return语句,在finally执行结束后执行,但finally并不能改变返回值。
  • 这个函数的返回值是0,而不是2。实际执行的过程:在执行到try内的return ret;语句前,会先将返回值ret保存在一个临时变量中,然后才执行finally语句,最后try再返回那个临时变量,finally对ret的修改不会被改变。
public static int test(){
	int ret = 0;
	try{
		return ret;
	}finally{
		ret = 2;
	}
}
  • 在finally中也有return语句。try和catch内的return会丢失,实际会返回finally中的返回值。finally中return不仅会覆盖try和catch内的返回值,还会掩盖try和catch内的异常,就像没有异常发生一样。
  • 5/0会触发ArithmeticExceptiion,但finally中有return语句,这个方法就会返回2,而不是向上传递异常了。
public static int test(){
	int ret = 0;
	try{
		int a = 5/0
		return ret;
	}finally{
		ret = 2;
	}
}
  • finally中如果抛出异常,原异常也会被覆盖。
public static int test(){
   int ret = 0;
   try{
   	int a = 5/0
   	return ret;
   }finally{
   	throw new RuntimeException("hello");
   }
}

try-with-resources

对于资源的使用,如文件和数据库连接,典型的使用流程是首先要打开资源,最后在finally语句中调用资源关闭的方法,
针对这种场景,Java7开始支持一种新的语法,称之为try-with-resources,这种语法针对实现了javalang.AutoCloseable接口的对象。

public interface AutoCloseable{
	void close() throws Exception;
}

没有try-with-resource时:

public static void useResource() throws Exception{
	AutoCloseable r = new FileInputStream("hello");//创建资源
	try{
		//使用资源
	}finally{
		r.close();
	}
}

使用try-with-resource时:

public static viod useResource() throws Exception{
	try(AutoCloseable r = new FileInputStream("hello")){//创建资源
		//使用资源
	}
}
  • 资源声明的语句和初始化放在try语句内,不用再调用finally,在语句执行完try语句后会自动调用资源的close方法,资源可以定义多个,以分号分隔
  • Java 9之前,资源必须声明和初始化在try语句块内
  • Java 9,去除了这个限制,资源可以在try语句外被声明和初始化,但必须是final的或者是事实上final的(虽然没有声明为final,但也没有被重新赋值)

throws

  • throws用于声明一个方法可能抛出的异常。
  • throws跟在方法的括号后面, 可以声明多个异常,以逗号分隔
  • 这个声明的含义:这个方法内可能跑出这些异常,且没有对这些异常进行处理,至少没有处理完,调用者必须进行处理。
  • 对未受检异常,不要求使用throws进行声明的。
  • 对于受检异常,必须进行声明。不可以抛出而不声明,但可以声明抛出而不抛出。
  • 主要用于父类方法中的声明,父类方法内可能没有抛出,但子类重写方法后可能就抛出了,子类不能抛出父类方法中没有声明的异常,所以就将所有可能的抛出的异常就都写到父类上了。
public static viod useResource() throws AppException,SQLException, NumberFormatException{
		//主体代码
}

受检异常和未受检异常

  • 受检异常必须出现在throws语句中
  • 未受检异常表示程序的逻辑错误。【程序员应该解决代码bug而不是想办法处理异常】
  • 受检异常表示程序本身没问题,但 I/O、网络、数据库等其他不可预测的错误导致的。【调用者应当进行适当处理】
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值