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

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

文章目录

异常写在开头:什么是异常?认识常见的异常和错误Java中如何表示异常的呢?处理异常机制异常处理之try-catch语法格式:举例:

异常处理之finally块语法格式:举例:

throws关键字throws的作用语法格式:拓展throws对重写方法的要求举例:

throw关键字throws与throw的区别:自定义异常步骤:

异常

写在开头:

我编写本文的时候还有点模糊不清,写到一半又有了新的理解就是!!当我们用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 异常处理的重要子类,各自都包含大量子类。

Error是Throwable的子类,用于指示合理的应用程序不应该试图捕获的严重问题,是程序无法处理的错误。例如: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;

}

}

🎯 相关推荐

《鹡鸰女神》
365bet体育在线怎么样

《鹡鸰女神》

📅 07-07 👁️ 2141
“烧不坏”的手帕
足球比分365cv

“烧不坏”的手帕

📅 09-24 👁️ 3172
卡塔尔世界杯:比球赛还好看的,是各国的太太团!
365bet体育在线怎么样

卡塔尔世界杯:比球赛还好看的,是各国的太太团!

📅 10-13 👁️ 8008
卡塔尔世界杯:比球赛还好看的,是各国的太太团!
365bet体育在线怎么样

卡塔尔世界杯:比球赛还好看的,是各国的太太团!

📅 10-13 👁️ 8008
13首致青春畢業歌推薦!五月天〈笑忘歌〉超催淚、蛋堡〈過程〉太Real
【24小时】西安数码维修
365bet注册送钱

【24小时】西安数码维修

📅 08-03 👁️ 3065