Java异常处理

1.abstract能修饰哪些结构?修饰以后有什么特点?

修饰 类、方法。

修饰以后,类不饿能实例化,提供子类,子类可以实例化。

抽象方法所在的类一定是抽象类。只定义了一种功能的标准。具体的执行,需要子类去实现。

2.接口是否能继承接口? 能,体现接口与接口之间的关系。

抽象类能否实现(implements)接口? 能。能够重写接口中的一些方法,然后进行实例化。

抽象类能否继承非抽象的类? 能。一个抽象类没有明确指明父类,那父类就是Object类。

非抽象的类能继承抽象的类,就是要通过子类实例化来调用抽象类的结构。

3. 声明抽象类,并包含抽象方法。测试类中创建一个继承抽象类的匿名子类的对象。

abstract AA{

        public abstract void m();

}

main{

        AA a = new AA(){     //a是匿名子类的对象

                public void m(){

                        

                        }

        };

        a.m();

}

class Person{

        String name;

        public void eat(){ }

}

main(){

        Person p = new Person(){

                public void eat(){}   //调用的是这行方法。

        };

        p.eat();

}

4.抽象类和接口有哪些共同点和区别?

共同点:

        不能实例化。需要提供他们的子类和实现类,进行实例化。

        都可以被继承。

区别:

        抽象类种可以有抽象方法和普通方法,但是接口种只能有抽象方法和全局常量。

        接口:全局常量,抽象方法,静态方法,默认方法。

        不同点:抽象类:有构造器。接口:不能声明构造器。

        单继承、多继承。

5.如何创建静态成员内部类和非静态成员内部类的对象?

Person 有静态类static Dog  和非静态类 Bird

创建:

        Person.Dog dog = new Person.Dog();

        vs

        Person p = new Person();

        Person.Bird bird = p.new Person.Bird();

abstract抽象的

可以用来修饰:类、方法

具体的:

        1.修饰的类,叫抽象类:不能进行实例化。

                抽象类中一定有构造器,便于子类实例化时调用。(涉及:子类实例化的全过程)

                开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作。--->抽象的使用前提:继承性。

        2.修饰的方法,叫抽象方法:只有抽象的方法,没有方法体。

                包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法。

                若子类重写了父类中的所有的抽象方法后,此子类方可实例化。

                若子类没有重写父类中的所有抽象方法,则此子类也是一个抽象类,需用abstract修饰。

注意点:

        1.abstract不能用来修饰:属性,构造器等结构。

        2.abstract不能用来修饰私方法、静态方法、final的方法、final的类。

因为静态方法不能被重写。

abstract的应用举例

内部类

类的第五个成员

1.定义:Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类。

2.内部类的分类:成员内部类(静态、非静态)和局部内部类(方法内、代码块内、构造器内)。

3.成员内部类的理解:

一方面,作为外部类的成员:

                1.调用外部类的结构。

                2.可以被static修饰。

                3.可以被4种不同的权限修饰。

另一方面,作为一个类:

                1.类内可以定义属性,方法,构造器等。

                2.可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承。

                3.可以被abstract修饰。

4.成员内部类:

4.1如何创建成员内部类的对象?(静态,非静态)

//创建静态Dog实例,(静态成员内部类)

Person.Dog dog = new Person.Dog();

//

//创建非静态Bird实例(非静态成员内部类)

Person p = new Person();

Person.Bird b = p.new Bird();

4.2 如何在成员内部类种调用外部类的结构?

class Person{

        String name = "xiaoming";

        public void eat(){

        }

        //非静态成员内部类

        class Bird{

                String name = "dujuan";

                public void display(String name){

                        System.out.println(name);  //方法的形参;

                        System.out.println(this.name); //内部类的属性;

                        System.out.println(Person.this.name); //外部类的属性;以上是有重名的情况下。没有重名情况下,可以省略;

                        eat();  //此为省略写法,Person.this.eat();

                }

        }

}

5.局部内部类的使用:

//返回一个实现类接口Comparable接口的类的对象

public Comparable getComparable(){

        //创建了一个实现Comparable接口的类:局部内部类

        //方式一:

        class MyComparable implements Comparable{

                @Override

                public int compareTo(Object o){

                        return 0;

                }

        }

        return new MyComparable();

        //方式二:

        return new Comparable(){

                @Override

                public int compareTo(Object o){

                        return 0;

                }

        }

}

总结:

成员内部类和局部内部类,在编译以后,都会生成字节码文件。

格式:成员内部类:外部类$内部类名.class

          局部内部类:外部类$数字 内部类名.class

public class innerClass_ {
        /**
         * 在局部内部类的方法中,(比如:show)如果调用局部内部类所声明的方法(比如:method)中的局部变量(比如:name)
         * 要求此局部变量声明为 final
         *
         * jdk7及之前的版本:要求声明为显示的final
         * jdk8及以后版本:可以省略final的声明
         */
        public void method(){
            int num = 10;
            class AA{
                public void show(){
//                    num = 20;    //可以使用方法中的局部变量,但是不能修改。
                    System.out.println(num);
                }
            }
        }
}

1.异常处理

1.1异常概述与异常体系结构

有一些问题不能能够靠代码就能解决的,比如:客户输入数据的格式,读取文件是否存在,网络是否始终保持通常等。

1.1.1异常定义:

        在Java语言中,将程序执行过程中发生的不正常的情况称为“异常”。

(开发过程中的语法错误和逻辑错误不是异常

1.1.2异常分类:在执行过程中(广义上的异常)

  • Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。比如:StackOverflowErrorOOM。一般不编写针对性的代码进行处理。
  • Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
    • 空指针访问
    • 试图读取不存在的文件
    • 网络连接中断
    • 数组角标越界

由于我们对于error一般不进行处理,所以一般我们称Exception为异常(狭义)。

例子:

package com.liu.jav;

/**
 * Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源耗尽等严重情况。
 * 比如:StackOverflowError和OOM( java.lang.OutOfMemoryError)。一般不编写针对性的代码进行处理。
 */
public class ErrorTest {
    public static void main(String[] args) {
        //1.栈溢出:java.lang.StackOverflowError
//        main(args);
        //2.堆溢出:java.lang.OutOfMemoryError  heap space
        Integer[] arr = new Integer[1024*1024*1024];
    }
}
  • 对于这些错误,一般有两种解决方法:一是遇到错误就终止程序的运行。另一种方法是由程序员在编写程序的过程时,就考虑到错误的检测、错误消息的提示,以及错误的处理。
  • 捕获错误最理想是在编译期间,但有的错误只有在运行时才会发生。比如:除数为0,数组下标越界等。
    • 分类:编译时异常运行时异常

 

 红色:编译时异常;  蓝色:运行时异常。

1.2常见异常

/**
 * 一、异常体系结构
 *
 * java.lang.Throwable
 *      |----java.lang.Error:一般不编写针对性的代码进行处理。
 *      |----java.lang.Exception:可以进行异常的处理。
 *          |----编译时异常(checked)
 *              |----IOException
 *                  |----FileNotFoundException
 *              |----ClassNotFoundException
 *         |----运行时异常(unchecked,RuntimeException)
 *              |----NullPointerException
 *              |----ArrayIndexOutOfBoundException
 *              |----ClassCastException
 *              |----NumberFormatException
 *              |----InputMismatchException
 *              |----ArithmeticException
 *
 *  面试题:常见的异常有哪些?举例说明。
 *
 */
public class ExceptionTest_ {
//*******************以下是b编译时异常********************

    @Test
    public void test7(){
        File file = new File("hello.txt");
        FileInputStream fils = new FileInputStream(file); //红色波浪线

        int data = fils.read();  //红色波浪线
        while(data != -1){
            System.out.println((char)data);
            data = fils.read(); //红色波浪线
        }
        file.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;
    }

    //ArrayIndexOutOfBoundException
    @Test
    public void test2(){
//        int[] arr = new int[4];
//        System.out.println(arr[4]);
        //StringIndexOutOfBoundException
        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);

    }

}

1.3异常处理机制一:try-catch-finally

在编写程序时,经常要在可能出现错误的地方加上检测的代码,

如:进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字母等。过多的if-else分支会导致程序的代码加长、臃肿,可读性差。因此采用异常处理机制。

Java异常处理

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

Java异常处理的方式:

1.try-catch-finally

2.throws+异常类型

  • Java提供的是异常处理的抓抛模型
  • Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给java运行时系统,这个过程称为抛出(throw)异常
  • 异常对象的生成
    • 由虚拟机自动生成:出现运行过程中,虚拟机检测到程序发送了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对于异常类的实例对象并抛出----自动抛出。
    • 由开发人员手动创建:Exception exception = new ClassCastException();-----创建号的异常对象不抛出堆程序没有任何影响,和创建一个普通对象一样。

/**
 * 一、异常的处理:抓抛模型
 * 过程一:”抛“:程序在正常执行过程中,一旦出现异常,就会在异常代码处生成一个d对应的异常类的对象。
 *              并将此对象抛出。
 *              一旦抛出对象以后,其后的代码就不再执行。
 *
 *      关于异常对象的产生:①系统自动生成的异常对象
 *                      ②手动的生成一个异常对象,并抛出(throw)
 *
 *  过程二:”抓“:客户怀疑理解为异常的处理方式:①try-catch-finally ②throws
 *
 *  二、try-catch-finally的使用
 *   try{
 *       //可能出现异常的代码
 *   }catch(异常类型1 变量名1){
 *       //处理异常的方式
 *   }catch(异常类型2 变量名2){
 *       //处理异常的方式
 *   }catch(异常类型3 变量名3){
 *       //处理异常的方式
 *   }
 *   ……
 *   finally{
 *       //一定会执行的代码
 *   }
 *
 *   说明:
 *   1.finally是可选的。
 *   2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象。
 *      根据此对象的类型,去catch中进行匹配。
 *   3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。
 *   一旦处理完成就会跳出当前的try-catch结构(在没有写finally的情况)。继续执行其后的代码。
 *   4.catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
 *     catch中的异常类型如果有子父类关系,则要求子类一定声明在父类的上面。否则,报错。
 *   5.常用的异常对象处理方式:①String getMessage() ②printStackTrace()
 *   6.在try结构中声明的变量,在出了try结构以后,就不能再被调用。
 *   7.try-catch-finally 可以相互嵌套
 *
 *   体会1:使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。
 *      相当于使用 try-catch-finally 将一个编译时可能出现的异常,延迟到运行时出现。
 *
 *   体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写 try-catch-finally 了。
 *        针对于编译时异常,一定要考虑异常的处理。
 */
public class ExceptionTest1 {
    @Test
    public void test1(){

        String str = "123";
        str = "abc";
        int num = 0;
        try{
            num = Integer.parseInt(str);
            System.out.println("hello------1");
        }catch (NumberFormatException e){
            //String getMessage:
//            System.out.println(e.getMessage());  //错误原因信息
            //printStackTrace():
            e.printStackTrace(); //就是我们常见的控制台爆红,包括message
        }catch (NullPointerException e){
            System.out.println("出现空指针异常了,不要着急哦");
        }catch (Exception e){
            System.out.println("出现异常了,不要着急哦");
        }
        System.out.println(num);
        System.out.println("hello-----2");
    }
}

1.4异常处理机制二:throws

package com.liu.jav.Throwable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * 异常处理的方式二:throws + 异常类型
 *
 * 1.”throws + 异常类型“写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
 * 一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象。
 * 此对象满足throws后异常类型时,就被抛出。
 *  异常代码后的代码,就不再执行了。
 *
 *  2.体会:try-catch-finally:真正的将异常给处理掉了。
 *          throws的方式只是将异常抛给了方法的调用者。并没有真正地将异常处理掉。
 *
 */
public class ThrowsTest {

    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();
        }
    }

    private static void method2() throws IOException {
        method1();
    }

    public static void method1() throws FileNotFoundException, IOException {
                File file = new File("hello.txt");
        FileInputStream fils = new FileInputStream(file); //红色波浪线

        int data = fils.read();  //红色波浪线
        while(data != -1){
            System.out.println((char)data);
            data = fils.read(); //红色波浪线
        }
        fils.close();//红色波浪线
    }

}

在开发中如何选择?

/**
 * 方法重写的规则之一:
 *    子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常
 *
 * 如果父类没有异常,子类也不能抛异常。
 *
 * 1.在开发中如何选择使用 try-catch-finally 还是 throws ?
 *      1.1如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,
 *          意味着如果子类重写的方法中异常,必须使用 try-catch-finally方式处理。
 *      1.2执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。
 *          我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用 try-catch-finally方式
 *          进行处理。
 *
 */
public class OverrideTest {

    public static void main(String[] args) {
        OverrideTest overrideTest = new OverrideTest();
        overrideTest.display(new SubClass());
    }

    public void display(SuperClass s){
        try {
            s.method();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
class SuperClass{
    public void method() throws IOException {

    }
}
class SubClass extends SuperClass{
    public void method() throws FileNotFoundException {
        //这里不抛异常也可以
    }
}

1.5手动抛出异常throw

public class StudentTest {
    public static void main(String[] args) {
        Student student = new Student();
        try {
            student.regist(-1);
            System.out.println(student);
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }

}
class Student{
    private int id;
    //throws:体现异常的处理,在方法的声明处。
    //throw:体现的是生成一个异常对象,在方法内部。
    public void regist(int id) throws Exception {
        if(id>0){
            this.id = id;
        }else{
            throw new Exception("您输入的数据非法!");
        }
    }
}

1.6用户自定义异常类

public class StudentTest {
    public static void main(String[] args) {
        Student student = new Student();
        try {
            student.regist(-1);
            System.out.println(student);
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }

}
//关键代码
class Student{
    private int id;
    //throws:体现异常的处理,在方法的声明处。
    //throw:体现的是生成一个异常对象,在方法内部。
    public void regist(int id) throws MyException {  //这里可以抛自定义的异常,也可以是自定义异常类所继承的父异常类
        if(id>0){
            this.id = id;
        }else{
//            throw new Exception("您输入的数据非法!");
            //如果是编译时异常,需要处理,延迟到运行时;运行时异常不需要处理
                throw new MyException("不能输入负数!");
                //注意:只有异常体系的类才可以用throw,别的类不可以。
                //错误的
//            throw new String("error");
        }
    }
}

MyException.java

/**
 *  如何自定义异常类?
 *  1.继承现有的异常结构:RuntimeException、Exception
 *  2.提供全局常量:serialVersionUID 序列号 相当于:唯一的标识MyException这个类。
 *  3.提供重载构造器
 *
 *
 */
public class MyException extends Exception{
    static final long serialVersionUID = -7034897190745766939L;
    public MyException(){

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

考察finally:

public class ReturnException {
    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中的代码,再执行这行。考察finally中的代码一定会被执行。
        }finally {
            System.out.println("用B方法的finally");
        }
    }

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

    }
}

练习2:

  • 编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数。计算两束相除。

        对数据类型不一致(NumberFormatException)、缺少命令行参数(ArrayIndexOutOfBoundsException、除0(ArithmeticException)及输入负数(EcDef)自定义的异常)进行异常处理。

  • 提示:
  1. 在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
  2. 在main()方法中使用异常处理语句进行异常处理。
  3. 在程序中,自定义对应输入负数的异常类(EcmDef)。
  4. 运行时接收参数 java EcmDef 20 10     //args[0]="20" args[1]="10"
  5. Interger类的static方法parseInt(String s)将s转成对应的int值。
    1. 如:int a = Interger.parseInt("314");   //a=314

EcmDef.java

package com.liu.exer;

/**
 * 1.编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数。计算两束相除。
 *         对数据类型不一致(NumberFormatException)、缺少命令行参数
 * (ArrayIndexOutOfBoundsException、除0(ArithmeticException)及输入负数(EcDef)自定义的异常)
 * 进行异常处理。
 *
 * 2.在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
 * 在main()方法中使用异常处理语句进行异常处理。
 * 在程序中,自定义对应输入负数的异常类(EcmDef)。
 * 运行时接收参数 java EcmDef 20 10     //args[0]="20" args[1]="10"
 * Interger类的static方法parseInt(String s)将s转成对应的int值。
 * 如:int a = Interger.parseInt("314");   //a=314
 */
public class EcmDef {
    public static void main(String[] args) {
        try{
            int a = Integer.parseInt(args[0]);
            int b = Integer.parseInt(args[1]);
            int result = ecm(a, b);
            System.out.println(result);
        }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());
        }catch (Exception e){

        }finally {

        }
    }
    public static int ecm(int a,int b) throws EcDef {
        if(a < 0 || b < 0){
            throw new EcDef("分子或分母为负数!");
        }
        return a / b;
    }
}

异常类:EcDef.java

package com.liu.exer;

/**
 * 1.编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数。计算两束相除。
 *         对数据类型不一致(NumberFormatException)、缺少命令行参数
 * (ArrayIndexOutOfBoundsException、除0(ArithmeticException)及输入负数(EcDef)自定义的异常)
 * 进行异常处理。
 *
 * 2.在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
 * 在main()方法中使用异常处理语句进行异常处理。
 * 在程序中,自定义对应输入负数的异常类(EcmDef)。
 * 运行时接收参数 java EcmDef 20 10     //args[0]="20" args[1]="10"
 * Interger类的static方法parseInt(String s)将s转成对应的int值。
 * 如:int a = Interger.parseInt("314");   //a=314
 */
public class EcmDef {
    public static void main(String[] args) {
        try{
            int a = Integer.parseInt(args[0]);
            int b = Integer.parseInt(args[1]);
            int result = ecm(a, b);
            System.out.println(result);
        }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());
        }catch (Exception e){

        }finally {

        }
    }
    public static int ecm(int a,int b) throws EcDef {
        if(a < 0 || b < 0){
            throw new EcDef("分子或分母为负数!");
        }
        return a / b;
    }
}

总结:异常处理的5个关键字

throw和throws的区别:

throws是异常处理的一种方式,而throw是生成异常对象的方式。

复习:

1.异常的体系结构?

java.lang.Throwable
*      |----java.lang.Error:一般不编写针对性的代码进行处理。
*      |----java.lang.Exception:可以进行异常的处理。
*          |----编译时异常(checked)
*              |----IOException
*                  |----FileNotFoundException
*              |----ClassNotFoundException
*         |----运行时异常(unchecked,RuntimeException)
*              |----NullPointerException
*              |----ArrayIndexOutOfBoundException
*              |----ClassCastException
*              |----NumberFormatException
*              |----InputMismatchException
*              |----ArithmeticException

2.从程序执行过程中看,编译时异常和运行时异常?

 编译时异常:执行javac.exe命令时,可能出现的异常。

运行时异常:执行java.exe命令时,出现的异常。

3.常见的异常类型,请举例说明?

//*******************以下是编译时异常********************
//IOException/
FileNotFoundException
//    @Test
//    public void test7(){
//        File file = new File("hello.txt");
//        FileInputStream fils = new FileInputStream(file); //红色波浪线
//
//        int data = fils.read();  //红色波浪线
//        while(data != -1){
//            System.out.println((char)data);
//            data = fils.read(); //红色波浪线
//        }
//        file.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;
    }

    //ArrayIndexOutOfBoundException
    @Test
    public void test2(){
//        int[] arr = new int[4];
//        System.out.println(arr[4]);
        //StringIndexOutOfBoundException
        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);

    }

4.Java异常处理的抓抛模型

过程一:”抛“:程序在正常执行过程中,一旦出现异常,就会在异常代码处生成一个d对应的异常类的对象。
*              并将此对象抛出。
*              一旦抛出对象以后,其后的代码就不再执行。
*
*      关于异常对象的产生:①系统自动生成的异常对象
*                      ②手动的生成一个异常对象,并抛出(throw)
*
过程二:”抓“:客户怀疑理解为异常的处理方式:①try-catch-finally ②throws

5.异常处理方式一:try-catch-finally

5.1使用说明:

try{
*       //可能出现异常的代码
*   }catch(异常类型1 变量名1){
*       //处理异常的方式
*   }catch(异常类型2 变量名2){
*       //处理异常的方式
*   }catch(异常类型3 变量名3){
*       //处理异常的方式
*   }
*   ……
*   finally{
*       //一定会执行的代码
*   }
*
*   说明:
*   1.finally是可选的。
*   2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象。
*      根据此对象的类型,去catch中进行匹配。
*   3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。
*   一旦处理完成就会跳出当前的try-catch结构(在没有写finally的情况)。继续执行其后的代码。
*   4.catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
*     catch中的异常类型如果有子父类关系,则要求子类一定声明在父类的上面。否则,报错。
*   5.常用的异常对象处理方式:①String getMessage() ②printStackTrace()
*   6.在try结构中声明的变量,在出了try结构以后,就不能再被调用。
*   7.try-catch-finally 可以相互嵌套

总结:如何看待代码中的编译时异常和运行时异常?

*   体会1:使用try-catch-finally处理编译时异常,使得程序在编译时就不再报错,但是运行时仍可能报错。
*      相当于使用 try-catch-finally 将一个编译时可能出现的异常,延迟到运行时出现。
*
*   体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写 try-catch-finally 了。
*        针对于编译时异常,一定要考虑异常的处理。

如果都是编译时异常,那么每调一个方法或者写其它代码都要去try,违背了try的简洁性相对if else,所以制衡后就出现运行时异常。

5.2 finally的再说明:

*  1.finally是可选的。
*  2.finally中声明的是一定会被执行的代码。
*  即使catch中又出现了异常,try中有return语句,catch中有return语句等情况。
*
* 3.像数据库连接,输入输出流、网络编程Socket等资源,JVM是不能自动回收的,我们需要自己手动的进行资源的释放。
* 此时的资源释放,就需要声明在finally中。

5.3面试题:final、finally、finalize三者的区别?

类似:

throw 和throws的区别

Collection 和Collectoins的区别

String、StringBuffer和StringBuilder有什么区别

ArrayList和LinkedList

HashMap和LinkedHashMap

重写、重载

结构不相似的:

抽象类、接口

==、equals()

sleep()、wait()

6.异常处理方式二:throws

* 1.”throws + 异常类型“写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
* 一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象。
* 此对象满足throws后异常类型时,就被抛出。
*  异常代码后的代码,就不再执行了。

7.对比两种处理方式:

try-catch-finally:真正的将异常给处理掉了。
*          throws的方式只是将异常抛给了方法的调用者。并没有真正地将异常处理掉。

8.体会开发中,应该如何选择两种处理方式?

1.在开发中如何选择使用 try-catch-finally 还是 throws ?
*    1.1如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中异常,必须使用 try-catch-finally方式处理。
*    1.2执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。
*我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally        方式进行处理。

补充:

* 方法重写的规则之一:
*    子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常
*
* 如果父类没有异常,子类也不能抛异常。

9.手动抛出异常对象

9.1 使用说明

在程序执行中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常类对象。

9.2 【面试题】

throw和throws的区别:

throw表示抛出一个异常类的对象,生成异常类对象的过程。声明在方法内。

throws属于异常处理的一种方式,声明在方法的声明处。

3.典型例题:

public class StudentTest {
    public static void main(String[] args) {
        Student student = new Student();
        try {
            student.regist(-1);
            System.out.println(student);
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
        }
    }

}
//关键代码
class Student{
    private int id;
    //throws:体现异常的处理,在方法的声明处。
    //throw:体现的是生成一个异常对象,在方法内部。
    public void regist(int id) throws MyException {  //这里可以抛自定义的异常,也可以是自定义异常类所继承的父异常类
        if(id>0){
            this.id = id;
        }else{
//            throw new Exception("您输入的数据非法!");
            //如果是编译时异常,需要处理,延迟到运行时;运行时异常不需要处理
                throw new MyException("不能输入负数!");
                //注意:只有异常体系的类才可以用throw,别的类不可以。
                //错误的
//            throw new String("error");
        }
    }
}

如何自定义一个异常类?

*  1.继承现有的异常结构:RuntimeException、Exception
*  2.提供全局常量:serialVersionUID 序列号 相当于:唯一的标识MyException这个类。
*  3.提供重载构造器
public class MyException extends Exception{
    static final long serialVersionUID = -7034897190745766939L;
    public MyException(){

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chao_nengli

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值