【知晓的丧day拯救计划】java基础学习笔记20 异常

笔记来自2019求知讲堂零基础Java入门编程视频教程 https://www.bilibili.com/video/av76235341

java异常

java程序在运行时发生的不正常的情况被称为“异常”。这些异常事件大体可以分为两类:

  • error:JVM系统内部错误、资源耗尽等严重错误(栈溢出StackOverflowError、内存溢出OutOfMemoryError)
  • Exception:其他因编程错误或偶然的外在因素导致的一般性问题,包括
    ○ RuntimeException(运行时异常:空指针、数组下标越界、错误的类型转换等)。
    ○ CheckedException(已检查异常:IOException、SQLException等以及用户自定义的Exception异常)

运行时异常RuntimeException可以提前通过逻辑判断避免
已检查异常在编译时必须通过try-catch处理,否则不能编译

数组下标越界异常ArrayIndexOutOfBoundsException

String[] strs = new String[]{"a","b","c"};
for (int i = 0; i < 4; i++){  //strs数组中没有第四个元素,strs[3]不存在
	System.out.println(strs[i]);
}

空指针异常NullPointException

//类A中有一个属性i
A a = null;
System.out.println(a.i);  //引用变量a没有指向任何对象,自然也没有i的值

//处理
A a = null;
if(a != null){
	System.out.println(a.i);
}

错误运算 ArithmeticException

int i = 0;
System.out.println(3/i);  //除数不能为0

//处理
int i = 0;
if(i != 0){
	System.out.println(3/i);
}

类型转换异常ClassCastException

Animal a = new Dog();
Cat c = (Cat)a;

//处理:使用instanceof判断是否为相应类的对象
Animal a = new Dog();
if(a instanceof Cat){
	Cat c = (Cat)a;
}

数字格式异常NumberFormatException

String str = "abc";
System.out.println(Integer.parseInt(str));

//处理:引入正则表达式判断是否为数字

异常处理机制

捕获异常最理想的是在编译期间(eclipse等集成开发环境可以发现编译期异常),但有的错误只能在运行时才会发生,对于这些错误,有两种解决办法:

  • 遇到错误就终止程序的运行
  • 由程序员在编写时就考虑到的,可以进行错误的检测、错误消息提示和错误的处理。

有些时候,可以在编写时在容易出现错误的地方加上检测代码,比如判断分母是否为零,输入是否为空等。但过多的分支会导致程序代码加长,可读性差。所以针对异常可以采用异常处理机制。

java的异常处理机制,将异常处理的程序代码集中在一起,与正常代码分开,使得程序简洁,并易于维护。

抓抛模型

java提供的异常处理的抓(捕获)抛(抛出)模型。

如果在程序运行时出现异常,会自动生成一个异常类对象,该异常类对象将被提交给Java运行时系统,这个过程叫做抛出(throw)异常。

如果一个方法内抛出异常,该异常会被抛到调用方法中。如果这个异常没有在调用方法中处理,它将继续被抛给调用这个方法的调用者,这个过程将一直继续,直到异常被处理,这一过程叫做捕获(catch)异常。如果一个异常抛回到main()方法也没有被处理,则运行终止。

  • try{}
    捕获异常的第一步是用try{…}语句块选定捕获异常的范围,也就是将可能发生异常的代码放到try语句块之中。
  • catch(Exceptiontype e){…}
    catch语句的参数是可能捕获的异常类对象,如果明确的知道会发生何种异常,应该用该异常类作为catch的参数,如果不明确,也可以使用其父类作为catch的参数。比如分母可能为0时,可以使用ArithmeticException类作为参数,也可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能使用与ArithmeticException类无关的异常,如果用NullPointerException类作为参数则无法正确捕获异常。
    catch语句块中是在try语句块中发生异常后,对异常对象进行处理的代码,每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
  • finally{…}
    捕获异常的最后一步可以通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其他部分以前,能够对程序的状态做统一的管理。不论在try-catch语句块中是否发生异常事件,finally语句块中的代码都会被执行。(finally语句不是必须的)
    finally语句常用在打开外部连接的异常处理中,无论是否有异常,都要在最后关闭资源。

try-catch

try{
	//可能出现异常的语句(该代码块中出现异常之后的语句不再执行)
}catch(Exception e){ //捕获的异常类对象,若不知道具体类型,可以使用所有异常类的父类Exception
	//发生异常后执行的语句,若没有异常不执行
}

try-catch-finally

try{
	//可能出现异常的语句
}catch(ExceptionName1 e){ 
	//发生ExceptionName1类型异常后执行的语句,若没有该异常不执行
}catch(ExceptionName2 e){ 
	//发生ExceptionName2类型异常后执行的语句,若没有该异常不执行
}finally{
	//无条件执行语句,不论上述异常是否发生
}
  • getMessage()方法:用来得到有关异常事件的信息
  • printStackTrace()方法:用来跟踪异常事件发生时,执行堆栈的内容。
  • try语句块中遇到异常之后,其后面的代码就不再运行了。
public class Test {
	public static void main(String[] args) {
		int i = 0;
		String[] strs = new String[] {"a","b"};
		//使用try{}catch(){}之后,发生异常不会影响后续代码运行
		try {//用try{}来括住一段有可能出现异常的代码段
			System.out.println(strs[2]);  //数组下标越界
			System.out.println(3/i);      //分母为0
		}catch(ArithmeticException e1) {//catch的参数是捕获的异常类对象,这里是运算错误
			e1.printStackTrace(); //输出捕获的异常及其所在的位置
			System.out.println(e1.getMessage());  //输出有关异常的信息
			System.out.println("运算错误");
		}catch(IndexOutOfBoundsException e) {//数组下标越界
			e.printStackTrace(); 
			System.out.println(e.getMessage());  
			System.out.println("数组下标越界");
		}finally {
			System.out.println("finally");
		}
		System.out.println("ok");
	}
}
/**
* 运行结果:
* java.lang.ArrayIndexOutOfBoundsException: 2
* 	at exception.Test.main(Test.java:9)
* 2
* 数组下标越界
* finally
* ok
*/	
  • throws
    也可以使用throws在方法中抛出异常,在调用方法的地方进行捕获。
    继承关系上,重写方法不能抛出比被重写方法范围更大的异常

throws

public class Test1 {
	public static void main(String[] args) {
		B b = new B();
		//调用test方法时,由于该方法抛出了异常,所以要对该方法进行异常捕获,否则会报错
		try {
			b.test();
		}catch(Exception e) {
			e.printStackTrace();
		}
	}

}

class B{
	int i;
	//test方法中可能存在空指针异常,但没有在方法中捕获,而是抛出给调用方
	public void test() throws Exception{ //throws后是抛出的异常类型,也可以是所有异常的父类
		B b = null;
		System.out.println(b.i);
	}
}

try-with-resource 自动关闭资源

Java中JVM的垃圾回收机制可以自动回收内部资源,给开发者提供很多便利,但JVM对外部资源的引用却无法实现自动回收,例如数据库连接、网络连接以及IO流等。这些连接需要手动关闭,否则会导致资源泄露、连接池溢出、文件被异常占用等问题。

JDK7之后,新增了“try-with-resource”,他可以自动关闭实现了AutoClosable接口的类,实现类需要实现接口中的close()方法。
“try-with-resource”实际上就是将涉及关闭资源时的“try-catch-finally”简化为“try-catch”,实现了自动关闭则不需要finally语句了。(这只是编写代码时的省略,在编译时仍会转化为“try-catch-finally”执行)

语法格式
将打开连接的代码写在try后的一个小括号里,以分号结束

import java.io.FileReader;

public class TestNewTryCatch {
	public static void main(String[] args) {
		try(FileReader reader = new FileReader("f:\\test.txt");){
			char c = (char)reader.read();
			char c2 = (char)reader.read();
			System.out.println("" + c + c2);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}

人工抛出异常

Java异常类对象除了在异常发生时由系统自动生成并抛出,也可以根据需要由人工创建并抛出。
首先要生成异常类对象,然后通过throw语句实现抛出操作。抛出的异常必须是Throwable或其子类的实例。
语法:
Exception e = new Exception;
throw e;

public class Test1 {
	public static void main(String[] args) {
		B b = new B();
		//调用test1()方法时,需要捕获异常
		try {
			b.test1(160);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}
		
	}

}

class B{
	int age;
	//方法test1(),判断输入的年龄是否在0-150之间,不是则抛出异常
	public void test1(int age) throws Exception{  //异常抛给方法调用者
		if(age >= 0 && age < 150) {
			System.out.println("年龄:" + age);
		}else {
			//创建一个异常类对象
			throw new Exception("年龄不在0-150之间");
		}
	}
}

运行结果:
在这里插入图片描述

创建用户自定义异常类

用户自定义异常类必须继承现有异常类。

public class Test1 {
	public static void main(String[] args) {
		B b = new B();
		try {
			b.test2(160);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println(e.getMessage());
		}		
	}
}

class B{
	int age;
	public void test2(int age) throws MyException{
		if(age >= 0 && age < 150) {
			System.out.println("年龄:" + age);
		}else {
			throw new MyException("年龄不在0-150之间");
		}
	}
}

//自定义异常类,继承父类的构造方法,参数是输出的异常信息
class MyException extends Exception{
	public MyException(String msg) {
		super(msg);
		
	}
}

运行结果
在这里插入图片描述

可以看出虽然错误信息相同,但抛出异常的类不再是java.lang.Exception,而是我们自定义的MyException。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值