在Java等面向对象的语言中,异常本身是一个类,产生异常就是创建并抛出一个异常对象。Java处理异常的方式是中断处理。
异常并不是语法错误。
Throwable是Java中所有错误和异常的父类。
Throwable体系:
1.Error:严重错误,无法处理的错误,只能事先避免;
2.Exception:异常,可以通过代码纠正。
Exception:编译期异常
RuntimeException:运行期异常
处理方式:
1.抛给虚拟机处理
2.使用try/catch
package lch;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class fangfa {
public static void main(String[] args){
//编译期异常:
SimpleDateFormat sdf1 = new SimpleDateFormat();
try {
sdf1.parse("1999-09-09");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("后续代码1");
//运行期异常:
int[] arr = {
1,2,3};
try {
System.out.println(arr[3]);;
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("后续代码2");
//错误,必须修改代码
int[] arr2 = new int[1024*1024*1024];
System.out.println("后续代码3");
}
}
1.根据异常产生的原因创建一个异常对象,这个异常对象包含了异常产生的内容,原因,位置;
2.在发生错误的方法中如果没有try…catch的异常处理逻辑,那么JVM会把异常抛出给方法的调用者main方法来处理这个异常;
3.main方法接收到异常对象,如果main方法也没有异常处理机制,则继续把异常对象抛出给main方法的调用者JVM处理;
4.JVM接收到异常对象,会把异常对象的内容、原因、位置打印在控制台,并终止当前正在运行的Java程序(中断处理)。
package lch;
public class fangfa {
public static void main(String[] args){
int a[] = {
1,2,3,4,5,6};
System.out.println(getElement(a, 6));
}
public static int getElement(int[] a, int index){
return a[index];
}
}
使用throw关键字在指定的方法中抛出指定的异常。
格式:throw new xxxException("异常产生的原因");
throw关键字必须写在方法内部;
throw后new的关键字必须是Exception或Exception的子类;
throw抛出的异常对象,如果是RuntimeException或其子类,可以不处理,默认交给JVM处理;如果是编译异常,必须自行处理。
package lch;
public class fangfa {
public static void main(String[] args){
int a[] = {
1,2,3,4,5,6};
System.out.println(getElement(a, 6));
int a2[] = null;
System.out.println(getElement(a2, 0));
}
public static int getElement(int[] a, int index){
if(a==null){
//NullPointerException和ArrayIndexOutOfBoundsException是一个运行期异常,可以不自行处理
throw new NullPointerException("数组为空!");
}
if(index >= a.length){
throw new ArrayIndexOutOfBoundsException("数组越界!");
}
return a[index];
}
}
Objects是空指针安全的,因为对null值进行了抛出异常操作。
package lch;
import java.util.Objects;
public class fangfa {
public static void main(String[] args){
int a[] = null;
Objects.requireNonNull(a);
}
}
异常处理的第一种方式:交给别人处理。
1.throws必须写在方法声明处。
2.throws声明的对象必须是Exception或其子类。
3.方法内部如果抛出了多个异常,throws必须也声明多个异常。如果抛出的对象有子父类关系,直接声明父类即可。
4.调用了一个声明抛出异常的方法,就必须处理声明的异常。要么继续使用throws抛出,要么try…catch。
package lch;
import java.io.FileNotFoundException;
import java.io.IOException;
public class fangfa {
public static void main(String[] args) throws IOException{
judge("C:\\a.txt");
}
public static void judge(String str) throws IOException{
if(!str.endsWith(".txt")){
throw new IOException();
}
if(!str.equals("C:\\a.txt")){
throw new FileNotFoundException();
}
}
}
格式:try{可能异常的代码}catch(定义一个异常变量,用来接收抛出的异常){异常的处理逻辑}
1.可以使用多个catch;
2.如果try中产生了异常,那么就会执行catch中的处理逻辑,然后继续执行try…catch之后的代码。
package lch;
import java.io.FileNotFoundException;
import java.io.IOException;
public class fangfa {
public static void main(String[] args){
try{
judge("qsw");
System.out.println("后续代码1");
}catch(FileNotFoundException e){
System.out.println("后缀错误");
}catch(IOException e){
System.out.println("名称错误");
}
System.out.println("后续代码2");
}
public static void judge(String str) throws IOException{
if(!str.endsWith(".txt")){
throw new IOException();
}
if(!str.equals("C:\\a.txt")){
throw new FileNotFoundException();
}
}
}
package lch;
import java.io.FileNotFoundException;
import java.io.IOException;
public class fangfa {
public static void main(String[] args){
try{
judge("qsw");
System.out.println("后续代码1");
}catch(IOException e){
System.out.println(e);
System.out.println(e.toString());
e.printStackTrace();
}
System.out.println("后续代码2");
}
public static void judge(String str) throws IOException{
if(!str.endsWith(".txt")){
throw new IOException();
}
if(!str.equals("C:\\a.txt")){
throw new FileNotFoundException();
}
}
}
finally必须和try一起使用,修饰的代码无论程序是否出现异常,都会执行。
finally一般用于资源释放,因为无论程序是否出现异常,我们都需要释放资源。
package lch;
import java.io.FileNotFoundException;
import java.io.IOException;
public class fangfa {
public static void main(String[] args){
try{
judge("qsw");
System.out.println("后续代码1");
}catch(IOException e){
e.printStackTrace();
}finally{
System.out.println("无论是否出现异常,都需要执行的代码");
}
System.out.println("后续代码2");
}
public static void judge(String str) throws IOException{
if(!str.endsWith(".txt")){
throw new IOException();
}
if(!str.equals("C:\\a.txt")){
throw new FileNotFoundException();
}
}
}
多个catch定义的异常变量,如果有子父类关系,子类必须写在前面,否则就会报错。
多个异常一次捕获多次处理:
package lch;
import java.util.List;
public class fangfa {
public static void main(String[] args){
int a[] = {
1,3,5};
List<Integer> list1 = List.of(1,3,5);
try{
System.out.println(a[3]);
System.out.println(list1.get(3));
}catch(ArrayIndexOutOfBoundsException e1){
e1.printStackTrace();
}catch(IndexOutOfBoundsException e2){
e2.printStackTrace();
}
}
}
多个异常一次捕获一次处理:
package lch;
import java.util.List;
public class fangfa {
public static void main(String[] args){
int a[] = {
1,3,5};
List<Integer> list1 = List.of(1,3,5);
try{
System.out.println(a[3]);
System.out.println(list1.get(3));
}catch(IndexOutOfBoundsException e2){
e2.printStackTrace();
}
}
}
如果finally中有return语句,永远返回finally中的结果。(需要避免这种情况)
package lch;
public class fangfa {
public static void main(String[] args){
System.out.println(method1());
}
public static int method1(){
int a = 10;
try{
return a;
}catch(Exception e){
e.printStackTrace();
}finally{
return 20;
}
}
}
如果父类抛出多个异常,子类重写父类方法时,抛出和父类相同的异常或父类异常的子类或不抛出异常。
如果父类没有抛出异常,子类重写父类方法时也不可抛出异常,此时子类产生该异常,只能捕获处理,不能声明抛出。
自定义异常类继承Exception,那么自定义异常类就是一个编译器异常。
继承RuntimeException,那么自定义异常类就是一个运行期异常。
package lch;
public class RegisterException extends Exception{
public RegisterException(){
super();
}
public RegisterException(String message){
super(message);
}
}
package lch;
import java.util.Scanner;
public class fangfa {
public static void main(String[] args) throws RegisterException{
String[] name = {
"alex", "bob", "cindy"};
System.out.println("请输入要注册的用户名:");
Scanner sc = new Scanner(System.in);
String username = sc.next();
check(name, username);
}
public static void check(String[] name, String username) throws RegisterException{
for(String str : name){
if(str.equals(username)){
throw new RegisterException("该用户名已被注册!");
}
}
}
}