一、异常处理:
1、
package com.atguigu.exception;
import java.util.Scanner;
import org.junit.Test;
public class TestException {
// @Test //直接在@Test上点击导包就可以
// public void test1() {
//
// Scanner s=new Scanner(System.in);
// int i=s.nextInt();
// System.out.println(i);
// }
//常见的运行时异常
//1、数组下标越界的异常
@Test
public void test2() {
}
}
2、
try{ //try把可能出现异常的代码包起来,方便判断
//存放可能出现异常的代码
}catch(Exception1 e1){ //如果异常时Exception1类型的,则执行处理方式1
//处理的方式1
} catch(Exception2 e2){ //如果异常是Exception2类型的,则执行处理方式2
//处理的方式2
}
…………………….
finally{
//不管怎样,一定会被执行的代码(不管异常如何,finally方法体中的代码是一定要执行的)
}
注:1、try内声明的变量,类似于局部变量,出了try{}语句,就不能被调用
2、finally是可选的。(类似于switch( ){ }语句内的default语句)。
3、可以有多个catch语句,try中抛出的异常类对象从上到下去匹配catch中的异常类的类型,一旦满足就执行catch中的代码。执行完,就跳出其后的多条catch语句。
4、如果异常在catch语句中能够抛出异常,那么try-catch语句外的代码还可以照常执行。因为try-catch异常处理完后,又回归了正常。(如果异常处理了,以后的代码可正常执行)。
5、若catch中多个异常类型是”并列关系”,孰上孰下都可以
若catch中多个异常类习惯是”包含”的关系,须将子类放在父类的上面,进行处理。否则报错。
6、finally中存放的是一定会被执行的代码,不管try中、catch中是否仍有异常未被执行,以及是否有return语句。finally内的语句在try{ }catch( ){ }...中的return语句前执行。
7、try-catch是可以相互嵌套的。类似if-else……。
、例如数组下标越界的异常:ArrayIndexOutOfBoundsException(讲解:ArrayIndexOutOfBoundsException的父类异常叫IndexOutOfBoundsException;
IndexOutOfBoundsException的父类异常叫OutOfBoundsException;…最终的祖先是Exception异常,即Exception异常是所有异常的父类。像ArrayIndexOutOfBoundsException等是具体的异常名)。
实例解释:
package com.atguigu.exception;
import java.util.InputMismatchException;
import java.util.Scanner;
import org.junit.Test;
public class Example {
@Test
public void test1(){
Scanner s=new Scanner(System.in);
try {
int i=s.nextInt();
System.out.println(i);
}catch (InputMismatchException e) {
// TODO: handle exception
System.out.println("出现类型不匹配的异常!");
}
}
}
运行结果:
ewe
出现类型不匹配的异常!
3、
try{}catch(){}的快捷键:Alt+Shift+Z(可以选中一片,然后右键Surround With来添加try-catch)。
try{ } catch( ){ } catch( ){ }类似于if( ){ } else if( ){ } else if( ){ }…
try中有错误执行第一个catch,如果第一个catch执行发现了错误,那么第二个catch就不会再执行了。
4、对于运行时异常来说,可以不显式的进行处理;对于编译异常来说,必须要显式地进行处理。
5、finally:
package finally00;
public class Testfinally {
public static void main(String[] args) {
int i=method();
System.out.println(i);
}
public static int method() {
/*
* 正常讲,try中的return会返回并跳出method方法,但是finally内部是一定会执行的,
* 就会先不返回1;而是执行finally内部的语句,finally内部的语句又会return 2;所以结果。
*加入try语句中存在异常,就会先执行catch内的语句,然后再执行finally内的语句。
* */
try {
//.........
return 1;
} catch (Exception e) {
e.printStackTrace();
}finally {
System.out.println("彼此各自安好!");
return 2;
}
}
}
结果:(程序一旦遇到return就会跳出当前的方法,)
彼此各自安好!
2
会报错:因为在rty-catch中存在return语句,在try-catch外再写语句也不会执行;写任何语句都没用了。
异常处理方式二:
未使用抛出异常的情况;
使用第二种抛出方式:throws ……
Method1( )中出现的异常解决不了抛给method2( );method2( )也解决不了此异常,并抛给了main( )方法;main( )方法也解决不了此异常就抛给了虚拟机。
一个地区(method1( )方法)的案子(异常)办不了,上报给了市里(method2()方法);市里发现这个案子(异常)市里也办不了,交给了省里(main方法),省里发现也办不了就交给了国家部门(虚拟机)。
异常处理的方式二:在方法的声明处,显式的抛出该异常对象的类型。
1、格式:如:public static void method1() throws FileNotFoundException,IOException{ }
2、当在此方法内部出现异常的时候,会抛出一个异常类的对象,抛给方法的调用者。
3、 异常的对象可以依次向上抛,直至main中;在向上抛的过程中可以再通过try-catch-finally进行处理。
4、抛出异常的两种方式:try-catch可以看作解决问题的;而throws则是回避问题的方式。
5、代码证明:
package finally00;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 异常处理的方式二:在方法的声明处,显式的抛出该异常对象的类型。
* 格式:如:public static void method1() throws FileNotFoundException,IOException{ }
* 当在此方法内部出现异常的时候,会抛出一个异常类的对象,抛给方法的调用者。
* 异常的对象可以依次向上抛,直至main中;在向上抛的过程中可以再通过try-catch-finally进行处理。
*抛出异常的两种方式:try-catch可以看作解决问题的;而throws则是回避问题的方式。
* */
public class TestException {
public static void main(String[] args) throws FileNotFoundException,IOException{
try {
method2();
} catch (FileNotFoundException e) {
// TODO: handle exception
System.out.println(e.getMessage());
}catch(IOException e) {
e.printStackTrace();
}
}
public static void method2() throws FileNotFoundException,IOException{
try {
method1();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public static void method1() throws FileNotFoundException,IOException{
FileInputStream fis=new FileInputStream(new File("hello.txt"));
int b;
while((b=fis.read())!=-1) {
System.out.println((char)b);
}
fis.close();
}
}
二、总结:
Java的异常处理:抓抛模型
- 抓:异常的处理:有两种方式(①、try-catch-finally;②、throws+异常的类型)
- 抛:一旦执行过程中,出现异常,会抛出一个异常类的对象。(自动抛出 vs 手动的抛出(throw + 异常类的对象))。
三、新知识点:
1、手动的抛出异常的例子:(throw new Exception(“传入的类型有误!”);)
抛出的异常类既可以是系统自带的异常类,也可以是自己造的异常类。
2、自定义异常类:(自定义的异常类用class …,一般自定义的异常类都继承并重写Exception;因为Exception是所有异常类的父类)
①、
package exception;
/*
*如何定义一个异常类:
* 1、自定义的异常类继承现有的异常类
* 2、提供一个序列号,提供几个重载的构造器
* */
public class MyException extends Exception{
/* 如果extends的是Exception或IOException则在TestStudent里需要显式的抛出异常(用public void register(int id)throw MyException)*/
static final long serialVersionUID=-70348975766939L;
public MyException() {
}
public MyException(String msg) {
super(msg);
}
}
②、
package exception;
public class TestStudent {
public static void main(String[] args) {
Student s=new Student();
try {
s.regist(-12);
System.out.println(s); //放在此处的,如果有异常的话就不会打印id
} catch (MyException e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
// System.out.println(s); //如果是写在这里,不管有没有异常都会打印id
}
}
class Student{
int id;
/* 如果extends的是Exception或IOException则在TestStudent里需要显式的抛出异常(用public void register(int id)throw MyException)*/
public void regist(int id) throws MyException{
if(id>0) {
this.id=id;
}else {
throw new MyException("传入的学号有误!");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
- 抛异常的方法的重写原则:
重写:存在继承的类中;
子类抛出的异常的类型要小于或等于继承的父类的异常;
如果大于父类抛出异常的类型是错误的。
代码:
package exception;
import java.io.IOException;
/*
* 重写:存在继承的类中;
* 子类抛出的异常的类型要小于或等于继承的父类的异常;
* 如果大于父类抛出异常的类型是错误的。
* */
public class TestOverride {
public static void main(String[] args) {
A a=new B(); //编译时看左边是A类型
try {
a.method1();//因为method1()抛出的类型为IOException类型,所以catch的为IOException
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class A{
public void method1() throws IOException{//或者FileNotFoundException等
}
}
class B extends A{
public void method1() throws IOException{
}
}
四、异常处理的总结:
情况一:
package exception;
public class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally{
System.out.println("用A方法的finally");
// TODO: handle exception
}
}
static void methodB() {
try {
System.out.println("进入方法B");
return ;
} finally {
System.out.println("调用B方法的finally");
// TODO: handle finally clause
}
}
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
// TODO: handle exception
}
methodB();
}
}
结果:
进入方法A
用A方法的finally
制造异常
进入方法B
调用B方法的finally
情况二:
package exception;
public class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally{
System.out.println("用A方法的finally");
// TODO: handle exception
}
}
static int methodB() {
try {
System.out.println("进入方法B");
return 1+1;
} finally {
System.out.println("调用B方法的finally");
// TODO: handle finally clause
}
}
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
// TODO: handle exception
}
int i=methodB();
System.out.println(i);
}
}
结果:
进入方法A
用A方法的finally
制造异常
进入方法B
调用B方法的finally
2
情况二:
package exception;
public class ReturnExceptionDemo {
static void methodA() {
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally{
System.out.println("用A方法的finally");
// TODO: handle exception
}
}
static int methodB() {
try {
System.out.println("进入方法B");
return 1+1;
} finally {
System.out.println("调用B方法的finally");
return 3;
// TODO: handle finally clause
}
}
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
// TODO: handle exception
}
int i=methodB();
System.out.println(i);
}
}
结果:
进入方法A
用A方法的finally
制造异常
进入方法B
调用B方法的finally
3
五、异常处理的综合练习:
运行时因为有:int i=Integer.parseInt(args[0]);所以在运行时应该是用:右键--Run As--Run Configurations然后在Arguments栏目中输入两个需要的参数(因为int 了i和j)
package Exception00.exec;
public class EcmDef {
public static void main(String[] args) {
try {
int i=Integer.parseInt(args[0]);//被除数
int j=Integer.parseInt(args[1]);//除数
ecm(i,j);
}catch(NumberFormatException e){
System.out.println("输入的数据类型不一致");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("缺少命令行参数");
}catch(ArithmeticException e){
System.out.println("分母为0了");
}catch(EcDef e) {
System.out.println(e.getMessage());
}
}
public static void ecm(int i,int j) throws EcDef{//利用的是throws来抛出异常,谁调用的cem抛出的异常就传给谁
if(i<0 || j<0) {
throw new EcDef("您输入的数值存在负数的错误!");
}
else {
System.out.println(i/j);
}
}
}
//自定义异常类
class EcDef extends Exception{
static final long serialVersionUID=-3387524229948L;
public EcDef() {
}
public EcDef(String msg) {
super(msg);
}
}
运行时因为有:int i=Integer.parseInt(args[0]);所以在运行时应该是用:右键--Run As--Run Configurations然后在Arguments栏目中输入两个需要的参数(因为int 了i和j)
package Exception00.exec;
public class EcmDef {
public static void main(String[] args) {
try {
int i=Integer.parseInt(args[0]);//被除数
int j=Integer.parseInt(args[1]);//除数
ecm(i,j);
}catch(NumberFormatException e){
System.out.println("输入的数据类型不一致");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("缺少命令行参数");
}catch(ArithmeticException e){
System.out.println("分母为0了");
}catch(EcDef e) {
System.out.println(e.getMessage());
}
}
public static void ecm(int i,int j) throws EcDef{//利用的是throws来抛出异常,谁调用的cem抛出的异常就传给谁
if(i<0 || j<0) {
throw new EcDef("您输入的数值存在负数的错误!");
}
else {
System.out.println(i/j);
}
}
}
//自定义异常类
class EcDef extends Exception{
static final long serialVersionUID=-3387524229948L;
public EcDef() {
}
public EcDef(String msg) {
super(msg);
}
}