1.异常概念
异常,就是不正常的意思。在生活中:医生说,你的身体某个部位有异常,该部位和正常相比有点不同,该部位的功能将受影响.在程序中的意思就是:
异常 :指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。
异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行
2.异常体系和异常分类
3.抛出异常throw
在编写程序时,我们必须要考虑程序出现问题的情况。比如,在定义方法时,方法需要接受参数。那么,当调用方法使用接受到的参数时,首先需要先对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。
在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?
-
创建一个异常对象。封装一些提示信息(信息可以自己编写)。
-
需要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?通过关键字throw就可以完成。throw 异常对象。
throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
使用格式:
throw new 异常类名(参数);
例如:
throw new NullPointerException("要访问的arr数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
public void setAge(int age) {
if(age<18 || age>=50){
throw new RuntimeException();
}else{
this.age = age;
}
}
package yichang;
public class demo01 {
public static void main(String[] args) {
/*
异常作用一:异常是用来查询bug的关键参考信息
异常作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
*/
//1.创建学生对象
Student s1 = new Student();
//年龄:(同学) 18~40岁
s1.setAge(50);//就知道了50赋值失败
//选择1:自己悄悄处理
//选择2:打印在控制台上
}
}
4.JVM虚拟机默认处理异常方式
package yichang;
public class demo2 {
public static void main(String[] args) {
/*
JVM默认处理异常的方式:
1. 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
2. 程序停止执行,异常下面的代码不会再执行了
*/
System.out.println("狂踹瘸子那条好腿");
System.out.println(2/0);//算术异常 ArithmeticException
System.out.println("是秃子终会发光");
System.out.println("火鸡味锅巴");
}
}
JVM默认处理异常的方式:
1. 把异常的名称,异常原因及异常出现的位置等信息输出在了控制台
2. 程序停止执行,异常下面的代码不会再执行了
5.捕获异常try…catch
如果异常出现的话,会立刻终止程序,所以我们得处理异常:
该方法不处理,而是声明抛出,由该方法的调用者来处理(throws)。
在方法中使用try-catch的语句块来处理异常。
try-catch的方式就是捕获异常。
捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。
捕获异常语法如下:
try{
编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
try:该代码块中编写可能产生异常的代码。
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。
注意:try和catch都不能单独使用,必须连用。
package yichang;
public class demo3 {
public static void main(String[] args) {
/*
自己处理(捕获异常)
格式:
try {
可能出现异常的代码;
} catch(异常类名 变量名) {
异常的处理代码;
}
好处:可以让程序继续往下执行,不会停止
*/
int[] arr = {1, 2, 3, 4, 5, 6};
try{
//可能出现异常的代码;
System.out.println(arr[10]);//此处出现了异常,程序就会在这里创建一个ArrayIndexOutOfBoundsException对象
//new ArrayIndexOutOfBoundsException();
//拿着这个对象到catch的小括号中对比,看括号中的变量是否可以接收这个对象
//如果能被接收,就表示该异常就被捕获(抓住),执行catch里面对应的代码
//当catch里面所有的代码执行完毕,继续执行try...catch体系下面的其他代码
}catch(ArrayIndexOutOfBoundsException e){
//如果出现了ArrayIndexOutOfBoundsException异常,我该如何处理
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗?");
}
}
6.四问
第一问
自己处理(捕获异常)灵魂四问:
灵魂一问:如果try中没有遇到问题,怎么执行?
会把try里面所有的代码全部执行完毕,不会执行catch里面的代码
注意:
只有当出现了异常才会执行catch里面的代码
package yichang;
public class demo4 {
public static void main(String[] args) {
/*
自己处理(捕获异常)灵魂四问:
灵魂一问:如果try中没有遇到问题,怎么执行?
会把try里面所有的代码全部执行完毕,不会执行catch里面的代码
注意:
只有当出现了异常才会执行catch里面的代码
*/
int[] arr = {1, 2, 3, 4, 5, 6};
try{
System.out.println(arr[0]);//1
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗?");//看看我执行了吗?
}
}
第二问
自己处理(捕获异常)灵魂四问:
灵魂二问:如果try中可能会遇到多个问题,怎么执行?
会写多个catch与之对应
细节:
如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
了解性:
在JDK7之后,我们可以在catch中同时捕获多个异常,中间用|进行隔开
表示如果出现了A异常或者B异常的话,采取同一种处理方案
package com.itheima.a01myexception;
public class ExceptionDemo8 {
public static void main(String[] args) {
/*
自己处理(捕获异常)灵魂四问:
灵魂二问:如果try中可能会遇到多个问题,怎么执行?
会写多个catch与之对应
细节:
如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
了解性:
在JDK7之后,我们可以在catch中同时捕获多个异常,中间用|进行隔开
表示如果出现了A异常或者B异常的话,采取同一种处理方案
*/
//JDK7
int[] arr = {1, 2, 3, 4, 5, 6};
try{
System.out.println(arr[10]);//ArrayIndexOutOfBoundsException
System.out.println(2/0);//ArithmeticException
String s = null;
System.out.println(s.equals("abc"));
}catch(ArrayIndexOutOfBoundsException | ArithmeticException e){
System.out.println("索引越界了");
}catch(NullPointerException e){
System.out.println("空指针异常");
}catch (Exception e){
System.out.println("Exception");
}
System.out.println("看看我执行了吗?");
}
}
第三问
自己处理(捕获异常)灵魂三问: 如果try中遇到的问题没有被捕获,怎么执行? 相当于try...catch的代码白写了,最终还是会交给虚拟机进行处理。
package yichang;
public class demo6 {
public static void main(String[] args) {
/*
自己处理(捕获异常)灵魂三问:
如果try中遇到的问题没有被捕获,怎么执行?
相当于try...catch的代码白写了,最终还是会交给虚拟机进行处理。
*/
int[] arr = {1, 2, 3, 4, 5, 6};
try{
System.out.println(arr[10]);//new ArrayIndexOutOfBoundsException();
}catch(NullPointerException e){
System.out.println("空指针异常");
}
System.out.println("看看我执行了吗?");
}
}
第四问
自己处理(捕获异常)灵魂四问:
如果try中遇到了问题,那么try下面的其他代码还会执行吗?
下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体
但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
package yichang;
public class demo7 {
public static void main(String[] args) {
/*
自己处理(捕获异常)灵魂四问:
如果try中遇到了问题,那么try下面的其他代码还会执行吗?
下面的代码就不会执行了,直接跳转到对应的catch当中,执行catch里面的语句体
但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
*/
int[] arr = {1, 2, 3, 4, 5, 6};
try{
System.out.println(arr[10]);
System.out.println("看看我执行了吗?... try");
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗?... 其他代码");
}
}
7.异常的常见方法
package yichang;
public class demo8 {
public static void main(String[] args) {
/*
public String getMessage() 返回此 throwable 的详细消息字符串
public String toString() 返回此可抛出的简短描述
public void printStackTrace() 在底层是利用System.err.println进行输出
把异常的错误信息以红色字体输出在控制台
细节:仅仅是打印信息,不会停止程序运行
*/
int[] arr = {1, 2, 3, 4, 5, 6};
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
String message = e.getMessage();
//System.out.println(message);//Index 10 out of bounds for length 6
String string = e.toString();
//System.out.println(string);//java.lang.ArrayIndexOutOfBoundsException: Index 10 out of bounds for length 6
e.printStackTrace();
}
//正常的输出语句
//System.out.println(123);
//错误的输出语句(而是用来打印错误信息)
//System.err.println(123);
}
}
8.声明异常throws
package yichang;
public class demo9 {
public static void main(String[] args) {
/*
throws:写在方法定义处,表示声明一个异常。告诉调用者,使用本方法可能会有哪些异常。
throw :写在方法内,结束方法。手动抛出异常对象,交给调用者。方法中下面的代码不再执行了。
需求:
定义一个方法求数组的最大值
*/
int[] arr = null;
int max = 0;
try {
max = getMax(arr);
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("索引越界异常");
}
System.out.println(max);
}
public static int getMax(int[] arr) throws NullPointerException ,ArrayIndexOutOfBoundsException {
if(arr==null){
//手动创建一个异常对象,并把这个异常交给方法的调用者处理
//此时方法就会结束,下面的代码不会再执行了
throw new NullPointerException();
}
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;
}
}
9.练习
package lx;
import java.util.Scanner;
public class demo1 {
public static void main(String[] args) {
/*
需求:
键盘录入自己心仪的女朋友姓名和年龄。
姓名的长度在 3 - 10之间,
年龄的范围为 18 - 40岁,
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示:
需要考虑用户在键盘录入时的所有情况。
比如:录入年龄时超出范围,录入年龄时录入了abc等情况
*/
Girlfriend g = new Girlfriend();
Scanner sc = new Scanner(System.in);
while (true) {
try {
System.out.println("请输入你心仪的女朋友姓名");
String name = sc.nextLine();
g.setName(name);
System.out.println("请输入你心仪的女朋友年龄");
String str = sc.nextLine();
int age = Integer.parseInt(str);
g.setAge(age);
break;//程序前面的只要出现异常就会跳到对应的catch语句体当中
} catch (NumberFormatException e) {
System.out.println("输入的年龄格式错误");
} catch (RuntimeException e) {
System.out.println("年龄或者名字的范围不对");
}
}
}
}
package lx;
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) {
// 姓名的长度在 3 - 10之间,
if (name.length() < 3 || name.length() > 10) {
throw new RuntimeException();//运行出错误 运行时错误可以不用写throws
}
this.name = name;
}
/**
* 获取
*
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
*
* @param age
*/
public void setAge(int age) {
// 年龄的范围为 18 - 40岁
if (age < 18 || age > 40) {
throw new RuntimeException();
}
this.age = age;
}
public String toString() {
return "Girlfriend{name = " + name + ", age = " + age + "}";
}
}
10.自定义异常
package lx;
import java.util.Scanner;
public class demo2 {
public static void main(String[] args) {
//技巧:
//NameFormat:当前异常的名字,表示姓名格式化问题
//Exception:表示当前类是一个异常类
//运行时:RuntimeException 核心 就表示由于参数错误而导致的问题
//编译时:Exception 核心 提醒程序员检查本地信息
/*
需求:
键盘录入自己心仪的女朋友姓名和年龄。
姓名的长度在 3 - 10之间,
年龄的范围为 18 - 40岁,
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止。
提示:
需要考虑用户在键盘录入时的所有 情况。
比如:录入年龄时超出范围,录入年龄时录入了abc等情况
*/
Girlfriend g = new Girlfriend();
Scanner sc = new Scanner(System.in);
while (true) {
try {
System.out.println("请输入你心仪的女朋友姓名");
String name = sc.nextLine();
g.setName(name);
System.out.println("请输入你心仪的女朋友年龄");
String str = sc.nextLine();
int age = Integer.parseInt(str);
g.setAge(age);
break;//程序前面的只要出现异常就会跳到对应的catch语句体当中
} catch (NumberFormatException e) {
e.printStackTrace();
} catch (AgeFormatExcepion e) {
e.printStackTrace();
} catch (NameFormatExcepion e) {
e.printStackTrace();
}
}
}
}
package lx;
public class NameFormatExcepion extends RuntimeException{
public NameFormatExcepion() {
}
public NameFormatExcepion(String message) {
super(message);
}
}
package lx;
public class AgeFormatExcepion extends RuntimeException {
public AgeFormatExcepion() {
}
public AgeFormatExcepion(String message) {
super(message);
}
}