异常处理
异常体系:
Error是指java虚拟机无法解决的严重问题;如JVM系统内部错误、资源耗尽等严重情况;比如:StrackOverflowError、OOM(OutOfMemoryError)(主要就是看后面带Error就是错误)。
java.lang.Throwable
|-----java.lang.Error:一般不编写针对性的代码进行处理。
|-----java.lang.Exception:可以进行异常的处理
|------编译时异常(checked)
|-----IOException
|-----FileNotFoundException
|-----ClassNotFoundException
|------运行时异常(unchecked,RuntimeException)
|-----NullPointerException
|-----ArrayIndexOutOfBoundsException
|-----ClassCastException
|-----NumberFormatException
|-----InputMismatchException
|-----ArithmeticException
public class MyExceptionTest1 {
@Test
public void test() {
FileInputStream fis = null;
try {
File file = new File("hello.txt");
fis = new FileInputStream(file);
int date = fis.read();
while(date != -1) {
System.out.print((char)date);
date = fis.read();
}
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(IOException e) {
e.printStackTrace();
}finally {
while(fis != null) {
try {
fis.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2() {
//ArrayIndexOutOfBoundsException;
int[] arr = new int[5];
System.out.println(arr[5]);
//NullPointerException
int[] arr2 = null;
System.out.println(arr2[0]);
}
@Test
public void test3() {
// NumberFormatException
String str = "abc";
int a = Integer.parseInt(str);
}
//ClassCastException
@Test
public void test4(){
Object obj = new Date();
String str = (String)obj;
}
//ArithmeticException
@Test
public void test5(){
int a = 10;
int b = 0;
System.out.println(a / b);
}
//InputMismatchException
@Test
public void test6(){
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();
System.out.println(score);
scanner.close();
}
}
抓抛模型:
抓:程序正常执行的过程中,如果出现异常就会在异常代码处产生一个对应异常类的异常对象,并抛出;并且其后的代码不会再执行。
关于异常的产生:
①系统自动生成的异常对象;
②手动生成的异常类的对象,并抛出(throw)
抓:抓可以理解成异常的处理方式:
①try-catch-finally
②throws
try{ //可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}
…
finally{
//一定会执行的代码
}
说明:
①finally是可选的;
②使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常就会生成一个对应异常类的对象,根据此对象 的类型,去catch中进行匹配;
③一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的try-catch结构(在没有写finally的情况)。继续执行后面的代码,如果有finally先执行finally中的代码。
④catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
⑤常用的异常处理方式:一、String getMessage();二、printStrackTrace()。
⑥try结构中声明的变量在出了try结构之后就不能再进行调用。
⑦try-catch-finally结构可以嵌套
体会1:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。
finally使用:
①finally是可选的;
②finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
③像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。
public class FinallyTest {
@Test
public void test2(){
FileInputStream fis = null;
try {
File file = new File("hello1.txt");
fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test
public void testMethod(){
int num = method();
System.out.println(num);
}
public int method(){
try{
int[] arr = new int[10];
System.out.println(arr[10]);
return 1;
}catch(ArrayIndexOutOfBoundsException e){
e.printStackTrace();
return 2;
}finally{
System.out.println("我一定会被执行");
return 3;
}
}
@Test
public void test1(){
try{
int a = 10;
int b = 0;
System.out.println(a / b);
}catch(ArithmeticException e){
e.printStackTrace();
// int[] arr = new int[10];
// System.out.println(arr[10]);
}catch(Exception e){
e.printStackTrace();
}
// System.out.println("我好帅啊!!!~~");
finally{
System.out.println("我好帅啊~~");
}
System.out.println("wo zai na");
}
}
异常处理的方式二:throws+异常类型
1、“throws+异常类型”写在方法的声明出。指明方法执行时可能会出现的异常。
当方法体执行时,出现了异常,还是会在异常代码处生成一个异常类的对象,此对象满足throws后的异常类型时,就会被抛出。异常代码后的代码就不会再执行。
2、体会:try-catch-finally:真正的将异常给处理掉了。throws的方式只是将异常抛给了方法的调用者。 并没有真正将异常处理掉。
3、开发中如何选择使用try-catch-finally 还是使用throws?
3.1、如果父类中被重写的方法没有用throws的方式处理异常,则子类中重写的方法也不能够使用throws的方式进行处理。也就是说,如果父类没有使用throws,子类对异常的处理只能使用try-catch-finally的方式。
3.2、如果要执行的方法a中先后调用了另外几个方法,且这些方法之间存在递进关系,一般建议调用的方法使用throws进行处理,而执行方法a使用try进行处理。(这不单单是为了方便和节省内存考虑,有时如果method1中出现异常可能导致method2中需要的数据并没有生成,但如果使用try处理,那么执行方法a就不会再处理而是直接执行下面的程序;)
public class ExceptionTest2 {
public static void main(String[] args){
try{
method2();
}catch(IOException e){
e.printStackTrace();
}
// method3();
}
public static void method3(){
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method2() throws FileNotFoundException,IOException{
method1();
}
public static void method1() throws IOException{
File file = new File("hello1.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
fis.close();
System.out.println("hahaha!");
}
}
方法重写的规则之一:
子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型;
(如果大于父类中的异常类型,父类就处理不了。)
如何自定义异常:
1、继承现有的异常体系,一般是RunTimeException和Exception;
2、提供全局常量:serialVersionUID
3、提供重载的构造器;
public class MyException extends Exception{
static final long serialVersionUID = -7034897193246939L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}
体会手动抛出异常:
public class StudentTest {
public static void main(String[] args) {
try {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
// System.out.println("您输入的数据非法!");
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
// throw new Exception("您输入的数据非法!");
throw new MyException("不能输入负数");
//错误的
// throw new String("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
执行的先后顺序判别:
public class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally {
System.out.println("用A方法的finally");
}
}
static void methodB() {
try {
System.out.println("进入方法B");
return;
} finally {
System.out.println("调用B方法的finally");
}
}
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
}
methodB();
}
}