Java-07异常

一、异常引入

代码不能尽善尽美,如用户输入类型格式出错,找不到文件等不能避免异常的产生,影响用户体验,所以需要预处理,对能预料到的异常进行处理

(语法错误和逻辑错误不是异常)

异常事件分为error+exception(狭义的异常),出现error是程序员无法通过修改代码更正的,比如JVM系统内部错误、资源 耗尽等严重情况。一般不编写针对性 的代码进行处理。

对于这些异常,要不程序终止,要不程序员在编译的时候就考虑到这些异常并友好【提醒】处理

二、异常体系

异常exception分为编译器异常和运行期异常

1、编译器异常则设计代码的时候就要处理,不然编译不通过,但并不是一定有异常,但是编译就是不让你过,要不抛到主方法要不trycatch

2、运行期异常在编译的时候不会报错,运行才出现异常,一般不处理,若全处理可能会对 程序的可读性和运行效率产生影响。

Java-07异常

 

public class ExceptionTest {
    
    //******************以下是编译时异常***************************
    @Test
    public void test7(){
//        File file = new File("hello.txt");
//        FileInputStream fis = new FileInputStream(file);
//        
//        int data = fis.read();
//        while(data != -1){
//            System.out.print((char)data);
//            data = fis.read();
//        }
//        
//        fis.close();
        
    }
    
    //******************以下是运行时异常***************************
    //ArithmeticException
    @Test
    public void test6(){
        int a = 10;
        int b = 0;
        System.out.println(a / b);
    }
    
    //InputMismatchException
    @Test
    public void test5(){
        Scanner scanner = new Scanner(System.in);
        int score = scanner.nextInt();
        System.out.println(score);
        
        scanner.close();
    }
    
    //NumberFormatException
    @Test
    public void test4(){
        
        String str = "123";
        str = "abc";
        int num = Integer.parseInt(str);
        
        
        
    }
    
    //ClassCastException
    @Test
    public void test3(){
        Object obj = new Date();
        String str = (String)obj;
    }
    
    //IndexOutOfBoundsException
    @Test
    public void test2(){
        //ArrayIndexOutOfBoundsException
//        int[] arr = new int[10];
//        System.out.println(arr[10]);
        //StringIndexOutOfBoundsException
        String str = "abc";
        System.out.println(str.charAt(3));
    }
    
    //NullPointerException
    @Test
    public void test1(){
        
//        int[] arr = null;
//        System.out.println(arr[3]);
        
        String str = "abc";
        str = null;
        System.out.println(str.charAt(0));
        
    }
    
    
}

 三、异常处理方式

1、抓抛模型

过程一,抛:【系统自动/我们手动生成】异常对象并抛出,抛出后其后面的代码就不会执行了;

过程二,抓:【try-catch-finally或者throws】

try{
//可能出现异常的代码
} catch(异常类型1,变量名1){
//处理方法1
}catch(异常类型2,变量名2){
//处理方法2
}...
finally{
//一定会执行的代码
}

体会:

1、finally是可选的
2、catch匹配了异常类型就不往后走了,选择性,【但是finally里边的代码是一定会执行的,即使catch又出现了异常或者try和catch有return语句】
3、异常类型如果有继承关系,放置catch时候,子类放父类之前,否则报错,如果没有继承关系,先后无所谓
4、catch处理方法一般getMessage(),printStackTrace()
5、try中声明的变量,出了try就不能使用了,技巧:非要使用5的话,可以将变量声明在方法外,并赋予初始值
6、trycatchfinally处理机制,编译没有报错,但是运行不能保证不报错【比如catch本身也会有异常等】,而是把编译期可能出现的异常推迟到运行期,

开发中由于运行时异常比较常见,也不报错,不知道是不是异常了,所以一般不针对运行时异常编写try-catch-finally,针对编译异常就要处理
7、finally一般放一些像输入输出流,数据库连接,网络编程socket等,jvm不能自动回收,需要我们自己去手动操作
8、trycatchfinally可以相互嵌套

过程二处理方法1

public class Test {
    public static void main(String[] args) {
        System.out.println(method());
// java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 10 at demo01.Test.method(Test.java:11) at demo01.Test.main(Test.java:5)
//我一定会被执行
//3
    }
    public static 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;
        }

    }
}

过程二处理方法2

throws+异常类型或者其父类【因为子类重写了父类的方法】

向上抛,谁调用就抛给谁,可以同时抛出多个类型【如果处理不同,则需要分别异常处理】;最终只能抛到main方法,那么这时候main继续抛由jvm处理,要么就要用try-catch了
throws+异常类型此机制声明在方法处,相比trycatch,其后续代码会终止,而trycatch则是处理了异常,trycatch后面的代码会运行。
public class Demo01Throw {//parseexception是编译器异常,编译器必须改代码,否则编译不通过
    public static void main(String[] args) throws ParseException {//方法2=throws+异常类型,谁调用,抛给谁,虚拟机抛出异常,缺点是如果日期不符合pattern,则会终止抛出异常了
        System.out.println("=========编译期异常,2种处理方法=========");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = sdf.parse("2015-09-12");//这个方法本身是有异常,2种处理方法,1抛出,2try-catch
//        Date date = sdf.parse("2015-0912");//这个方法本身是有异常,2种处理方法,1抛出,2try-catch
        System.out.println(date);
        method2();
    }
    public static void method2(){//方法1,异常抛出,但是程序可以运行
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {//放可能异常的代码
            System.out.println("hello1");
            Date date = sdf.parse("2015-0912");
            System.out.println("hello2");

        } catch(NullPointerException e){
            System.out.println("hello3");
        } catch (ParseException e) {//符合了异常类型;

e.printStackTrace();//处理方法 } System.out.println("后续代码可以运行"); } }
public class Test {//运行期异常
    public static void main(String[] args) /*throws Exception*/{//main如果也向上抛,那么jvm抛异常就是越界异常,如果trycatch了,那么处理了异常,如果throws和trycatch一起了,那么trycatch会先捕捉并异常,也就不会有异常向上抛给jvm,

//i向上抛的异常必须大于等于method方法里的异常类型,这里的ArrayIndexOutOfBoundsException可以替换成exception
            //System.out.println("索引越界异常");

// System.out.println(method());//异常 try{ int[] arr = new int[10]; System.out.println(arr[10]); System.out.println(method()); }catch (ArrayIndexOutOfBoundsException e){//这里的异常类型必须罩住method抛出的异常
      // System.out.println(method());//catch自己也报异常,这样就会调升到运行期异常
      } 
}
public static int method() throws ArrayIndexOutOfBoundsException{//向上抛出异常,谁调用谁处理异常,main方法调用了必须得处理,注意的是此处的
   int[] arr = new int[10];
    System.
out.println(arr[10]);
    
return 1;
}
}

 

如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数

比 如 : 可 以 用 ArithmeticException 类 作 为 参 数 的 地 方 , 就 可 以 用 RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。 但不能是与ArithmeticException类无关的异常

 * 3. 开发中如何选择使用try-catch-finally 还是使用throws?【父类的异常类型必须大于等于子类的异常类型】
 *   3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果
 *       子类重写的方法中有异常,必须使用try-catch-finally方式处理。
 *   3.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws
 *       的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。》》最后再一起处理,同时如果第一个方法就trycatch那么第二个方法就不能使用到第一个方法的值了,这不好
 *   throws和trycatch语法上可以同时使用,但是没有必要,已经处理了为什么还要throws
 */
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 IOException{
        method1();
    }
    
    
    public static void method1() throws FileNotFoundException,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!");
    }
    
    
}

 2、手动生产异常对象throw

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 Runtimeexception("不能输入负数");//不会报错,编译能通过,因为是runtime异常,如果我们自己定义异常对象
//错误的 // throw new String("不能输入负数"); } } @Override public String toString() { return "Student [id=" + id + "]"; } }
/*
* 如何自定义异常类?
* 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 ReturnExceptionDemo {
    static void methodA() {
        try {
            System.out.println("进入方法A");//@1
            throw new RuntimeException("制造异常");@3
        } finally {
            System.out.println("用A方法的finally");//@2
        }
    }

    static void methodB() {
        try {
            System.out.println("进入方法B");@4
            return;
        } finally {
            System.out.println("调用B方法的finally");@5
        }
    }

    public static void main(String[] args) {
        try {
            methodA();
        } catch (Exception e) {
            System.out.println(e.getMessage());@3
        }          
        methodB();
    }
}

 

/*
练习:接收命令行的2个参数z(main非法的args),不能输入负数,计算2数相除的结果
对数据不一样(numberformatexception),缺少命令行参数(arrayindexoutofboundsexception),除0,以及输入负数(自定义)进行异常处理
 */
public class Demo04Throw {
    public static void main(String[] args) {


        try {
            int i =Integer.parseInt(args[0]);//用于输入2个参数通过命令行
            int j =Integer.parseInt(args[1]);
            //因为抛出了非运行期异常@three,必须抛出或者trycatch否则报错
            int result = ecm(i,j);
            System.out.println(result);
        } catch (EcDef e) {//定义的非负数
            System.out.println(e.getMessage());
        } catch (NumberFormatException e){//i j数据是非int类型
            System.out.println(e.getMessage());
        } catch (ArrayIndexOutOfBoundsException e){//缺少i,j 的值
            System.out.println(e.getMessage());
        } catch (ArithmeticException e){//除0异常
            System.out.println(e.getMessage());
        }

    }
    public static int ecm (int i,int j) throws EcDef{//抛出异常对象@two
        if(i<0||j<0){
            throw new EcDef("分子或分母为负数了");//产生了编译期异常对象@one
        }
        return i/j;
    }

}

public class EcDef extends Exception{
    static final long s=-3487;
    public EcDef(){

    }
    public EcDef(String msg){
        super(msg);
    }

}

 自定义的异常属于编译期异常

Java-07异常

上一篇:java基础


下一篇:从零搭建ssm整合环境(不使用springboot)图片纯享版