小编也是考完期末了,给大家再更新一篇异常处理吧。反正是全文通俗易懂,小白也包可以听懂的!!!大家放心食用(嘻嘻)
一,异常是什么呢?就大致和人们口中说的bug差不多。
异常 :指的是程序在执行过程中,出现的非正常情况,如果不处理最终会导致JVM的非 正常停止。(小白可能看不太懂)
举个栗子!!!(小编就爱举例子,小白听了嘎嘎懂)
异常其实就是比如说,你开车去上班,但从出门(开始)到抵达公司(结果)中间的过程中随便一个自身原因或者外界因素导致到不了公司(没有成功输出结果),就会出现异常!!
自身因素:可能说车子没油了,你驾照就考了个科二(技术不过关),超载了...
自身因素就类比于:你编译的能力,使用的编译语言和编译器匹不匹配,编译的语法对不对,就像做数学题粗心多加了一位数...
外界因素:客户给你的文件格式和内容都不一致,甲方爸爸(🐕不是)的无理取闹,公司给你配备的电脑老是自己死机的不行,你编译一半电脑关机了....
所以出bug了有时候不一定是在座各位自身的原因,哈哈哈哈,也可能是外界的其他因素
二,Java将异常分为两大类:Error和Exception。
分别对应着 java.lang.Error 与 java.lang.Exception 两个类。
①那么他们分别是什么呢?②怎么个分类标准?③遇到不同的异常类别又该如何应对?
咱们接下来就是主要解决这三个问题了。
①分别是什么?再细分类
Error:Java 虚拟机无法解决的严重问题。如:JVM 系统内部错误、资源耗尽等严重情况。一般不编写针对性的代码进行处理。
例如:StackOverflowError(栈内存溢出)和 OutOfMemoryError(堆内存溢出,简称OOM).
Exception:其它因编程错误或偶然的外在因素导致的一般性问题,需要使用针对性的代码进行处理,使程序继续运行。否则一旦发生异常,程序也会挂掉
例如:空指针访问,试图读取不存在的文件,网络连接中断,数组角标越界
看懂了吗?官方定义.....反正我看不太懂,
还是老规矩简单举个栗子:
Error就像是电脑突然死机了,这时候你没法做什么,只能重启;
而Exception则更像是你在做数学题时不小心除以了0,这时你可以检查一下自己的计算过程,改正错误后重新计算。
所以,在编写Java程序时,我们应该关注如何正确处理Exception,而对于Error,我们更多是预防和优化,而不是试图在程序中处理它们。
所以我们接下来的重点和平常需要积累的debug经验指的是什么呢?
就是Exception!!
Java 程序的 “执行” 分为 “编译过程 ” 和 “运行过程” 。
大家学过Java应该对这个图是相当不陌生了。(好像不学java的也可以看得懂,嘻嘻)
编译时期异常(即checked异常、受检异常):在代码编译阶段,编译器就能明确警 示当前代码可能发生(不是一定发生)xx异常,并明确督促程序员提前编写处理它 的代码。如果程序员没有编写对应的异常处理代码,则编译器就会直接判定编译失 败,从而不能生成字节码文件。通常,这类异常的发生不是由程序员的代码引起的, 或者不是靠加简单判断就可以避免的,例如:FileNotFoundException(文件找不到异 常)。
运行时期异常(即runtime异常、unchecked异常、非受检异常):在代码编译阶段, 编译器完全不做任何检查,无论该异常是否会发生,编译器都不给出任何提示。只有 等代码运行起来并确实发生了xx异常,它才能被发现。通常,这类异常是由程序员 的代码编写不当引起的,只要稍加判断,或者细心检查就可以避免。
– java.lang.RuntimeException:类及它的子类都是运行时异常。比如: ArrayIndexOutOfBoundsException:数组下标越界异常,ClassCastException 类型转换异常。
还是举个栗子!!
1)编译时异常:
你写完作业之后,家长或者老师会检查你的作业。如果他们发现有错别字、语法错误或者其他明显的错误,他们会告诉你需要改正这些错误,然后才能提交作业。
在Java中,编译器就扮演了这个“家长”或“老师”的角色。
2)运行时异常:
你已经完成了家庭作业,并且经过检查没有问题,所以成功提交了作业。但是,当你开始完成作业中的任务时,可能会遇到一些意想不到的问题,比如你发现题目中的数字太大,计算器无法处理;或者你突然找不到某个参考资料了。
这些问题是在你开始做作业(即程序开始运行)之后才发现的,而且它们不是因为你的作业本身有错别字或语法错误。
这个用几个具体代码例子就非常清晰明了了:!!
1)编译错误(忘记分号):假设你在写一段Java代码时,不小心漏掉了一个分号(;),就像下面这样:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, world")
}
}
当你尝试编译这段代码时,编译器会报错,因为它期望在System.out.println("Hello, world")这行语句的末尾有一个分号。这时你就需要回去添加上那个分号,然后重新编译。
1)编译错误(使用未定义的变量):
public class HelloWorld {
public static void main(String[] args) {
System.out.println(undeclaredVariable);
}
}
编译器会告诉你undeclaredVariable不存在,要求你声明这个变量或者修正代码。
2)运行错误(除以零):假设你编写了一个程序来计算两个数相除的结果,但用户输入了0作为除数。在数学中,任何数除以0都是不允许的,因此当程序运行到这个点时,会抛出ArithmeticException,告诉你除数不能为0。
public class DivisionExample {
public static void main(String[] args) {
int a = 10;
int b = 0; // 用户输入了0
System.out.println(a / b); // 这里会抛出 ArithmeticException
}
}
2)(数组越界):如果你有一个长度为5的数组,但你尝试访问索引为10的元素,那么在运行时,程序会抛出ArrayIndexOutOfBoundsException,因为数组并没有那么多元素。
public class ArrayExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
System.out.println(numbers[10]); // 这里会抛出 ArrayIndexOutOfBoundsException
}
}
小结一下:
编译时异常:就像是在你提交作业之前,家长或老师帮你检查作业,确保没有明显的错误。如果你的代码有问题,编译器会告诉你,并且不会让你继续。
运行时异常:就像是在你已经开始做作业后,遇到了一些意料之外的问题。这些问题可能是因为外部条件变化或者用户输入的数据不正确等原因导致的。
三,如何对不同类别的异常做出对应的处理:
Java 异常处理的方式:
方式一:try-catch-finally
方式二:throws + 异常类型
①try-catch-finally:
当你知道某些代码可能会抛出异常,并且你想要立即处理这些异常,而不是让它们传播到调用栈上层时,你会使用try-catch-finally。(什么时候使用)
例如,读取文件、连接数据库或进行网络请求等操作都可能抛出异常,这时你可以使用try-catch-finally来捕获并处理这些异常。
语法结构:
try {
// 可能会抛出异常的代码
} catch (ExceptionType1 e1) {
// 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
// 处理 ExceptionType2 类型的异常
} finally {
// 不管是否发生异常,都会执行的代码
}
举个栗子:
你有一个方法用来读取文件内容,但文件可能不存在,或者你没有权限访问这个文件。你可以使用try-catch-finally来处理这些潜在的异常:
import java.io.*;
public class FileReaderExample {
public static void main(String[] args) {
File file = new File("example.txt");
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.out.println("找不到指定的文件: " + e.getMessage());
} catch (IOException e) {
System.out.println("读取文件时发生了IO异常: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close(); // 确保资源被正确关闭
} catch (IOException e) {
System.out.println("关闭文件流时发生异常: " + e.getMessage());
}
}
}
}
}
这个代码例子里,try块包含了可能会抛出FileNotFoundException或IOException的代码。
如果抛出了FileNotFoundException,则第一个catch块会被触发;
如果是IOException,第二个catch块会被触发。
finally块中的代码无论是否发生异常都会被执行,这里用于确保文件流被正确关闭。
② throws + 异常类型:
当你编写的方法内部可能会抛出异常,但你不希望在这个方法内处理这些异常,而是想让调用者(即方法的使用者)来处理时,你会使用throws关键字。这通常用于构建库或框架,其中具体的异常处理策略应该由最终用户决定。(什么时候使用)
语法结构:
public void methodName() throws ExceptionType1, ExceptionType2 {
// 可能会抛出异常的代码
}
举个栗子:
你正在编写一个简单的计算器类,其中一个方法是用来除两个数。但是,如果你尝试除以0,就会抛出ArithmeticException。你可以在方法签名中声明这个异常,这样任何调用这个方法的人都知道他们需要处理这个异常:
public class Calculator {
// 宣告此方法可能会抛出 ArithmeticException
public int divide(int a, int b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException("除数不能为0");
}
return a / b;
}
}
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator();
try {
int result = calc.divide(10, 0); // 这里会抛出 ArithmeticException
System.out.println("结果是: " + result);
} catch (ArithmeticException e) {
System.out.println("捕获到了异常: " + e.getMessage());
}
}
}
在这个代码例子中,divide方法声明了它可能会抛出ArithmeticException。
当我们在main方法中调用divide并传入0作为除数时,divide方法会抛出异常。
由于我们在main方法中使用了try-catch语句,所以我们可以捕获并处理这个异常,避免程序崩溃。
小结一下:
try-catch-finally:当你希望在方法内部处理异常时使用。它允许你在异常发生时立即采取行动,并确保一些必要的清理工作(如关闭资源)总是被执行。
throws + 异常类型:当你不想在方法内部处理异常,而是希望将责任推给调用者时使用。这可以让你的方法更加通用,因为不同的调用者可以根据自己的需求来决定如何处理异常。
这两种方式并不是互相排斥的,实际上在一个较大的应用程序中,你可能会同时使用这两种方式。
例如,低级别的方法可能会使用throws来传递异常,而高级别的方法则会使用try-catch-finally来处理这些异常。
再详细的俩种异常处理具体使用就需要大家自己多敲代码多练习了,平时就要多积累经验。
那么小编今天的分享就到此为止,之后学有所成之后,必然会给大家带来更多的debug优质内容的!!!!!感谢观看!!!