Java基础系列七之异常Exception

① Java异常机制相关关键字

Java异常机制相关关键字有: trycatchfinallythrowthrows
关键字解释:

  • try 用于监听. 将被监听的代码(可能抛出异常的代码)放在try语句块之内, 当try语句块内发生异常时,异常就被抛出.
  • catch 用来捕获try语句块中发生的异常.
  • finally finally语句块总是会被执行. 主要用于回收在try块里打开的物理资源(如文件, 网络连接, 数据库连接等).

finally语句中return

只有finally块执行完成之后,才会执行try或者catch块中的return或者throw语句. 如果finally中使用了return或者throw等终止方法的语句,则就不会跳回执行,直接停止.

  • throw 用于抛出异常.
  • throws 用在方法签名中,用于声明该方法可能抛出的异常.

② Java异常框架

Java将可抛出(Throwable)的结构分为三种类型:

  • 编译异常(Checked Exception)
  • 运行时异常(RuntimeException)
  • 错误(Error)

Java异常框架继承关系如图: 
图15-1

1.Throwable

ThrowableJava语言中所有错误或异常的超类, 包含两个子类:ErrorException.它们通常用于指示发生了异常情况.Throwable包含了其线程创建时线程执行堆栈的快照,提供了printStackTrace()等接口用于获取堆栈跟踪数据等信息.

2.运行时异常RuntimeException

RuntimeException是那些可能在Java虚拟机正常运行期间抛出的异常的超类, 简称运行时异常. RuntimeException及其子类都被称为运行时异常.

Java编译器不会检查运行时异常.当程序中可能出现这类异常时,倘若既”没有通过throws声明抛出它”,也”没有用try-catch语句捕获它”,还是会编译通过.

虽然Java编译器不会检查运行时异常, 但是我们也可以通过throws进行声明抛出, 也可以通过try-catch对它进行捕获处理. 如果产生运行时异常,则需要通过修改代码来进行避免.

例如: 
* 除数为零时产生的ArithmeticException异常 
* 数组越界时产生的IndexOutOfBoundsException异常 
* fail-fail机制产生的ConcurrentModificationException异常等,都属于运行时异常.

部分常用运行时异常说明
异常 描述
ArithmeticException 除数为零异常
ArrayIndexOutOfBoundsException 数组越界
ClassCastException 对象转型错误
IllegalArgumentException 参数不合法
IndexOutOfBoundsException 指示某排序索引(例如对数组、字符串或向量的排序)超出范围
NegativeArraySizeException 数组长度为负值
NullPointerException 空指针异常
NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常.

3.编译异常Exception

Exception类以及Exception的子类中除了”运行时异常”之外的其它子类都属于被检查异常. 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译.

部分常用编译异常说明
异常 描述
ClassNotFoundException 应用程序试图加载类时,找不到相应的类,抛出该异常.
FileNotFoundException 文件不存在异常
ClassCastException 对象转型错误
InterruptedException 一个线程被另一个线程中断,抛出该异常.
NoSuchFieldException 请求的变量不存在
NoSuchMethodException 请求的方法不存在

4.Error

Error类及其子类统称错误. 用于指示试图捕获的严重问题, 大多数这样的错误都是异常条件. 和运行时异常一样, 编译器也不会检查Error. 当资源不足、约束失败、或是其它导致程序无法继续运行的条件发生时, 就产生错误. 程序本身无法修复这些错误.

例:

  • VirtualMachineError就属于错误.

  • 按照Java惯例, 不应该实现任何新的Error子类, 需要自定义异常可以采用Exception类.

到底该哪一种异常?

对于可以恢复的条件使用被检查异常,对于程序错误使用运行时异常.虚拟机及系统错误采用Error.

③ 捕获异常

使用trycatch关键字可以捕获异常.try/catch代码块放在异常可能发生的地方.

语法如下:

try {
    /** 程序代码*/
} catch (Exception e) {
    /** 异常处理*/
}
  • 1
  • 2
  • 3
  • 4
  • 5
一个`try`代码块后面跟随多个`catch`代码块的情况就叫多重捕获. 可以在 try 语句后面添加任意数量的 catch 块. 如果保护代码中发生异常,异常被抛给第一个 catch 块. 如果抛出异常的数据类型与捕获异常类型匹配, 就会被捕获. 如果不匹配,它会被传递给下一个`catch`块.直到异常被捕获或者通过所有的`catch`块. 语法如下:
try {
    /** 程序代码*/
} catch (Exception1 e) {
    /** 异常处理*/
} catch (Exception1 e) {
    /** 异常处理*/
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

④ 抛出异常

可以使用throw关键字抛出一个异常.

public static void testThrow() {
    /** 方法体*/
    throw new NullPointerException();
}
  • 1
  • 2
  • 3
  • 4
如果一个方法没有捕获一个`编译异常`, 那么该方法必须使用`throws`关键字来声明. `throws`关键字放在方法签名的尾部. 示例代码:
public static void testThrows() throws NullPointerException {
    /** 方法体*/
}
  • 1
  • 2
  • 3
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开. 例如,下面的方法声明抛出`NullPointerException`和`ArithmeticException` 示例代码:
public static void testThrows() throws NullPointerException, ArithmeticException {
    /** 方法体*/
}
  • 1
  • 2
  • 3

⑤ finally关键字

finally关键字用来创建在try代码块后面执行的代码块. 无论是否发生异常,finally代码块中的代码总会被执行. 在finally代码块中,可以运关闭链接, 释放系统资源等必须要执行的语句.

finally代码块出现在catch代码块最后.

语法如下:

try {
    /** 方法体*/
} catch (Exception e) {
    /** 异常处理*/
} finally {
    /** finally语句*/
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

finally块并非强制添加,但是try代码块后面不能既没有catch块也没有finally块

代码示例

package exception;

public class ArithmeticDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a = 66;
		int b = 0;
		try {
			System.out.println(a / b);
		} catch (ArithmeticException e) {
			// TODO: handle exception
			//用输出语句来处理异常
			System.out.println("除数不能为0");
			e.printStackTrace();
		} finally {
			// TODO: handle finally clause
			System.out.println("run finally");
		}
		System.out.println("over");
	}

}

如何处理多个异常 两个或两个以上的异常怎么处理?

try{
  可能出现问题的代码
   int[] arr = {1,2,3} ;
   Sop(arr[3]);
   int a = 10 ;
   int b =0 ;
  Sop(a/b) ;
 
  
   }catch(异常类名1 对象名1){
   //异常处理
   }catch(异常类名2 对象名2(){
 
   //异常处理

  }

代码示例

package exception;

public class ExceptionDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		method();
	}

	private static void method() {
		int a = 11;
		int b = 0;
		int[] array = { 1, 2, 3 };
		try {
			System.out.println(array[3]);
			System.out.println(a / b);
			System.out.println("代码到这一步可能出现问题,怎么办?");
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("访问了数组中不存在的角标");
			e.printStackTrace();
		} catch (ArithmeticException e) {
			// TODO: handle exception
			System.out.println("除数不能为0");
			e.printStackTrace();
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("程序出问题了");
		} finally {
			System.out.println("run finally");
		}
	}
}
Jdk7以后出现了另外一种方式来处理多个异常
 try{
可能出现问题的代码;
  }catch(异常类名1 | 异常类名2 |... 对象名){
  
  处理异常
  }
代码示例
package exception;

public class ExceptionDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		method();
	}

	private static void method() {
		int a = 11;
		int b = 0;
		int[] array = { 1, 2, 3 };
		try {
			// sSystem.out.println(array[3]);
			System.out.println(a / b);
			System.out.println("代码到这一步可能出现问题,怎么办?");
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
			// TODO: handle exception
			System.out.println("程序出现异常了");
			e.printStackTrace();
		}
	}
}
编译时期异常和运行时期异常的区别?
编译时期异常:开发者必须进行显示处理,如果不处理,编译不能通过,
   运行时期异常:不需要进行显示处理,但是也可以像编译时期异常一样进行处理
  处理异常的第二种方式:使用throws 抛出异常 (跟在方法的后面)
  xxx 返回值  方法名() throws  异常类名{

  }

代码示例

package exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ExceptionDemo2 {

	public static void main(String[] args) throws ParseException {
		// TODO Auto-generated method stub
		System.out.println("今天天气很好!");
		method2();
		method1();
		System.out.println("但是不该有雾霾....");

	}

	private static void method1() {
		int a = 10;
		int b = 0;
		try {
			System.out.println(a / b);
		} catch (ArithmeticException e) {
			// TODO: handle exception
			System.out.println("除数不能为0");
			e.printStackTrace();
		}
	}

	private static void method2() throws ParseException {
		String string = "2018-5-17";
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		Date date = simpleDateFormat.parse(string);
		System.out.println("date" + date);

	}
}

标准格式 try{ ... }catch(异常类 对象){ // 异常处理 } 

执行try里面的代码,如果出现了问题,它会创建一个异常类的对象,然后判断异常类对象的类型和catch里面的异常类

是否一致

如果一致的情况,就会执行catch里面的代码,执行Throwable里面的方法

public String getMessage() :消息字符串   例如: Unparseable date: "2018-6-20"

public String toString(): 异常的简短描述 ":   例如:  java.text.ParseException: Unparseable date: "2018-6-20"

public void printStackTrace():返回值void   直接调用

包含了toString(),出现的异常在源码中的行数以及在本程序中的行数

例如: java.text.ParseException: Unparseable date: "2018-6-20"
at java.text.DateFormat.parse(DateFormat.java:366)

at exception.Exception.main(Exception.java:13)

面试题:

final,finally,finalize的区别?

final: 可以修饰类,该类不能被继承;可以修饰变量,该变量是常量;可以修饰成员方法,该方法重写
finalize: gc():运行垃圾回收器,实际是调用finalize()方法,和垃圾回收器有关系
finally:在io,数据库中以及后面对数据库操作(DBUtuls/c3p0/Hibernate/MyBatis)里面中释放资源的

代码示例

package exception;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Exception {

	public static void main(String[] args) {
		try {
			String string = "2018-6-20";
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
			Date date = simpleDateFormat.parse(string);
			System.out.println(date);
		} catch (ParseException e) {
			// TODO: handle exception
			String string = e.getMessage();
			System.out.println(string);
			String string2 = e.toString();
			System.out.println(string2);
			e.printStackTrace();
		}
		System.out.println("日期解析完毕!!!");
		System.out.println("------------------------------");
		try {
			String string = "2018-6-6";
			SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
			Date date = simpleDateFormat.parse(string);
			System.out.println(date);
			System.exit(0);// 终止当前正在运行的Java虚拟机,如果没有出现解析异常,则直接执行exit(0),不再执行finally块中的代码
		} catch (ParseException e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			System.out.println("这里释放资源......");
		}
	}
}
throw:表示也是抛出异常,抛出的一个异常对象 (throw new 异常类名() :匿名对象的方式)

 面试题:
  throws和throw的区别?
  throws:也是表示抛出异常,它后面跟的异常类名,并且可以多个异常类名中间逗号开
  举例:
  public void show() throws IoException,ClassNotFoundException{...}
  在方法上抛出,由调用者处理
  它抛出可能出现的异常
  throw:抛出的一个异常对象
  在语句体中抛出的,由语句体进行处理
  它抛出肯定出现的异常

代码示例

package Exception;

public class Exception1 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			method();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}

	private static void method2() throws Exception {
		int a = 10;
		int b = 0;
		if (b == 0) {
			throw new Exception();
		} else {
			System.out.println(a / b);
		}
	}

	private static void method() {
		int a = 10;
		int b = 0;
		if (b == 0) {
			throw new ArithmeticException();
		} else {
			System.out.println(a / b);
		}
	}
}
try...catch...finally
  finally语句体是一定会执行的,除非终止JVM的运行  System.exit(0); 
 
 面试题:
  如果catch里面有return语句,finally中的代码还会执行,是在return语句之前执行还是return后执行?
  finally中代码是一定会执行的,在return前执行,如果先执行return则方法终止运行,finally块就不会运行,与规则冲突,所以return是一个方法体最后执行的部分,它的后面不会再执行任何操作

try的代码出现问题了,执行catch中的语句,30赋值a,
* return 30(已经形成了一个回路径)finally代码一定会执行(除非Jvm) a = 40 ,在fianlly外面
* 有return a: a记录的是回路径的那个a(30),所以返回30

package Exception;

public class Exception2 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(getInt());
	}

	private static int getInt() {
		int a;
		try {
			a = 10;
			System.out.println(a / 0);
			a = 20;
		} catch (Exception e) {
			// TODO: handle exception
			a = 30;
			return a;// 形成回路径
		} finally {
			a = 40;
			System.out.println("执行了finally  a:" + a);
		}
		return a;// 返回回路径a(30)
	}
}

如何自定义一个异常类?

代码示例

package Exception;

public class Teacher {
	public static void check(int score) throws MyException {
		if (score < 0 || score > 100) {
			throw new MyException("该学生成绩有问题...");
		} else {
			System.out.println("该学生成绩没有问题...");
		}
	}
}

package Exception;

public class MyException extends Exception {

	public MyException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public MyException(String message) {
		super(message);
	}
}
package Exception;

import java.util.Scanner;

public class Demo {

	private static Scanner in;

	public static void main(String[] args) throws MyException {
		in = new Scanner(System.in);
		System.out.println("请输入学生成绩:");
		int score = in.nextInt();
		Teacher teacher = new Teacher();
		Teacher.check(score);
	}

}
异常中的注意事项:
  子类继承父类的时候的注意事项 
  1)子类重写父类的方法的时候,子类方法抛出的异常要么和父类方法抛出的异常一样,要么是父类方法抛出的异常的子类

  2)子类重写父类方法的时候,如果父类中的这个方法没有抛出异常,那么子类重写的这个方法也不能抛出异常,只能try...catch

代码示例

package Exception;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Demo1 {
	public static void main(String[] args) {
		Zi aZi = new Zi();
		aZi.method();
	}
}

class Fu {
	public void show() throws Exception {

	}

	public void method() {

	}
}

class Zi extends Fu {

	@Override
	public void show() throws ArithmeticException {

	}

	@Override
	public void method() {
		try {
			String str = "2018-5-13";
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			Date d = sdf.parse(str);
			System.out.println(d);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}




猜你喜欢

转载自blog.csdn.net/qq_40727767/article/details/80357178