概述
- 所有的 Exception 都是在运行时发生,因为异常的产生是需要new 对象的;
- 不建议在main方法上使用throws,如果该异常真正发生就会抛给JVM,JVM会终止线程。
编译时异常
- 编译时异常是指 在编写程序的时候,需要预先对这种异常进行处理,不处理的话编译器报错;
- 编译时异常一般发生的概率较高;
- 编译时异常又称为受检异常(受控异常 Checked Exception)。
运行时异常
-
RuntimeException 及子类均属于运行时异常,在编写程序阶段可以选择处理也可以选择不处理;
-
运行时异常一般发生的概率比较低;
-
运行时异常又被称为非受检异常(非受控异常 UnChecked Exception))。
- 在方法声明的位置,使用throws关键字抛给上一级,谁调用就抛给谁,同时调用者也需要对该异常继续处理,同样也有两种处理方式;
- Java中异常发生之后如果一直上抛,最终会抛给nain方法,main方法继续向上抛,抛给了调用者JVM,JVM感知到该异常发生,终止程序;
- throws 抛出 受检异常和非受检异常有区别。
throws 受检异常 && 非受检异常
- 调用doSome()方法如果不对ClassNotFoundException异常进行处理,编译器会提示 Unhandled exception: java.lang.ClassNotFoundException,因为ClassNotFoundException 属于受检异常,在编写代码阶段必须进行处理;
- 调用doAny时,不需要对ArithmeticException异常进行处理,因为ArithmeticException 属于非受检异常,在编写代码阶段不需要进行处理。
public class ExceptionTest02 {
public static void main(String[] args) throws ClassNotFoundException {
//调用doSome时,需要对ClassNotFoundException异常进行处理,因为ClassNotFoundException 属于受检异常
doSome();
//调用doAny时,不需要对ArithmeticException异常进行处理,因为ArithmeticException 属于非受检异常
doAny();
}
/**
* 1.以下代码表示doSome()方法在执行过程中,可能会出现ClassNotFoundException异常
* 2.ClassNotFoundException属于编译时异常,在代码编写的时候需要处理
* @throws ClassNotFoundException
*/
static void doSome() throws ClassNotFoundException{
}
static void doAny() throws ArithmeticException{
}
}
2.2 try catch
概述
- catch(Exception e)括号内的e可以是该方法抛出的特定异常 ,也可以是其父类;
- 多个catch块的情况下,捕捉到一个异常即停止;
- 多个catch块捕捉异常的顺序:先子类后父类。
测试
- catch()捕获的异常类型分别为
- FileNotFoundException
- FileNotFoundException的父类IOException
- 抛出FileNotFoundException的父类IOException的父类Exception
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionTest05 {
/**
* 1.抛出 FileNotFoundException
* catch (FileNotFoundException e) {
*
* }
* @param args
*/
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("dd");
} catch (FileNotFoundException e) {
System.out.println("exception");
}
System.out.println("2022-04-24");
}
/**
* 2.抛出FileNotFoundException的父类IOException
* catch (IOException e) {
*
* }
* @param args
*/
/* public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("dd");
} catch (IOException e) {
System.out.println("exception");
}
System.out.println("2022-04-24");
}*/
/**
* 3.抛出FileNotFoundException的父类IOException的父类Exception
*catch (Exception e) {
*
* }
* @param args
*/
/* public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("dd");
} catch (Exception e) {
System.out.println("exception");
}
System.out.println("2022-04-24");
}*/
}
/*
以上输出均为
exception
2022-04-24
*/
- 多个catch块的情况,捕捉到一个异常即停止。
public class ExceptionTest06 {
public static void main(String[] args) {
FileInputStream dd = null;
try {
dd = new FileInputStream("dd");
dd.read();
} catch (FileNotFoundException e) {
System.out.println("文件不存在");
}catch (IOException e){
System.out.println("文件读取错误");
}
System.out.println("main over");
}
}
//文件不存在
//main over
-
多个catch块捕捉异常的顺序:先子类后父类。
在ExceptionTest06.java中先捕获IOException再捕获其子类FileNotFoundException,会提示
Exception ‘java.io.FileNotFoundException’ has already been caught
public class ExceptionTest06 {
public static void main(String[] args) {
FileInputStream dd = null;
try {
dd = new FileInputStream("dd");
dd.read();
} catch (IOException e){
System.out.println("文件读取错误");
}catch (FileNotFoundException e) {
System.out.println("文件不存在");
}
System.out.println("main over");
}
}
// 提示 Exception 'java.io.FileNotFoundException' has already been caught
2.3 throws和try catch的选择
- 如果希望调用者来处理或者希望调用者感知到异常,选择 throws;
- 其他选择try catch。
概述
-
String message = e.getMessage(); 获取异常简单的描述信息;
-
e.printStackTrace() 异步执行,打印异常的追踪堆栈信息
**【注意】**ExceptionTest07.java中"main over"的输出和nullPointerException.printStackTrace() 的输出顺序不确定,因为e.printStackTrace()是异步执行。
测试
public class ExceptionTest07 {
public static void main(String[] args) {
NullPointerException nullPointerException = new NullPointerException("空指针异常-2022-04-24");
String message = nullPointerException.getMessage();
System.out.println(message);
// 异步输出
nullPointerException.printStackTrace();
System.out.println("main over");
}
}
/*
空指针异常-2022-04-24
main over
java.lang.NullPointerException: 空指针异常-2022-04-24
at exceptionTest.ExceptionTest07.main(ExceptionTest07.java:5)
*/
4. finally
概述
- finally语句块通常用于完成资源的释放和关闭;
- finally和return连用时,会在函数返回之前调用finally中的语句;
- finally语句一定执行 (除非在执行finally语句之前退出jvm)。
测试
- ExceptionTest08.java中,try中的s.toString()会造成空指针异常,导致下面的fis.close()无法执行,若没有finally语句块,则会导致FileInputStream未关闭;
- 使用finally语句块用来确保资源的释放和关闭。
public class ExceptionTest08 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\test.txt");
System.out.println("读取结束后请关闭流");
String s = null;
s.toString();
// 以上代码会造成空指针异常,以下代码不会执行,流还未关闭
System.out.println("尝试关闭流");
fis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NullPointerException e){
System.out.println("捕捉空指针异常");
}finally {
if (fis != null) {
try {
fis.close();
System.out.println("关闭fis流");
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println("main over");
}
}
//读取结束后请关闭流
//捕捉空指针异常
//关闭fis流
//main over
- ExceptionTest09.java中,finally和return连用,会在return返回之前执行finally中的语句。
public class ExceptionTest09 {
public static void main(String[] args) {
try {
System.out.println("try...");
return;
}finally {
System.out.println("finally...");
}
//以下代码会提示 Unreachable statement
System.out.println("xx");
}
}
//try...
//finally...
- finally语句不一定执行,退出jvm之后,finally语句不执行。
public class ExceptionTest10 {
public static void main(String[] args) {
try {
System.out.println("try...");
//System.exit(0)
System.exit(0);
}finally {
System.out.println("finally...");
}
}
}
//try...
- 【特殊情况】ExceptionTest11.java 程序执行结果为100
- 方法体中的代码必须遵循自上而下顺序依次逐行执行
- return语句一且执行,整个方法必须结束
public class ExceptionTest11 {
public static void main(String[] args) {
System.out.println(m()); //【输出】100
}
private static int m() {
int i = 100;
try {
return i;
}
finally {
i++;
}
}
}
5. finally&final&finalize
5.1 finally
-
和try连用,finally语句一定执行 (除非在执行finally语句之前退出jvm);
-
finally语句块通常用于完成资源的释放和关闭;
-
finally和return连用时,会在函数返回之前调用finally中的语句。
- final修饰的类无法被继承;
- final修饰的方法无法被覆盖;
- final修饰局部变量只能赋一次值,一旦赋值则不能再重新赋值;
- final修饰的引用一旦指向某个对象,则不能再重新指向其他对象,但该引用指向的对象的内部数据是可以修改的;
- final修饰的实例变量必须手动初始化,不能采用系统默认值。
public class Stu {
String name;
final String country;
}
// 报错提示 Variable 'country' might not have been initialized
- final修饰的实例变量一般和static联合使用,称为常量
概念
-
是object类中的一个方法名,该方法由垃圾回收器gc调用;
-
finalize()是protected修饰的,如下
protected void finalize() throws Throwable { }
-
该方法只有一个方法体且里面没有代码;
-
不需要程序员手动调用,JVM垃圾回收器负责调用该方法;
-
finalize()方法的执行时机;
当一个java对象即将被垃圾回收期回收的时候,垃圾回收器负责调用finalize()方法;
-
是垃圾销毁的时机,如果希望在对象销毁的时候执行一段代码的话,这段代码写到finalize方法当中;
-
不像equals方法重写之后需要写代码调用,finalize()方法只需要重写,重写完自动会有程序来调用。
测试
- 创建100000个对象
public class FinalizeTest {
public static void main(String[] args) {
for (int i = 0; i < 100000; i++){
Person person = new Person();
person = null;
}
}
}
class Person {
String name;
@Override
protected void finalize() throws Throwable {
System.out.println(this + "即将被销毁!");
}
}
/*
objectTest.Person@1bb3fcd即将被销毁!
objectTest.Person@17cc18a即将被销毁!
objectTest.Person@14354bd即将被销毁!
objectTest.Person@41cbb1即将被销毁!
objectTest.Person@dcc0e3即将被销毁!
*/
- 测试
System.gc();
,建议启动垃圾回收器。
public class FinalizeTest {
public static void main(String[] args) {
for (int i = 0; i < 10; i++){
Person person = new Person();
person = null;
System.gc();
}
}
}
class Person {
String name;
@Override
protected void finalize() throws Throwable {
System.out.println(this + "即将被销毁!");
}
}
//objectTest.Person@1bb3fcd即将被销毁!
//objectTest.Person@17cc18a即将被销毁!
6. 自定义异常类
步骤
- 编写类继承Exception或者RuntimeException;
- 继承Exception 是编译时异常
- 继承RuntimeException是运行时异常
- 提供两个构造方法,无参 + 带有String参数的。
public class ExceptionTest12 {
public static void main(String[] args) {
MyException e = new MyException("自定义异常");
e.printStackTrace();
System.out.println(e.getMessage());
}
/* 自定义异常
exceptionTest.MyException: 自定义异常
at exceptionTest.ExceptionTest12.main(ExceptionTest12.java:5)
*/
}
7. 异常和方法覆盖
- 重写之后的方法不能比重写之前的方法抛出更多(更宽泛)的异常,可以更少。
public class ExceptionTest13 {
}
class Animal{
public void doSome(){
}
public void doOther() throws Exception{
}
}
class Cat extends Animal{
/**
* 【提示】
* 'doSome()' in 'exceptionTest.Cat' 【clashes】 with 'doSome()' in 'exceptionTest.Animal';
* overridden method does not throw 'java.lang.Exception
* @throws Exception
*/
public void doSome() throws Exception{
}
/**
* 不抛出异常ok
*/
/* public void doOther(){
}*/
/**
* 抛出更小的异常ok
* @throws NullPointerException
*/
public void doOther() throws NullPointerException {
}
}
8. 关于异常产生后后续代码是否继续执行
ExceptionTest01.java中 “2022-04-24” 不会输出
- ArithmeticException继承RuntimeException 属于运行时异常,在编写阶段不需要处理异常。
public class ExceptionTest01 {
public static void main(String[] args) {
System.out.println(100/0);
/*
程序执行发生了ArithmeticException异常,底层new了一个ArithmeticException异常对象
由于该方法是main方法调用,所以该异常抛给了main方法,main方法没有处理,将该异常自动抛给了JVM
JVM终止程序的运行
*/
System.out.println("2022-04-24");
}
}
public class ArithmeticException extends RuntimeException {
}
try && throws
- try语句块中某一行出现异常,之后的代码不执行;
- 采用throws方式时,只要异常没有被捕捉,此方法的后续代码不会执行,比如m1 over和m2 over均未执行。
public class ExceptionTest04 {
public static void main(String[] args) {
System.out.println("main start");
try {
m1();
//try语句块中某一行出现异常,之后的代码不执行
System.out.println("异常之后代码不执行");
} catch (FileNotFoundException e) {
System.out.println("exception");
}
System.out.println("end");
}
private static void m1() throws FileNotFoundException {
System.out.println("m1 start");
m2();
//只要异常没有捕捉,采用throws方式 此方法的后续代码不会执行
System.out.println("m1 over");
}
private static void m2() throws FileNotFoundException {
new FileInputStream("D:\source");
//出异常之后的代码不执行
System.out.println("m2 over");
}
}
/*
m1 start
exception
end
*/
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)