1. 异常
异常:程序在运行过程中出现的和预想不一致的情况
类和对象:在Java里使用Throwable类表示程序运行过程中出现的不正常现象
Throwable子类:
Error:程序中出现的错误,程序员不应该尝试解决这种问题,应该让程序终止!
Exception:程序运行中出现的异常,程序员可以解决这种问题。 异常又分为两种:
运行时异常: RuntimeException,可以处理可以不处理
非运行时异常: 必须要处理,否则编译会报错 (编译时异常)
能出现问题的代码解决思路:
1、规避:在出现问题之前把出问题的情况排除,不属于异常处理的方式,因为异常还未发生
规避只能用于运行时异常,不能用在编译时异常
2、让程序产生异常,再通过异常处理语言来补救
2.1 try...catch
2.2 try...catch...finally语句
2.3 使用 throw和throws抛出异常
public class ExceptionDemo {
public static void main(String[] args) {
/*常见的运行时异常 RuntimeException,编译不报错,运行时会出现问题
ArrayIndexOutOfBoundsException 数组下标越界异常
StringIndexOutOfBoundsException 字符串下标越界异常
NullPointerException 空指针异常
ArithmeticException 算法异常*/
Scanner scanner = new Scanner(System.in);
System.out.print("请输入您要选择的编号:");
int index = scanner.nextInt();
scanner.close();
String[] names = {"朦朦", "橘子", "安妮", "崔崔", "芳芳", "巧玲"};
// 规避的方式让可能出现的异常不出现
if (index < 0 || index >= names.length) {
System.out.println("编号不合法");
} else {
System.out.println("您选择的是" + names[index]);
}
}
}
2. try...catch
try {
有可能出现异常的代码
}catch(出现的异常类型 e) {
异常处理语句,通常有两个操作:
1. e.printStackTrace(); 打印错误日志,记录在后台给开发人员看
2. 给用户一个友好的提示 System.out.println();
}
一个try后面可以有多个catch语句,如果多个异常之间有继承关系,父类的异常处理要放在子类的下面!
如果多个catch里的异常处理语句一样,可以将多个catch语句合并成为一个catch,中间使用 | 连接。这种情况下,异常类型之间不能有继承关系!
public class CatchDemo {
public static void main(String[] args) {
int[] nums = {5, 9, 2, 1, 7, 6, 4, 3};
Scanner scanner = new Scanner(System.in);
System.out.print("请输入一个数字:");
int i = scanner.nextInt();
scanner.close();
String x = "ab";
Object o = null;
try {
System.out.println(1 / i);
System.out.println(nums[i]);
char c = x.charAt(i);
System.out.println(c);
System.out.println(o.toString());
} catch (ArithmeticException | ArrayIndexOutOfBoundsException | StringIndexOutOfBoundsException e) {
e.printStackTrace();
}
/*catch (ArithmeticException e) {
System.out.println("除数不能为0");
e.printStackTrace();
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组下标越界");
e.printStackTrace();
} catch (StringIndexOutOfBoundsException e) {
System.out.println("字符串下标越界");
e.printStackTrace();
} catch (RuntimeException e) { // 可以catch父类异常
System.out.println("出现了运行时异常");
e.printStackTrace();
}*/
}
}
3. throw 和throws
throw和throws关键字的使用:用来抛出异常
假如你是 java.util.Scanner.java 的作者,实现 nextInt()功能,大概的步骤:
(1) 调用 next()方法获取到用户输入的字符串
(2) 调用 Integer.parseInt(String s) 方法,将字符串转换成为整数
(3) 返回这个整数给调用者
throw在方法里用来抛出异常:
如果throw抛出的是 RuntimeException,方法声明里的throws可以不写
throws用在方法声明里,表示该方法有异常:
如果方法里抛出的不是RuntimeException,方法声明里必须要使用throws声明异常
调用这个方法的代码也必须要处理这个异常,要么try...catch,要么抛出去
如果异常一直向上抛到main方法,main方法会将异常交给JVM虚拟机,虚拟机默认操作就是终止程序,返回状态码 1
throw和throws通常会配合自定义使用!
public class ThrowDemo {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入密码:"); // "hello"
String password = scanner.next();
scanner.close();
// checkPassword(password);
/*try {
check(password);
} catch (Exception e) {
System.out.println("密码格式错误");
}*/
test(password);
System.out.println("注册成功... ...");
}
static void test(String password) throws Exception {
check(password);
}
// 要求密码长度要在[8,15]位,由数字字母组成,不能以数字开头
static void checkPassword(String password) throws RuntimeException {
if (password.matches("[a-zA-Z][a-zA-Z0-9]{7,14}")) {
System.out.println("连接数据库");
System.out.println("将密码写入到数据库");
} else {
throw new RuntimeException("密码不合法!"); // 抛出一个运行异常
}
}
static void check(String password) throws Exception {
if (password.matches("[a-zA-Z][a-zA-Z0-9]{7,14}")) {
System.out.println("连接数据库");
System.out.println("将密码写入到数据库");
} else {
throw new Exception("密码格式不合法");
}
}
}
4. 自定义异常
自定义异常的使用
throw后面的对象,必须要继承自 Throwable类,通常情况下不直接继承 Throwable
因为Throwable类有两个子类 Exception 和 Error,Error是不能处理的错误
所以自定义异常通常继承自Exception(编译时异常)或者 RuntimeException(运行时异常)
如果继承自Exception,方法声明里必须要使用throws声明抛出
如果继承自RuntionException,方法声明里可以不适用throws声明抛出
package com.atguigu.exception;
public class 数字格式化异常 extends RuntimeException {
}
public class ExceptionDemo {
public static void main(String[] args) {
int x = checkNumber("goof");
System.out.println(x);
}
// 判断用户输入的字符串是否是一个合法的数字
static int checkNumber(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
e.printStackTrace();
throw new 数字格式化异常();
}
}
}
public class PasswordFormatException extends Exception {
public PasswordFormatException(String message) {
super(message);
}
public PasswordFormatException(int min, int max) {
super("密码由" + min + "到" + max + "位的数字和字母组成,不能以数字开头");
}
}
public class MyExceptionDemo {
public static void main(String[] args) {
String s = "abc";
try {
checkPassword(s);
} catch (PasswordFormatException e) {
e.printStackTrace();
}
}
static void checkPassword(String password) throws PasswordFormatException {
int x = 9, y = 18;
if (password.matches("[a-zA-Z][0-9a-zA-Z]{" + (x - 1) + "," + (y - 1) + "}")) {
System.out.println("密码格式正确");
} else {
// throw new PasswordFormatException("密码由8到16位的数字和字母组成,不能以数字开头");
throw new PasswordFormatException(x, y);
}
}
}
5. 继承里异常的注意事项
子类不能抛出比父类更多(大)的异常
1. 父类如果没有抛出异常,子类不能抛出编译时异常(运行时异常除外)
2. 子类抛出的异常可以是父类抛出的异常的子类。
在这种情况下,子类如果使用 super.方法名() 调用父类的方法,会报错
因为子类没有解决父类里的异常
3. 子类不能抛出比父类范围更大的异常,子类在重写方法时
如果有范围更大的异常,只能使用try...catch解决,不能再抛出
public class ExceptionInheritanceDemo {
}
class XXX {
@Override
public String toString() /*throws UnsupportedEncodingException*/ {
try {
"hello".getBytes("UTF8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return super.toString();
}
}
class Base {
public void test() {
}
}
class Father extends Base {
public void test() {
}
public void demo() throws IOException {
}
public void foo() throws FileNotFoundException {
}
}
class Son extends Father {
@Override
public void test() {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
formatter.parse("2020-07-10 14:00:23");
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public void demo() throws FileNotFoundException {
}
@Override
public void foo() throws FileNotFoundException {
}
}