异常概念
1.异常是指程序在运行过程中遇到了一些无法处理的情况,这时JVM会向控制台打印错误信息,并停止程序。
这不是我们想看到的结果,基于此,Java为我们提供了一种异常处理机制可以使我们程序发生异常情况时,可以跳过代码的异常,继续向下执行。
2.JVM处理异常的默认方式;
1).JVM执行到有异常的代码;2).JVM会识别出这种异常;3).JVM会到类库中找到描述这种异常的异常类——JVM为每种异常情况都定义了异常类。并创建了异常对象;4).JVM会到代码中查看我们的代码是否捕获这种异常:
是:JVM会执行异常处理代码-catch 否:JVM会向控制台打印异常信息,并结束程序。
异常和错误的区别:
Throwable(所有异常跟错误的根类)
1 Error(错误):我们不需要捕获,因为捕获也没有意义
2 Exception(异常):我们程序需要捕获并处理的
1)RuntimeException(运行时异常)
2)其它的异常(编译期异常)
常见的运行时异常:
1.空指针异常---NullPointerException:
例子:
int[] arr1 = null;
System.out.println(arr1.length);
//NullPointerExcepiton--空指针异常
2.数据索引越界异常---ArrayIndexOutOfBoundsException
例子:
int[] arr2 = {1,2,3};
System.out.println(arr2[30]);
//ArrayIndexOutOfBoundsException--数组索引越界异常
3.字符串索引越界异常---StringIndexOutOfBoundsException
例子:
String str = "Hello";
System.out.println(str.charAt(30));
//StringIndexOutOfBoundsException--字符串索引越界
4.数学运算异常---ArithmaticException
例子:
int a = 10 / 0;
System.out.println("a = " + a);
//ArithmeticException--数学运算异常
异常处理throw抛出
例子:
public class Demo {
public static void main(String[] args) {
int[] arr = null;
if(arr == null){
//抛出异常--抛给此方法的调用者--JVM
throw new NullPointerException("空指针异常!");
}
System.out.println(arr.length);
}
}
异常处理Objects requireNonNull方法
例子:
class Student{
private String name;
private String address;
public Student(String name,String address){
/*
if(name == null){
//抛出异常--相当于return,立即结束方法,向调用者返回一个异常对象
throw new NullPointerException("名字不能为null");
}
if(address == null){
throw new NullPointerException("地址不能为null");
}
*/
//Objects的requeireNonNull()方法内部会判断参数是否为null,是:抛出异常
//这样就不需要我们自己判断,它会为我们判断。
this.name = Objects.requireNonNull(name);
this.address = Objects.requireNonNull(address);
}
}
main(){
Student stu = new Student(null,"北京");
}
异常处理throws声明抛出
例子:
public static void main(String[] args) {
int[] arr = {432,43,24,32,432,43,24,3243};
int r = sum(null);
System.out.println("累加和是" + r);
}
//throws的作用:告诉JVM,我这个方法中可能会抛出这个异常,如果真的发生这个异常
//请将这个异常对象抛给"调用处"。
public static int sum(int[] arr) throws NullPointerException,
ArrayIndexOutOfBoundsException{
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
注意:1.如果throws抛出的是“运行时异常”,调用处可以不处理,编译会通过,但如果真的出现异常,仍然会终止程序
2.如果throws跑出的是“编译期异常”,调用处必须处理(try...catch抛出),否则编译错误。
异常处理try...catch语句
格式:
try{
//可能出现异常的代码
}catch(异常类型名 变量名){
//如果try中出现了与“异常类型名”一样的异常,就会执行这个catch语句
}
例子:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("请输入年龄:");
try {
int age = sc.nextInt();
System.out.println("你的年龄是:" + age);
break;
} catch (InputMismatchException e) {
sc = new Scanner(System.in);
System.out.println("哥们,请输入数字!");
}
}
System.out.println("后续程序...");
}
异常处理 异常对象的操作
变量名.getMessage(); 异常信息
变量名.toString(); 异常类名+异常信息
变量名.printStacktrace(); 常用在测试的时候,上线后写日志
例子:
public class Tets {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("异常信息:"+e.getMessage());
System.out.println("toString:"+e.toString());
e.printStackTrace();
}
}
}
结果为:
异常信息:10
toString:java.lang.ArrayIndexOutOfBoundsException: 10
java.lang.ArrayIndexOutOfBoundsException: 10
at cn.itcast.demo01.Tets.main(Tets.java:7)
异常处理 多catch语句
基本格式:try{
//...
//...
//...
}catch(异常类名1 变量名){
}catch(异常类名2 变量名){
}...
代码:
public class Test {
public static void main(String[] args) {
try {
int[] arr = null;
System.out.println(arr.length);
int[] arr2 = {1, 2, 3};
System.out.println(arr2[4]);
int a = 10 / 0;
System.out.println(a);
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数据索引越界异常");
} catch (ArithmeticException e) {
System.out.println("数学运算异常");
} catch (Exception e) {
System.out.println("其它的异常,由我来处理");
System.out.println("我只能写在多个catch的最后");
}
}
}
运行结果:空指针异常
注意:这种写法假如第一个catch语句执行后后面的就不会执行了。
假如第一个出异常,还想执行后面的,就必须分开来写。
例如:
public class Test1 {
public static void main(String[] args) {
try {
int[] arr = null;
System.out.println(arr.length);
} catch (NullPointerException e) {
System.out.println("空指针异常");
}
try {
int[] arr2 = {1, 2, 3};
System.out.println(arr2[4]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数据索引越界异常");
}
}
}
空指针异常
数据索引越界异常
异常处理 try_catch_finally
格式:try{
...
}catch(异常类型名 变量名){
...
}finally{
...//无论是否出现异常都会被执行的代码 ,尤其在方法中,当try中有return时,需要关闭资源时尤其有用。
}
例如:
public class Test2 {
public static void main(String[] args) {
try {
System.out.println("打开文件...");
System.out.println("读取文件...");
int a = 10 / 0;
return "文件内容";//在执行return的过程中,会去调用finally
} catch (Exception e) {
System.out.println("出现异常");
return null;
} finally{
System.out.println("关闭文件");
}
}
}
自定义异常
在我们的程序中,根据某些业务,需要抛出某种异常,但类库中没有,这时我们就可以自定义异常。
例如:
public class Student{
private int age;
public void setAge(int age){
if(age<15||age>50){
//必须要想办法通知调用出,这个参数不正确
//抛出异常
throw new 自定义异常对象();
}
this.age=age;
}
}
自定义异常继承RuntimeException(运行时异常)演示:
自定义异常
public class AgeException extends RuntimeException{
public AgeException(){
}
public AgeException(String message){
super(message);
}
}
使用自定义异常
public class Student{
private int age;
public void setAge(int age){
if(age<15||age>50){
throw new AgeException("年龄必须在15到50之间")
}
this.age=age;
}
}
测试类
public class Demo{
public static void main(String[] args)
Student stu=new Student();
try{
stu.setAge(10);
}catch(AgeException e){
System.out.println("异常信息:"+e.getMessage());
}
}
这个结果就为自己定义所抛出的那句话
自定义类继承自Exception(编译期异常)演示
自定义异常
public class NameException extends Exception{
public NameException() {
}
public NameException(String message) {
super(message);
}
}
使用自定义异常
public class Person {
private String name;
public Person(String name) throws NameException {
if (name == null) {
throw new NameException("请输入名字");
}
this.name = name;
}
}
测试类
public class Test {
public static void main(String[] args) {
try {
Person p = new Person(null);
} catch (NameException e) {
System.out.println(e.getMessage());
}
}
}
结果就为使用自定义异常时要抛出的那句话
异常_子类重写父类方法时的异常抛出
calss Fu{
public void show(){} //不抛出任何异常
public void show2()throws NullPointerException{} //抛出运行时异常
public void show3()throws IOException{} //编译期异常
}
class Zi extends Fu{
//子类重写这三个方法
1)不抛任何异常
2)可以抛出任何的运行时异常
3)不能抛出比父类更多的编译期异常
}
异常注意事项:
运行时异常被抛出可以不处理,既不捕获也不声明抛出
如果父类抛出了多个异常,子类覆盖父类方法时,只能抛出相同的异常或者是它的子集
父类方法没有抛出异常,子类覆盖父类该方法时也不可抛出异常,子类产生异常,只能捕获处理,不能声明抛出