异常介绍
基本概念
Java语言中,将程序执行中发生的不正常情况称为异常。(开发过程中的语法错误和逻辑错误不是异常)
package com.pero.exception_;
/**
* 异常处理入门
*
* @author Pero
* @version 1.0
*/
public class Exception01 {
public static void main(String[] args) {
int a1 = 10;
int a2 = 0;
// a1 / a2 ,因为分母为0,程序会(抛出)异常 AithmeticException
// 当抛出异常后程序就退出,崩溃了
//异常处理解决该问题,使用try-catch异常处理机制来解决
//从而保障健壮性
//选中代码块->ctrl+alt+t->选中try-catch
//后续代码继续执行
try {
int res = a1 / a2;
} catch (Exception e) {
throw new RuntimeException(e);
}
System.out.println("程序继续执行");
}
}
1.执行过程中所发生的异常事件可分为两类;
1)Error(错误):Java虚拟机无法解决的严重问题。Error是严重错误,程序会崩溃。
2)Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。分为两大类:运行时异常和编译时异常。
2.运行时异常,编译器检查不出来。一般是指编译时的逻辑错误,是程序员应该避免其出现的异常;
3.对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响;
4.编译时异常,是编译器要求必须处理的异常。
package com.pero.exception_;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author Pero
* @version 1.0
*/
public class Exception02 {
public static void main(String[] args) {
try {
FileInputStream fis;
fis = new FileInputStream("d:\\aa.jpg");
int len;
while ((len = fis.read()) != -1){
System.out.println(len);
}
fis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
常见的运行时异常
1)NullPointerException 空指针异常;
当应用程序试图需要对象的地方使用null时,抛出该异常。
package com.pero.exception_;
/**
* 常见异常-空指针异常
*
* @author Pero
* @version 1.0
*/
public class Exception03 {
public static void main(String[] args) {
String name = null;
System.out.println(name.length()); //抛出空指针异常
//Exception in thread "main" java.lang.NullPointerException
// at com.pero.exception_.Exception03.main(Exception03.java:15)
}
}
2)ArithmeticException数学运算异常;
当出现异常的运算条件时,抛出此异常
package com.pero.exception_;
/**
* 常见运行异常-数学运算异常
*
* @author Pero
* @version 1.0
*/
public class Exception04 {
public static void main(String[] args) {
int a = 1;
int b = 0;
double result = a / b; //抛出数学运算异常
//Exception in thread "main" java.lang.ArithmeticException: / by zero
// at com.pero.exception_.Exception04.main(Exception04.java:14)
System.out.println(result);
}
}
3)ArrayIndexOutOfBoundsException数组下标越界异常;
用非法索引访问数组时抛出的异常。如果索引为负数或者大于等于数组的大小,则该索引为非法索引。
package com.pero.exception_;
/**
* 常见运行异常-数组下标越界异常
*
* @author Pero
* @version 1.0
*/
public class Exception05 {
public static void main(String[] args) {
String name = "smith";
for (int i = 0; i <= name.length(); i++) {
System.out.println(name.charAt(i));
}
//当运行至name.charAt(5)时,数组下标越界抛出此异常
//s
//m
//i
//t
//h
//Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 5
// at java.lang.String.charAt(String.java:658)
// at com.pero.exception_.Exception05.main(Exception05.java:14)
}
}
4)ClassCastException类型转换异常;
当试图将对象强制转换为不是实力的子类时,抛出该异常。
package com.pero.exception_;
/**
* 常见运行异常-类型转换异常
*
* @author Pero
* @version 1.0
*/
public class Exception06 {
public static void main(String[] args) {
A b = new B();
B b2 = (B) b; //可以
C c2 = (C) b; //不可以,抛出类型转换异常
//Exception in thread "main" java.lang.ClassCastException: com.pero.exception_.B cannot be cast to com.pero.exception_.C
// at com.pero.exception_.Exception06.main(Exception06.java:13)
}
}
class A{}
class B extends A{}
class C extends A{}
5)NumberFormatException数字格式不正确异常
当程序试图将字符串转换成一种数值类型,但该字符不能转换为适当格式时,抛出该异常
package com.pero.exception_;
/**
* 常见运行异常-数字格式不正确异常
*
* @author Pero
* @version 1.0
*/
public class Exception07 {
public static void main(String[] args) {
String number = "12345678";
//将String 转换成 int
int number1 = Integer.parseInt(number);
String number2 = "正在学习";
int number3 = Integer.parseInt(number2); //抛出数字格式不正确异常
//Exception in thread "main" java.lang.NumberFormatException: For input string: "正在学习"
// at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
// at java.lang.Integer.parseInt(Integer.java:580)
// at java.lang.Integer.parseInt(Integer.java:615)
// at com.pero.exception_.Exception07.main(Exception07.java:17)
}
}
编译异常
编译异常是指在编译期间就必须处理的异常,否则代码不能通过编译。
常见的编译异常
1)SQLException //操作数据库时,查询表可能发生的异常
2)IOException //操作文件时发生的异常
3)FileNotFoundException //当操作一个不存在的文件时发生的异常
4)ClassNotFoundException //加载类而该类不存在时发生的异常
5)EOFException //操作文件到文件末尾发生异常
6)IllegalArguementException //参数异常
异常处理的方式(二选一)
1)try-catch-finally
程序员在代码中捕获发生的异常,自行处理
try{
代码/可能有异常
}catch(Exception e){
//捕获异常
1.当异常发生时,系统将一场封装成Exception对象e,传递给catch
2.得到异常对象后,程序员自己处理
3.如果没有发生异常,catch代码块不执行
}finally{
//不管try代码块是否有异常发生,始终要执行finally
//通常将释放资源的代码放进finally
}
2)throws
将发生异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM
调用:JVM -> main -> 方法f1 -> 方法f2
向上抛出异常:方法f2 —throws—> 方法f1 —throws—> main —throws—> JVM
顶级JVM处理异常:①输出异常信息 ②退出程序
try-catch异常处理
1)Java提供try和catch块来处理异常,try块用于包含可能出错的代码,catch块yongyuchulitry块中发生的异常。可以根据需要在程序中有多个try-catch块;
2)基本语法
try{
//可疑代码
//将发生异常生成对应的异常对象,传递给catch块
}catch(异常){
//对异常处理
}
//如果没有finally,语法上可以通过
try-catch处理异常的注意事项及细节
1)如果异常发生了,则异常后的代码不会执行,直接进入到catch块中;
2)如果异常没有发生,则顺序执行try的代码块,不会进入到catch块中;
3)如果希望不管是否发生异常,都执行某段代码块(比如关闭连接或者释放资源等等)则使用finally{ }块;
4)可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如(Exception在后,NullPointerException在前),如果发生异常值会匹配一个catch;
5)可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。应用场景就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
package com.pero.exception_;
/**
* try-catch实践
*
* @author Pero
* @version 1.0
*/
public class TryCatchDetail {
public static void main(String[] args) throws Exception{
//1)如果异常发生了,则异常后的代码不会执行,直接进入到catch块中;
//2)如果异常没有发生,则顺序执行try的代码块,不会进入到catch块中;
//3)如果希望不管是否发生异常,都执行某段代码块(比如关闭连接或者释放资源等等)则使用finally{ }块
try {
String str = "123456";
int a = Integer.parseInt(str); //如果此处有异常则后面的代码不再执行,直接进入catch块
System.out.println("数字:" + a);
} catch (NumberFormatException e) {
System.out.println("异常信息:"+e.getMessage());
}finally{
System.out.println("finally代码块被执行");
}
System.out.println("程序继续执行"); //此处代码块继续执行
//4)可以有多个catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,
// 比如(Exception在后,NullPointerException在前),如果发生异常值会匹配一个catch;
try {
Person person = new Person();
person = null;
System.out.println(person.getName()); //NullPointerException
int n = 10;
int m = 0;
int res = n / m; //ArithmeticException
}catch (NullPointerException e){
System.out.println("空指针异常:"+e.getMessage());
}catch (ArithmeticException e){
System.out.println("算数异常:"+e.getMessage());
} catch (Exception e) { //父类写在子类之后
System.out.println(e.getMessage());
} finally {
System.out.println("关闭相关资源");
}
//5)可以进行try-finally配合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。
// 应用场景就是执行一段代码,不管是否发生异常,都必须执行某个业务逻辑。
try {
int i = 10;
int j = 0;
System.out.println(i/j);
}finally {
System.out.println("执行了finally");
}
System.out.println("程序继续执行"); //因为异常没有被捕获,程序直接退出,该行代码不会被执行
}
}
class Person{
private String name = "smith";
public String getName() {
return name;
}
}
throws异常处理
1)如果一个方法中的语句执行时可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应该显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理;
2)在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
package com.pero.exception_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/**
* @author Pero
* @version 1.0
*/
public class Throws01 {
public static void main(String[] args) {
}
public void f1() throws FileNotFoundException,NullPointerException,
ArithmeticException /*Exception*/{
//3.显示地声明抛出异常,
// throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
//4.throws 关键字后面也可以是异常列表,即可以抛出多个异常
//创建一个文件流对象
//这里的异常是一个FileNotFoundException 编译异常
//1.可以使用try-catch-finally
//2.可以使用throws,抛出异常,让调用f1方法的调用者处理异常
FileInputStream fis = new FileInputStream("d://aa.txt");
}
}
throws异常处理注意事项和使用细节
1)对于编译异常,程序中必须处理,使用try-catch或者throws
2)对于运行异常,程序中如果没有处理,默认就是throws的处理方式
3)子类重写父类方法时,对抛出异常的规定:子类重写的方法,所抛出的异常类型要么和父类抛出异常一致,要么为父类抛出异常的类型的子类型;
4)在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws。
package com.pero.exception_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
/**
* throws处理异常的使用细节
*
* @author Pero
* @version 1.0
*/
public class ThrowsDetail {
public static void main(String[] args) throws ArithmeticException{ //异常默认处理方式,异常抛给JVM来处理
//JVM直接抛出异常,并退出程序
f2();
}
public static void f2() /*throws ArithmeticException*/{ //异常默认处理方式,异常抛给调用它的方法来处理
//1)对于编译异常,程序中必须处理,使用try-catch或者throws
//2)对于运行异常,程序中如果没有处理,默认就是throws的处理方式
int i = 10;
int j = 0;
double res = i / j;
}
public static void f1() /*throws FileNotFoundException*/{
//因为f3()方法抛出编译异常
//这时要求f1()方法必须处理这个编译异常
//使用try-catch-finally或者throws来处理异常
try {
f3();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} finally {
}
}
public static void f4() /*throws ArithmeticException*/{
//在f4()中调用f5()不报异常错误
//因为f5()抛出的是运行异常,Java中不要求程序员显示处理,因为有默认处理机制
f5();
}
public static void f5() throws ArithmeticException{ //这是一个运行异常
}
public static void f3() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d://aa.txt");
}
}
class Father{
public void method() throws RuntimeException{
}
}
class Son extends Father{
@Override
public void method() throws RuntimeException/*NullPointerException*/ {
//3)子类重写的方法,所抛出的异常类型要么和父类抛出异常一致,要么为父类抛出异常的类型的子类型;
//4)在throws过程中,如果有方法try-catch,就相当于处理异常,就可以不必throws。
super.method();
}
}
自定义异常
基本概念
当程序中出现了某些“错误”,但是该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息。
自定义异常的步骤
1)定义类:自定义异常类名继承Exception或RuntimeException;
2)如果继承Exception,属于编译异常;
3)如果继承RuntimeException,属于运行异常(一般来说继承RuntimeException)。
package com.pero.exception_;
/**
* @author Pero
* @version 1.0
*/
public class CustomException {
public static void main(String[] args) throws AgeException{
int age = 80;
if (!(age >= 18 && age <= 120)){
throw new AgeException("年龄需要在 18~120岁。");
}else {
System.out.println("你的年龄范围正确。");
}
}
}
//自定义的异常
class AgeException extends RuntimeException{
public AgeException(String message) { //构造器
super(message);
}
}
throw和throws的区别
意义 位置 后面跟的东西
throw 手动生成异常对象的关键词 方法体中 异常对象
throws 异常处理的一种方式 方法声明处 异常类型
package com.pero.exception_;
/**
* @author Pero
* @version 1.0
*/
public class ReturnExceptionDemo {
public static void main(String[] args) {
try {
ReturnExceptionDemo.methodA();
} catch (Exception e) {
System.out.println(e.getMessage());
}
ReturnExceptionDemo.methodB();
}
static void methodA(){
try {
System.out.println("进入方法A");
throw new RuntimeException("制造异常");
} finally {
System.out.println("执行方法A中的finally");
}
}
static void methodB(){
try {
System.out.println("进入方法B");
return;
} finally {
System.out.println("执行方法B中的finally");
}
}
}