异常有3中处理方式,分别是:
①JVM默认的处理方式
②自己处理
③抛出异常
●把异常的名称,异常原因及异常出现的位置等信息输出在了控制台(以红色字体)
●程序停止执行,下面的代码不会再执行了
public class ExceptionDemo1 {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
System.out.println(arr[5]);
// 异常后的代码
System.out.println("看看我执行了吗?");
}
}
以上代码将会抛出java.lang.ArrayIndexOutOfBoundsException,由于采用的是JVM默认的处理方式,因此在执行输出语句时遇到异常后将停止执行,异常出现后的代码将不会执行。
格式:
try {
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
目的:当代码出现异常时,可以让程序继续往下执行。
public class ExceptionDemo1 {
public static void main(String[] args) {
// 定义一个数组
int[] arr = {1, 2, 3, 4, 5};
try {
// 可能出现异常的代码
System.out.println(arr[5]); //此处出现了异常,程序就会在这里创建一个ArrayIndexOutOfBoundsException对象
// new ArrayIndexOutOfBoundsException();
//拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接收这个对象
// 如果能被接收,就表示该异常就被捕获(抓住),执行catch里面对应的代码
// 当catch里面所有的代码执行完毕,继续执行try...catch体系下面的其他代码
}catch (ArrayIndexOutOfBoundsException e){
// 如果出现了ArrayIndexOutOfBoundsException异常
// 要采取的操作
System.err.println("数组越界!");
}
// 异常后的代码
System.out.println("看看我执行了吗?");
}
}
灵魂一问:如果try中没有遇到问题,怎么执行?
会把try里面所有的代码全部执行完毕,不会执行catch里面的代码。
注意:只有当出现了异常才会执行catch里面的代码
灵魂二问:如果try中可能会遇到多个问题,怎么执行?
会写多个catch与之对应
细节:
如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
了解性:
在JDK7之后,我们可以在catch中同时捕获多个异常,中间用竖线|进行隔开表示如果出现了A异常或者B异常的话,采取同一种处理方案,如下:
try {
// 代码
}catch (ArrayIndexOutOfBoundsException | NullPointerException e){
System.err.println("出现异常!");
}
灵魂三问:如果try中遇到的问题没有被捕获,怎么执行?
相当于try...catch的代码白写了,最终还是会交给虚拟机进行处理。
灵魂四问:如果try中遇到了问題,那么try下面的其他代码还会执行吗?
try语句块下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体,但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理。
方法名称 |
说明 |
public String getMessage() |
返回此throwable的详细消息字符串 |
public String tostring() |
返回此可抛出的简短描述 |
public void printStackTrace() |
把异常的错误信息输出在控制台 |
Idea快捷键Ctrl+Alt+T可以把选中的代码快速包裹进语句块。
方法printStackTrace()打印异常的详细信息,但不会停止程序运行。
写在方法定义处,表示声明一个异常告诉调用者,使用本方法可能会有哪些异常。格式如下:
public void myMethod() throws ArrayIndexOutOfBoundsException, NullPointerException{
// 方法的代码
}
●编译时异常:必须要写。
●运行时异常:可以不写。
写在方法内,结束方法,表示手动抛出异常对象,交给调用者,方法中下面的代码不再执行了。
public void myMethod(){
// 方法的代码
throw new NullPointerException();
}
如下代码:
public class ExceptionDemo3 {
public static void main(String[] args) {
int[] arr = {1};
System.out.println(getMax(arr));
}
/**
* 获取数组中的最大值
* @param arr 数组
* @return 最大值
*/
public static int getMax(int[] arr){
if (arr == null){
//手动创建一个异常对象,并把这个异常交给方法的调用者处理
// 此时方法就会结束,下面的代码不会再执行了
// 抛出空指针异常
throw new NullPointerException();
}else if(arr.length == 0){
// 抛出越界异常
throw new ArrayIndexOutOfBoundsException();
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max){
max = arr[i];
}
}
return max;
}
}
1.虚拟机默认处理异常的方式
把异常信息以红色字体打印在控制台,并结束程序
2.捕获:try…catch
捕获的主要作用是不让程序停止。
一般用在调用处,能让代码继续往下运行。
3.抛出:throw throws
抛出的主要作用是告诉调用者出错了。
在方法中,出现异常了。方法就没有继续运行下去的意义了,采取抛出处理。让该方法结束运行并告诉调用者出现了问题。
需求:
键盘录入自己心仪的女朋友姓名和年龄。
姓名的长度在3~10之间,
年龄的范围为18-40岁,
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。比如:录入年龄时超出范围,录入年龄时录入了abc等情况
import java.util.Scanner;
public class GirlfriendInput {
public static void main(String[] args) {
//1.创建键盘录入的对象
Scanner sc = new Scanner(System.in);
//2.创建女朋友的对象
Girlfriend gf = new Girlfriend();
while (true) {
//3.接收女朋友的姓名
try {
System.out.println("请输入你心仪的女朋友的名字");
String name = sc.nextLine();
gf.setName(name);
//4.接收女朋友的年龄
System.out.println("请输入你心仪的女朋友的年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
//如果所有的数据都是正确的,那么跳出循环
break;
} catch (NumberFormatException e) {
System.out.println("年龄的格式有误,请输入数字");
//continue;
} catch (RuntimeException e) {
System.out.println("姓名的长度或者年龄的范围有误");
//continue;
}
}
//5.打印
System.out.println(gf);
}
}
Girlfriend类代码:
public class Girlfriend {
private String name;
private int age;
public Girlfriend() {
}
public Girlfriend(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
int len = name.length();
if (len < 2 || len > 10){
// 如果姓名长度不对,则抛出异常
throw new RuntimeException();
}
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
if (age < 18 || age > 40){
// 如果年龄不符合要求,抛出异常
throw new RuntimeException();
}
this.age = age;
}
public String toString() {
return "Girlfriend{name = " + name + ", age = " + age + "}";
}
}
自定义异常的步骤与方法:
①定义异常类,类名要见名知意
②要写继承关系:运行时异常继承于RuntimeException、编译时异常继承于Exception
③空参构造
④带参构造
意义:就是为了让控制台的报错信息更加的见名知意
Alt+Insert快捷键快速生成代码块。
上例中,我们可以自定义两个异常,分别用于姓名和年龄输入不符合要求时抛出:
姓名格式不符合要求的异常:
public class NameFormatException extends RuntimeException{
//技巧:
//NameFormat:当前异常的名字,表示姓名格式化问题
//Exception:表示当前类是一个异常类
//运行时:RuntimeException核心就表示由于参数错误而导致的问题
//编译时:Exception核心提醒程序员检查本地信息
// Alt + Insert插入2个构造方法:空参和带参
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
年龄输入不符合要求时的异常:
public class AgeOutOfBoundsException extends RuntimeException{
public AgeOutOfBoundsException() {
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}