首页 > 编程语言 >Java异常详解及处理机制(超详细附习题)

Java异常详解及处理机制(超详细附习题)

时间:2024-10-15 23:47:34浏览次数:8  
标签:Java System try 详解 println 习题 异常 public out

文章目录

异常

写在开头:

我编写本文的时候还有点模糊不清,写到一半又有了新的理解就是!!当我们用try-catch试图捕获异常的时候,写在try里的语句如果发生了异常,那么异常后面的语句将不再执行。进入catch里执行,finally一定在try的return语句前执行。若catch里处理了异常,则try-catch整体语句后的代码可以继续执行。

什么是异常?

异常是指程序运行出现意料之外、不想让它出现的情况。如果我们不处理,那么异常会导致程序无法正常运行/崩溃。

认识常见的异常和错误

ArithmeticException算术异常

package com.gj.exception;

import java.util.Scanner;

public class TestException {
    public static void main(String[] args) {
        //从键盘输入2个整数,求它们的商、和、差、乘积
        Scanner input = new Scanner(System.in);

        System.out.print("请输入第1个整数:");
        int a = input.nextInt();

        System.out.print("请输入第2个整数:");
        int b = input.nextInt();

        System.out.println("商:" + a/b);//当b=0的时候,发生ArithmeticException
        System.out.println("和:" + (a+b));
        System.out.println("差:" + (a-b));
        System.out.println("乘积:" + a*b);

        input.close();

    }
}

ArrayIndexOutOfBoundsException数组下标越界异常

package com.gj.exception;

public class TestException2 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for(int i=1; i<=arr.length; i++){//正确的下标范围:[0, arr.length-1]
            System.out.println(arr[i]);
        }
    }
}

NullPointerException空指针异常

package com.gj.exception;

public class TestException3 {
    public static void main(String[] args) {
        Student[] arr = new Student[3];//arr的元素全部都是null
        for (int i = 0; i < arr.length; i++) {
            //缺少 arr[i] = new Student();
            arr[i].setName("学生" + i);
            arr[i].setScore(90+i);
        }
    }
}

ClassCastException类型转换异常

package com.atguigu.exception;

public class TestException4 {
    public static void main(String[] args) {
        Object obj = new Object();
        String str = (String) obj;//ClassCastException
    }
}

StackOverflowError栈内存溢出错误

package com.gj.exception;

public class TestError {
    public static void main(String[] args) {
        m();
    }

    public static void m(){
//        System.out.println("m方法");
        m();//无条件递归
    }
}

InputMismatchException输入不匹配

package com.gj.exception;

import java.util.Scanner;

public class TestException {
    public static void main(String[] args) {
        //从键盘输入2个整数,求它们的商、和、差、乘积
        Scanner input = new Scanner(System.in);

        System.out.print("请输入第1个整数:");
        int a = input.nextInt();//输入非整数时

        System.out.print("请输入第2个整数:");
        int b = input.nextInt();

        System.out.println("商:" + a/b);
        System.out.println("和:" + (a+b));
        System.out.println("差:" + (a-b));
        System.out.println("乘积:" + a*b);

        input.close();

    }
}

Java中如何表示异常的呢?

Java通过API中Throwable类的众多子类描述各种不同的异常。因而,Java异常都是对象,是Throwable子类的实例,描述了出现在一段编码中的错误条件。当条件生成时,错误将引发异常。

Java异常类层次结构图:

Throwable类是 Java 语言中所有错误或异常的超类。Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类。

ErrorThrowable的子类,用于指示合理的应用程序不应该试图捕获的严重问题,是程序无法处理的错误。例如:VirtualMachineError (虚拟机错误),包含OutOfMemoryError(堆内存溢出), StackOverflowError(栈内存溢出错误)。

这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。

Exception类是Throwable的子类,是程序本身可以处理的异常。它指出了合理的应用程序想要捕获的条件。 对于Exception来说,咱们程序员的态度应该是:(1)能通过条件判断等代码避免的,就不要用try-catch(2)无法避免的用try-catch处理。

Exception又分为:

  • RuntimeException:运行时异常又称为不受检异常(编译器不要求强制处置的异常),类及其子类表示“JVM 常用操作”引发的错误。例如,若试图使用空值对象引用、除数为零或数组越界,则分别引发运行时异常。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
  • CheckedException:编译时异常又称为受检异常(编译器要求必须处置的异常)这种异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常,要么用try-catch语句捕获它,要么用throws子句声明抛出它,否则编译不会通过。

处理异常机制

在Java应用程序中,异常处理机制为:抛出异常,捕获异常。

注意:只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。类似地,只有此类或其子类之一才可以是 catch 子句中的参数类型。

通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。

异常处理之try-catch

语法格式:

try{
    尝试执行xx代码,它们可能发生异常,也可能不发生异常
}catch(异常的类型 异常参数名){ //通常参数名都是e
    对异常的处理代码
    以及 打印异常信息的代码(目前我们把异常打印到控制台,后期做项目异常信息打印到日志文件),错误信息怎么打印是根据实际情况来定
}

举例:

使用try-catch处理InputMismatchException异常。

package com.gj.exception;

import java.util.InputMismatchException;
import java.util.Scanner;

public class TestTryCatch {
    public static void main(String[] args) {
        //从键盘输入2个整数,求它们的商、和、差、乘积
        Scanner input = new Scanner(System.in);

        int a = 0;
        while(true) {
            try {
                //选中要放到try{}里面的语句,按快捷键Ctrl + Alt + T
                System.out.print("请输入第1个整数:");
                a = input.nextInt();//这句代码可能会发生异常,如果发生异常,try剩下的语句就不执行了
                                //如果没有发生异常,try{}中剩下的语句继续执行
                break;//如果有异常,break不走
            } catch (InputMismatchException e) {
//            throw new RuntimeException(e);//用throw的话,表示继续抛,等于异常没有处理掉,而是换了一种类型
                //System.err.println(e);//普通的错误信息打印,
//            e.printStackTrace();//标准异常信息的打印,包含异常的类型,异常的堆栈跟踪信息

                System.out.println("输入信息不对,这里需要一个整数!!!");

                input.nextLine();//这里会把刚刚输入的所有信息读取掉,但是不接收,因为这些信息是错误的,不要的
            }
        }
        int b;
        while(true) {
            try {
                System.out.print("请输入第2个整数:");
                b = input.nextInt();
                if(b==0){
                    System.out.println("除数不能为0,请重新输入!");
                }else{
                    break;
                }
            } catch (Exception e) {
                System.out.println("输入信息不对,这里需要一个整数!!!");
                input.nextLine();
            }

        }

        System.out.println("商:" + a/b);
        System.out.println("和:" + (a+b));
        System.out.println("差:" + (a-b));
        System.out.println("乘积:" + a*b);

        input.close();
    }
}

使用条件判断避免InputMismatchException异常。

package com.gj.exception;

import java.util.Scanner;

public class TestTryCatch2 {
    public static void main(String[] args) {
        //从键盘输入2个正整数,求它们的商、和、差、乘积
        Scanner input = new Scanner(System.in);

        int a;
        int b;

        while (true) {
            System.out.print("请输入第1个正整数:");
            if (input.hasNextInt()) {
                a = input.nextInt();
                if(a>0) {
                    break;
                }else{
                    System.out.println("这里需要输入正整数!");
                }
            } else {
                System.out.println("这里需要一个整数!!");
                input.nextLine();//读取非int整数的垃圾数据
            }
        }
        while (true) {
            System.out.print("请输入第2个整数:");
            if (input.hasNextInt()) {
                b = input.nextInt();
                if(b>0){
                    break;
                }else if(b==0){
                    System.out.println("除数不能为0!!!");
                }else {
                    System.out.println("这里需要输入正整数!");
                }
            } else {
                System.out.println("这里需要一个整数!!");
                input.nextLine();//读取非int整数的垃圾数据
            }
        }

        System.out.println("商:" + a/b);
        System.out.println("和:" + (a+b));
        System.out.println("差:" + (a-b));
        System.out.println("乘积:" + a*b);

        input.close();
    }
}

异常处理之finally块

语法格式:

try{
    尝试执行xx代码,它们可能发生异常,也可能不发生异常
}catch(异常的类型1 异常参数名){ //通常参数名都是e
    异常的处理代码
}catch(异常的类型2 异常参数名){ //通常参数名都是e
    异常处理代码
}finally{
    无论try中是不是发生异常,
    也不管catch能不能抓住异常,
    就算是try和catch中有return语句,
    都必须执行的代码,放这里
}

举例:

先执行输出语句1,没捕获到异常不执行2,finally一定执行3。

package com.gj.exception;

public class TestFinally1 {
    public static void main(String[] args) {
        try{
            System.out.println("1、没有异常");
        }catch (Exception e){
            System.out.println("2、发生异常");
        } finally {
            System.out.println("3、一定执行");
        }
        //13
    }
}

先执行语句1,0不能是除数发生异常执行catch语句3,发生异常后的语句不执行了,但finally一定执行。

package com.gj.exception;

public class TestFinally2 {
    public static void main(String[] args) {
        try{
            System.out.println("1、没有异常");
            System.out.println(1/0);//发生异常
            System.out.println("2、发生异常");
        }catch (Exception e){
            System.out.println("3、处理异常");
        } finally {
            System.out.println("4、一定执行");
        }
        //134
    }
}

finally会在return结束方法前执行。

package com.gj.exception;

public class TestFinally3 {
    public static void main(String[] args) {
        try{
            System.out.println("1、没有异常");
            return;//结束方法   先检查有没有finally,有finally,先执行finally再结束当前方法
        }catch (Exception e){
            System.out.println("2、发生异常");
        } finally {
            System.out.println("3、一定执行");
        }
        //13
    }
}
package com.gj.exception;

public class TestFinally4 {
    public static void main(String[] args) {
        System.out.println(getNumber(5));
        /*
        运行结果:
        finally
        1
         */
    }

    public static int getNumber(int a){
        try{
            if(a>0){
                return 1;
            }else{
                return -1;
            }
        }catch (Exception e){
            return 2;
        }finally {
            System.out.println("finally");
        }
    }
}
package com.gj.exception;

public class TestFinally5 {
    public static void main(String[] args) {
        System.out.println(getNumber(5));
        /*
        运行结果:
        finally
        3
         */
    }

    public static int getNumber(int a){
        try{
            if(a>0){
                return 1;//把1放入操作数栈,准备返回,先去执行finally
            }else{
                return -1;
            }
        }catch (Exception e){
            return 2;
        }finally {
            System.out.println("finally");
            return 3;//又把3放入操作数栈,结束方法,返回3
            //如果finally中有return语句,其他return语句都失效了,
            //不要在finally中写return语句
        }
    }
}
package com.gj.exception;

public class TestFinally6 {
    public static void main(String[] args) {
        System.out.println(getNumber());
        /*
        运行结果:
        finally
        2
         */
    }

    public static int getNumber(){
        int a = 1;
        try{
            a++;//a=2
            return a;//a=2  先把a的值放入操作数栈,然后去执行finally
        }catch (Exception e){
            a++;
            return a;
        }finally {
            System.out.println("finally");
            a++;//a=3,这里并未写return语句,没有返回3
        }
    }
}
package com.gj.exception;

import java.util.Scanner;

public class TestFinally7 {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        try {
            System.out.print("请输入姓名:");
            String name = input.next();
            System.out.println("name = " + name);
        } catch (Exception e) {
            System.out.println("输入错误");
        }finally {
            input.close();
            //一般编写资源释放代码,例如;流的关闭,网络连接的断开等
        }
    }
}

throws关键字

throws的作用

告知/声明 调用者当前方法中“可能”发生xx类型的异常,需要“调用者”处理。如果调用者不处理,也可以继续throws来声明抛出异常,只是一旦发生异常,就会导致程序崩溃。如果为了保证程序的健壮性,那么最终还是要靠try-catch处理的。

语法格式:

【①修饰符】 ②返回值类型 ③方法名(【④形参列表】)【⑤throws 异常类型列表(多个异常可用逗号隔开)】{
    ⑥方法体语句;
}

拓展throws对重写方法的要求

  • 子类重写方法throws的异常类型 <= 父类被重写方法throws的异常类型,这个要求主要是针对编译时异常类型来说
  • 对于运行时异常类型,不做任何要求

举例:

package com.gj.exception;

public class TestThrows {
    public static void main(String[] args) throws InterruptedException {
        printNumber();//main方法就得到了信息,可能发生InterruptedException
        //它的选择也有两种(1)try-catch(2)继续摆烂,接着throws
    }

    //需求:希望实现每隔1秒打印1个数字,实现10,9,8,....1效果
    //提前剧透:Thread.sleep(毫秒数)  1s = 1000ms
    //throws表示声明一下,当前方法可能发生xx类型的异常,需要 调用者处理,谁调用谁处理,反正我自己不处理
    public static void printNumber() throws InterruptedException {
        for(int i=10; i>=1; i--){
            System.out.println(i);
            Thread.sleep(1000);
        }
    }
}

throw关键字

throw总是出现在方法体中,主动抛出一个Throwable类型的异常对象。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。

手动抛出一个异常对象,代替return语句,返回异常对象,异常信息给调用者。

package com.gj.exception;

public class Account {//银行账号
    private String id;
    private double balance;//余额

    public Account(String id, double balance) {
        this.id = id;
        this.balance = balance;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id='" + id + '\'' +
                ", balance=" + balance +
                '}';
    }

    public void withdraw(double money){
        if(money<0){
//            System.out.println("取款金额不能为负数");
//            return false;
            //throw语句可以代替return语句,返回的是异常信息,不正常的信息
            throw new IllegalArgumentException("取款金额不能为负数");
            //Illegal:非法的,Argument:参数,Exception:异常
        }
        if(money >balance){
//            System.out.println("余额不足!");
//            return false;
            throw new UnsupportedOperationException("余额不足!");
            //Unsupported:不支持,Operation:操作,Exception:异常
        }
        balance -= money;
//        System.out.println("取款成功!");
//        return true;
    }

    public boolean save(double money){
        if(money<0){
            System.out.println("存款金额不能为负数");
            return false;
        }
        balance += money;
        System.out.println("存款成功!");
        return  true;
    }
}
package com.gj.exception;

import java.util.InputMismatchException;
import java.util.Scanner;

public class TestAccount {
    public static void main(String[] args) {
        Account a = new Account("111111",5000);
        Scanner input = new Scanner(System.in);
        while (true) {
            try {
                System.out.print("请输入取款金额:");
                double money = input.nextDouble();
                a.withdraw(money);
                System.out.println("取款成功!");
                break;
            }  catch (InputMismatchException e) {
                System.err.println("金额必须是整数或小数,不能是字符串");
                input.nextLine();
            } catch (Exception e) {
    //            e.printStackTrace();
                System.err.println(e.getMessage());
            }
        }

        input.close();

    }
}

throws与throw的区别:

throwsthrow
使用位置方法签名中方法体语句中
作用告知调用者该方法可能发生xx异常,需要调用者警惕,并且处理手动抛出一个异常对象,代替return语句,返回异常信息。一旦它执行了,就表示异常发生了。

自定义异常

使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。

步骤:

  • 创建自定义异常类:一般会选择继承Exception和RuntimeException,如果不要求调用者一定要处理抛出的异常,就继承RuntimeException。
  • 抛出自定义异常:在方法中通过throw关键字抛出异常对象。
  • 捕获自定义异常:如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
  • 在出现异常方法的调用者中捕获并处理异常
class MyException extends Exception { // 创建自定义异常类
    
    String message; // 定义String类型变量
    public MyException(String ErrorMessagr) { // 父类方法
        message = ErrorMessagr;
    }
 
    public String getMessage() { // 覆盖getMessage()方法
        return message;
    }
}

标签:Java,System,try,详解,println,习题,异常,public,out
From: https://blog.csdn.net/weixin_52176709/article/details/142965511

相关文章

  • 【JVM】—JVM垃圾回收详解
    JVM垃圾回收详解⭐⭐⭐⭐⭐⭐Github主页......
  • java学习10.15
    今天学习了java图形化编程importjava.awt.*;importjava.awt.event.*;publicclassFramePractice{publicstaticvoidmain(String[]args){Frameframe=newFrame();//Frame是窗体,我们只需要创建这样一个对象就可以了,这样就会直接创建一个新的窗口......
  • 第九章习题3-编写一个函数print,打印一个学生的成绩数组,该数组有5个学生的数据记录,每个
     ......
  • CSS伪元素详解
    CSS伪元素详解一、引言在CSS中,伪元素是一个非常强大的工具,它允许我们为元素的特定部分添加样式,而无需修改HTML结构。这不仅提高了样式的灵活性,还有助于保持代码的整洁和可维护性。本文将深入探讨CSS伪元素的使用方法和一些实用技巧。二、伪元素的基本概念1、伪元素的定......
  • JAVA输入输出,运算符
    1.输入输出packagecom.scanner;//1.导包importjava.util.Scanner;publicclassDemo1{publicstaticvoidmain(){print();}//需求:我是一个零基础小白,请帮我写一个程序,可以让用户键盘输入用户名和年龄,然后打印出来。publicstaticvoid......
  • 一. Java“速学通”之基础
    前言        Java急速学习课程是专为那些已经具备一定编程基础的同学设计的高效学习路径。这种学习方法摒弃了繁冗的理论堆砌,转而采用直接明了的代码示例与细致入微的注释来传授知识。每一个核心概念和技巧都通过精心挑选的实战代码片段来阐述,确保学习者能够通过观察......
  • Java中Log4j的配置与使用详细解析
    Log4jLog4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件。也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。这些可以通过一个配置文件来灵活地进行配置,而不需要修......
  • Java第二节
    复习if语句if(表达式) {语句}if后面的表达式只能是布尔表达式(关系表达式、逻辑表达式、布尔类型变量)if后面的语句只能是一条语句,多于一条则必须用括号括起来,变成一条复合语句。新知1.char字符类型,占用2个字节 2.字符常量:单引号括起来的单个字符 类型的转换:不同类......
  • Java面向对象六大设计原则总结1
    简介         在Java面向对象设计中,遵循六大原则是确保代码质量、可维护性和可扩展性的关键。这六大原则分别是:单一职责原则(SRP)、开闭原则(OCP)、里氏替换原则(LSP)、接口隔离原则(ISP)、依赖倒置原则(DIP)和迪米特法则(LOD)。以下是对这六大原则的详细解释,并结合实例进行说明......
  • 【Java SE 题库】递归的魅力之--> 青蛙跳台阶问题(秒了)
     ......