携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情
哈喽,大家好!我是Why,一名在读学生,目前刚刚开始进入自己的编程学习生涯。虽然学习起步较晚,但我坚信做了才有0或1的可能。学了一段时间以后也是选择在掘金上分享自己的日常笔记,也希望能够在众多道友的大家庭中打成一片。 本文主要讲解异常,如果大家读后觉得有用的话,还请大家多多支持博主:欢迎 ❤️点赞👍、收藏⭐、留言💬 ✨✨✨个人主页:JinHuan
异常对象的两个重要方法
获取异常简单的描述信息:
String msg = exception.getMessage();
打印异常追踪的堆栈信息:
exception.printStackTrace();
实例
public class ExceptionTest08 {
public static void main(String[] args) {
// 这里只是为了测试getMessage()方法和printStackTrace()方法。
// 这里只是new了异常对象,但是没有将异常对象抛出。JVM会认为这是一个普通的java对象。
NullPointerException e = new NullPointerException("空指针异常fdsafdsafdsafds");
// 获取异常简单描述信息:这个信息实际上就是构造方法上面String参数。
String msg = e.getMessage(); //空指针异常fdsafdsafdsafds
System.out.println(msg);
// 打印异常堆栈信息
// java后台打印异常堆栈追踪信息的时候,采用了异步线程的方式打印的。
e.printStackTrace();
for(int i = 0; i < 1000; i++){
System.out.println("i = " + i);
}
System.out.println("Hello World!");
}
}
运行结果如下:
怎样查看异常并做处理
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/*
我们以后查看异常的追踪信息,我们应该怎么看,可以快速的调试程序呢?
异常信息追踪信息,从上往下一行一行看。
但是需要注意的是:SUN写的代码就不用看了(看包名就知道是自己的还是SUN的。)。
主要的问题是出现在自己编写的代码上。
*/
public class ExceptionTest09 {
public static void main(String[] args) {
try {
m1();
} catch (FileNotFoundException e) {
// 获取异常的简单描述信息
String msg = e.getMessage();
System.out.println(msg); //C:\jetns-agent.jar (系统找不到指定的文件。)
//打印异常堆栈追踪信息!!!
//在实际的开发中,建议使用这个。养成好习惯!
// 这行代码要写上,不然出问题你也不知道!
//e.printStackTrace();
/*
java.io.FileNotFoundException: C:\jetns-agent.jar (系统找不到指定的文件。)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
at com.bjpowernode.javase.exception.ExceptionTest09.m3(ExceptionTest09.java:31)
at com.bjpowernode.javase.exception.ExceptionTest09.m2(ExceptionTest09.java:27)
at com.bjpowernode.javase.exception.ExceptionTest09.m1(ExceptionTest09.java:23)
at com.bjpowernode.javase.exception.ExceptionTest09.main(ExceptionTest09.java:14)
因为31行出问题导致了27行
27行出问题导致23行
23行出问题导致14行。
应该先查看31行的代码。31行是代码错误的根源。
*/
}
// 这里程序不耽误执行,很健壮。《服务器不会因为遇到异常而宕机。》
System.out.println("Hello World!");
}
private static void m1() throws FileNotFoundException {
m2();
}
private static void m2() throws FileNotFoundException {
m3();
}
private static void m3() throws FileNotFoundException {
new FileInputStream("C:\jetns-agent.jar");
}
}
Finally语句
"1、在finally子句中的代码是最后执行的,并且是一定会执行的,即使try语句块中的代码出现了异常。
finally子句必须和try一起出现,不能单独编写。
"2、finally语句通常使用在哪些情况下呢?
通常在finally语句块中完成资源的释放/关闭。
因为finally中的代码比较有保障。
即使try语句块中的代码出现异常,finally中代码也会正常执行。
实例
public class ExceptionTest10 {
public static void main(String[] args) {
FileInputStream fis = null; // 声明位置放到try外面。这样在finally中才能用。
try {
// 创建输入流对象
fis = new FileInputStream("D:\course\02-JavaSE\document\JavaSE进阶讲义\JavaSE进阶-01-面向对象.pdf");
// 开始读文件....
String s = null;
// 这里一定会出现空指针异常!
s.toString();
System.out.println("hello world!");
// 流使用完需要关闭,因为流是占用资源的。
// 即使以上程序出现异常,流也必须要关闭!
// 放在这里有可能流关不了。
//fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
} catch(NullPointerException e) {
e.printStackTrace();
} finally {
System.out.println("hello 浩克!");
// 流的关闭放在这里比较保险。
// finally中的代码是一定会执行的。
// 即使try中出现了异常!
if (fis != null) { // 避免空指针异常!
try {
// close()方法有异常,采用捕捉的方式。
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("hello kitty!");
}
}
Try和finally的连用
验证finally语句一定是最后执行的
public class ExceptionTest11 {
public static void main(String[] args) {
/*
try和finally,没有catch可以吗?可以。
try不能单独使用。
try finally可以联合使用。
以下代码的执行顺序:
先执行try...
再执行finally...
最后执行 return (return语句只要执行方法必然结束。)
*/
try {
System.out.println("try...");
return;
} finally {
// finally中的语句会执行。能执行到。
System.out.println("finally...");
}
// 这里不能写语句,因为这个代码是无法执行到的。
//System.out.println("Hello World!");
}
}
关于Finally中的特例
"注意,当退出JVM的时候,Finally语句就不会执行了"
public class ExceptionTest12 {
public static void main(String[] args) {
try {
System.out.println("try...");
// 退出JVM
System.exit(0); // 退出JVM之后,finally语句中的代码就不执行了!
} finally {
System.out.println("finally...");
}
}
}
Finally易错点
"试推测下列result的返回值
public class Test {
public static void main(String[] args) {
int result = m();
System.out.println(result); //猜测结果
}
public static int m(){
int i = 100;
try {
return i;
} finally {
i++;
System.out.println("Finally中的i"+i);
}
}
}
分析
"java语法规则(有一些规则是不能破坏的,一旦这么说了,就必须这么做!):
java中有一条这样的规则:
方法体中的代码必须遵循自上而下顺序依次逐行执行(亘古不变的语法!)
java中还有一条语法规则:
return语句一旦执行,整个方法必须结束(亘古不变的语法!)
运行结果
可以看出,虽然finally语句块执行了,但是,return的值还是100!!
为什么?看看反编译的结果
public static int m(){
int i = 100;
int j = i;
i++;
return j;
}
"不难看出,在反编译的时候,引入了一个新的中间变量,来解决我们的疑惑
Final 、Finally、 Finalize的区别
"final 关键字
final修饰的类无法继承
final修饰的方法无法覆盖
final修饰的变量不能重新赋值。
"finally 关键字
和try一起联合使用。
finally语句块中的代码是必须执行的。
"finalize 标识符
是一个Object类中的方法名。
这个方法是由垃圾回收器GC负责调用的。
实例
public class ExceptionTest14 {
public static void main(String[] args) {
// final是一个关键字。表示最终的。不变的。
final int i = 100;
//i = 200;
// finally也是一个关键字,和try联合使用,使用在异常处理机制中
// 在fianlly语句块中的代码是一定会执行的。
try {
} finally {
System.out.println("finally....");
}
// finalize()是Object类中的一个方法。作为方法名出现。
// 所以finalize是标识符。
// finalize()方法是JVM的GC垃圾回收器负责调用。
Object obj;
}
}
// final修饰的类无法继承
final class A {
// 常量。
public static final double MATH_PI = 3.1415926;
}
class B {
// final修饰的方法无法覆盖
public final void doSome(){
}
}