- 异常的概念: 程序出现了不正常的情况
- 异常本质就是Java当中对可能出现的问题进行描述的一种对象体现。
- 简单来说:异常本质就是异常描述的对象体现
- 异常的分类:
- 异常(Exception)
- 编译时异常 (受检异常): 在程序的编译时期就出问题,这个是可以提前处理的
- 不是继承自RuntimeException的Exception的子类都成为编译时期异常。
- 运行时异常 (非受检异常): 在程序运行时期出现问题,这个一般都是代码不够健壮,不够严谨,也是可以处理的
- RuntimeException及其所有子类都是运行时期异常。
- 错误(Error): 是无法避免的,也是程序员无法解决的 StackOverflowError
- 异常目的:能够保证程序继续执行 ArithmeticException
package com.sxt.exceptiondemo;
/*
* 生活的异常
*
* 班长开新买的宝马来上学
*
* 出门前 (编译时期)
* 班长的妈妈说 开车一定要加满油
* 班长的爸爸说 注意脚下的路
* 姐姐说 小心碰瓷
*
* 在路上 (运行时期)
* 被车撞
* 漏油
* 路上看到柳岩的演唱会
*
* 到学校门口 地震了
*
* 异常的概念: 程序出现了不正常的情况
* 异常本质就是Java当中对可能出现的问题进行描述的一种对象体现。
* 简单来说:异常本质就是异常描述的对象体现
*
* 异常的分类
* 异常(Exception)
* 编译时异常 (受检异常): 在程序的编译时期就出问题,这个是可以提前处理的
* 不是继承自RuntimeException的Exception的子类都成为编译时期异常。
* 运行时异常 (非受检异常): 在程序运行时期出现问题,这个一般都是代码不够健壮,不够严谨,也是可以处理的
* RuntimeException及其所有子类都是运行时期异常。
* 错误(Error): 是无法避免的,也是程序员无法解决的 StackOverflowError
*
* 异常目的:能够保证程序继续执行 ArithmeticException
*/
public class ExceptionDemo01 {
public static void main(String[] args) {
System.out.println("吃鸡开始");
int a = 10;
int b = 0;
System.out.println(a/b);
System.out.println("今晚吃鸡,大吉大利");
}
// public static void show() {
// System.out.println("show");
// show();
// }
}
-
异常处理
-
为什么需要处理异常? – 保证程序继续执行
-
如果我们不处理异常,jvm是如何处理异常的
-
JVM异常处理机制
-
1.打印错误信息
-
Exception in thread “main” java.lang.ArithmeticException: / by zero
at com.sxt.exceptiondemo.ExceptionDemo02.main(ExceptionDemo02.java:16)
a.异常名称
b.异常信息
c.异常所发生的方法
d.异常的行号 -
2.将虚拟机终止
-
JVM处理异常的方式不能够满足我们的需求
-
所以我们需要自己来处理异常
-
如何来处理异常?
-
异常处理的格式:
-
方式一: try…catch…finally
-
方式二: throws
-
方式一处理异常:
try {
// 放置可能出现问题的代码,这里代码越少越好
} catch(异常类名 异常对象){
// 处理异常的代码
} catch(异常类名 异常对象){
// 处理异常的代码
} ...catch(异常类名 异常对象) {
// 处理异常的代码
} finally {
// 释放资源的代码
}
- 注意:
- 1.try不可以独立存在,try-catch,try-catch-finally,try…finally是可以的
- 2.try中如果出现了问题,抛出异常对象,不会执行try块中后面的代码
- 3.多个catch块只能够执行一个
- 异常处理的执行流程:
- 1.程序执行到47行
- 2.系统会抛出一个异常对象
-
本质: ArithmeticException ae = new ArithmeticException(); throw ae;
- 3.无论47行下面有多少代码都不会被执行,程序进入catch块异常捕获
- 4.依次和每一个catch进行匹配
匹配成功: 程序执行catch块代码,程序继续执行
匹配失败: 交给JVM处理 - 标准的异常处理方式:
- 1.能够显示捕获的异常就显示声明捕获
- 2.就算程序异常处理的很全面还是有可能有其他异常,所以在最后面可以使用Exception父类异常做统一捕获
package com.sxt.exceptiondemo;
/*
* 面试题: 代码实现虚拟机处理异常的过程
*/
public class ExceptionDemo02 {
public static void main(String[] args) {
// System.out.println("第一步");
// int a = 10;
// int b = 0;
// try {
// System.out.println(a/b); // throw new ArithmeticException();
// System.out.println("我执行了吗?");
// } catch(NullPointerException ae) {
// // ArithmeticException ae = new ArithmeticException();
// System.out.println("出问题了!!!");
// }
// System.out.println("第二步");
System.out.println("第一步");
int a = 10;
int b = 0;
String s = null;
int[] arr = new int[3];
try {
// System.out.println(a/b); // throw new ArithmeticException();
// System.out.println(s.equals("null"));
// System.out.println(arr[-1]);
Object obj = new Integer("100");
System.out.println((String)obj);
System.out.println("我执行了吗?");
} catch(ArithmeticException ae) {
// ArithmeticException ae = new ArithmeticException();
System.out.println("算数异常");
} catch (NullPointerException ne) {
System.out.println("空指针异常");
} catch (ArrayIndexOutOfBoundsException aioobe) {
System.out.println("数组越界异常");
} catch (Exception e) {
System.out.println("出问题了!!!");
}
System.out.println("第二步");
}
}
- Throwable类
- Throwable fillInStackTrace()
填写执行堆栈跟踪。 - String getLocalizedMessage()
创建此可抛出的本地化描述。 - String getMessage()
返回此throwable的详细消息字符串。 - StackTraceElement[] getStackTrace()
提供对 printStackTrace()打印的堆栈跟踪信息的 编程访问 。 - void printStackTrace()
将此throwable和其追溯打印到标准错误流。 - void printStackTrace(PrintStream s)
将此throwable和其追溯打印到指定的打印流。 - void printStackTrace(PrintWriter s)
将此throwable和其追溯打印到指定的打印作者。 - void setStackTrace(StackTraceElement[] stackTrace)
设置将被返回的堆栈微量元素 getStackTrace()和由印刷 printStackTrace()和相关方法。 - String toString()
返回此可抛出的简短描述。
package com.sxt.exceptiondemo;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
/*
* 面试题: 代码实现虚拟机处理异常的过程
*/
public class ExceptionDemo03 {
public static void main(String[] args) throws FileNotFoundException {
// Throwable t = new NullPointerException("空指针异常");
// System.out.println(t); // java.lang.NullPointerException: 空指针异常
//
// // StackTraceElement[] getStackTrace()
// StackTraceElement[] stackTraces = t.getStackTrace();
// System.out.println(stackTraces.length);
// for (StackTraceElement element : stackTraces) {
// String fileName = element.getFileName();
// boolean nativeMethod = element.isNativeMethod();
// String methodName = element.getMethodName();
// String className = element.getClassName();
// int lineNumber = element.getLineNumber();
//
// System.out.println(fileName + "|" + methodName
// + "|" + nativeMethod + "|" + className + "|" + lineNumber);
// }
show();
// void printStackTrace()
// t.printStackTrace();
/*
* 第一步
* Exception in thread "main"
java.lang.ArithmeticException: / by zero
at com.sxt.exceptiondemo.ExceptionDemo03.main(ExceptionDemo03.java:52)
*/
/*System.out.println("第一步");
int a = 10;
int b = 0;
try {
System.out.println(a/b);
} catch (Exception e) {
StackTraceElement[] stackTraces = e.getStackTrace();
String methodName = stackTraces[0].getMethodName();
String className = stackTraces[0].getClassName();
String fileName = stackTraces[0].getFileName();
int lineNumber = stackTraces[0].getLineNumber();
System.err.printf("Exception in thread \"%s\"" +
"%s\r\n" +
" at %s.%s(%s:%d)", methodName, e.toString(),
className, methodName,fileName,lineNumber);
// void printStackTrace(PrintWriter s)
String exceptionMessage = String.format("Exception in thread \"%s\"" +
"%s\r\n" +
" at %s.%s(%s:%d)", methodName, e.toString(),
className, methodName,fileName,lineNumber);
PrintWriter s = new PrintWriter(new FileOutputStream("Console"), true);
s.println(exceptionMessage);
e.printStackTrace(s);
System.exit(1);
}*/
// System.out.println("第二步");
}
public static void show() {
method();
}
public static void method() {
Throwable t = new NullPointerException("空指针异常");
StackTraceElement[] stackTraces = t.getStackTrace();
System.out.println(stackTraces.length);
for (StackTraceElement element : stackTraces) {
String fileName = element.getFileName();
boolean nativeMethod = element.isNativeMethod();
String methodName = element.getMethodName();
String className = element.getClassName();
int lineNumber = element.getLineNumber();
System.out.println(fileName + "|" + methodName
+ "|" + nativeMethod + "|" + className + "|" + lineNumber);
}
}
}
-
编译时异常的处理 以及 如何来查看异常
-
处理方式: Ctrl+1 自动修复
-
如何来查看异常
-
查看错误: 从下往上看,先看你能够看懂的,再看源码里面的
package com.sxt.exceptiondemo;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/*
* 编译时异常的处理 以及 如何来查看异常
*
* 处理方式: Ctrl+1 自动修复
*
* 如何来查看异常
* 查看错误: 从下往上看,先看你能够看懂的,再看源码里面的
*/
public class ExceptionDemo04 {
public static void main(String[] args) {
System.out.println("main start");
exception();
System.out.println("main end");
}
private static void exception() {
System.out.println("exception first");
method();
System.out.println("exception last");
}
private static void method() {
String dataStr = "2019/01/26 14:08:20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss"); // throw new ParseException("Unparseable date: "2019/01/26 14:08:20"");
try {
sdf.parse(dataStr);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
-
为什么有了try…catch处理异常还需要学习throws处理异常?
-
有的时候可能我们没有办法处理,或者我压根就不想处理,又或者我压根没有权限处理,这个时候可以将异常抛出,抛给调用者
-
throws关键字概述
在定义一个方法的时候可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而交给方法的调用者进行处理。 -
throws格式
[修饰符] 返回值类型 方法名(参数列表) [throws 异常类1,异常类2....]{
}
注意:
- 1.如果抛出的是运行时异常,可以处理,也可以不处理,但是不能够抛给主方法,因为主方法是jvm调用,jvm的处理方式就是终止程序
- 2.如果抛出的是编译时异常,必须处理,处理方式既可以是try catch也可以是throws,但是不能够抛给主方法
- 3.重写一个方法时,它所声明的异常范围不能被扩大。
- 4.异常处理如果是平级关系的异常,可以并行处理 ArithmeticException|NullPointerException|ClassCastException e
package com.sxt.exceptiondemo;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/*
* 为什么有了try...catch处理异常还需要学习throws处理异常?
* 有的时候可能我们没有办法处理,或者我压根就不想处理,又或者我压根没有权限处理,这个时候可以将异常抛出,抛给调用者
*
* throws关键字概述
在定义一个方法的时候可以使用throws关键字声明,使用throws声明的方法表示此方法不处理异常,而交给方法的调用者进行处理。
* throws格式
* [修饰符] 返回值类型 方法名(参数列表) [throws 异常类1,异常类2....]{
}
注意:
1.如果抛出的是运行时异常,可以处理,也可以不处理,但是不能够抛给主方法,因为主方法是jvm调用,jvm的处理方式就是终止程序
2.如果抛出的是编译时异常,必须处理,处理方式既可以是try catch也可以是throws,但是不能够抛给主方法
3.重写一个方法时,它所声明的异常范围不能被扩大。
4.异常处理如果是平级关系的异常,可以并行处理 ArithmeticException|NullPointerException|ClassCastException e
*/
public class ExceptionDemo05 {
public static void main(String[] args) throws ArithmeticException, ParseException {
// System.out.println("start");
// show();
// System.out.println("end");
try {
Demo.method();
} catch (ArithmeticException|NullPointerException|ClassCastException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void show() throws ArithmeticException, ParseException {
// method();
// test();
}
public static void method() throws ArithmeticException {
int a = 10;
int b = 0;
System.out.println(a / b);
}
public static void test() throws ParseException, Exception, Throwable {
String dataStr = "2019/01/26 14:08:20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss"); // throw new ParseException("Unparseable date: "2019/01/26 14:08:20"");
sdf.parse(dataStr);
}
}
class Father {
public void method() throws Exception {
int a = 10;
int b = 0;
System.out.println(a / b);
}
}
class Son extends Father {
@Override
public void method() throws NullPointerException, ArithmeticException, ParseException {
}
}
class Demo {
public static void method() throws ArithmeticException, NullPointerException, ClassCastException {
int a = 10;
int b = 0;
System.out.println(a / b);
}
}
-
throw关键字
-
格式: throw 异常对象
-
面试题: throw和throws的区别
-
1.throws出现在方法的声明上,throw出现在方法体内
-
2.throws表示一种异常出现的可能性,而throw表示一定出现了异常
-
3.throws可以声明多个,但是throw只能够抛出一个对象
-
4.throws声明的是异常类,而throw抛出的是异常对象
package com.sxt.exceptiondemo;
import java.util.Scanner;
/*
* throw关键字
*
* 格式: throw 异常对象
*
* 面试题: throw和throws的区别
* 1.throws出现在方法的声明上,throw出现在方法体内
* 2.throws表示一种异常出现的可能性,而throw表示一定出现了异常
* 3.throws可以声明多个,但是throw只能够抛出一个对象
* 4.throws声明的是异常类,而throw抛出的是异常对象
*/
public class ExceptionDemo06 {
public static void main(String[] args) {
try {
method();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("over");
}
public static void method() throws ArithmeticException {
Scanner input = new Scanner(System.in);
int a = 10;
int b = input.nextInt();
if (b == 0) {
throw new ArithmeticException("除数不能为0");
}
System.out.println(a / b);
}
}
finally关键字
try {
} catch(异常类 异常对象){
} finally {
这里的代码一定会被执行,除非碰到系统退出 System.exit(0)或者 Runtime.getRuntime().exit(0);
一般用来释放资源,比如说数据库的连接,IO流的输入输出对象的关闭
}
package com.sxt.exceptiondemo;
import java.util.Scanner;
/*
* finally关键字
*
* try {
*
* } catch(异常类 异常对象){
*
* } finally {
* 这里的代码一定会被执行,除非碰到系统退出 System.exit(0)或者 Runtime.getRuntime().exit(0);
* 一般用来释放资源,比如说数据库的连接,IO流的输入输出对象的关闭
* }
*
* finally final finallize的区别?
*
* finally和return?
*/
public class ExceptionDemo07 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String line = input.nextLine();
System.out.println(line);
// input.close();
try {
int a = 10;
int b = 0;
System.out.println(a / b);
System.out.println("try 我执行了吗");
} catch (Exception e) {
e.printStackTrace();
System.out.println("catch 我执行了吗");
// return;
// System.exit(0);
// Runtime.getRuntime().exit(0);
} finally {
System.out.println("finally 我执行了吗");
input.close();
}
}
}
-
finally碰到return
-
finally一定会执行
-
执行顺序?
-
在try语句中,在执行return语句时,要返回的结果已经准备好了,就在此时,程序转到finally执行了。
-
在转去之前,try中先把要返回的结果存放到不同于x的局部变量中去,执行完finally之后,在从中取出返回结果,
-
因此,即使finally中对变量x进行了改变,但是不会影响返回结果。它应该使用栈保存返回值。
package com.sxt.exceptiondemo;
public class ExceptionDemo08 {
public static void main(String[] args) {
System.out.println(test()); // 3
}
public static int test() {
int x = 1;
try {
x++; // 2
return x; // return 2;
} finally {
++x; // 3
System.out.println(x); // 3
}
}
}
异常: 本质就是错误信息在Java当中的一个对象体现
-
Java提供了很多的异常,但是还是不能够满足我们开发的需求,既然异常本质仅仅是一个描述,那么我们
-
完全可以自己来描述我们所谓的错误,并且编写一个类来表达我们的错误描述
-
自定义一个异常,要求考试成绩必须在0-100之间,如果不在这个范围内,抛出异常。
-
自定义异常的步骤
1.自定义异常必须是Throwable的子类
2.书写一个类继承Exception
3.书写两个构造方法
a.无参构造方法 (没有带错误描述)
b.带参构造方法 (带错误描述)
package com.sxt.exceptiondemo;
import java.util.Scanner;
public class ExceptionDemo10 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("请输入分数:");
double score = input.nextDouble();
Teacher t = new Teacher();
try {
System.out.println(t.isBetween0To100(score) ? "分数合法" : "分数不合法");
} catch (ScoreException e) {
e.printStackTrace();
} finally {
if (input != null) {
input.close();
}
}
System.out.println("分数批改完毕!!!");
}
}
class Teacher {
public boolean isBetween0To100(double score) throws ScoreException {
if (score >= 0 && score <= 100) {
return true;
} else {
throw new ScoreException("分数必须在0~100分之间!!!");
}
}
}
class ScoreException extends Exception {
private static final long serialVersionUID = -1989349702073875392L;
public ScoreException() {
super();
}
public ScoreException(String message) {
super(message);
}
}
1、自定义一个异常判断身份证号是否合法
运行结果:
输入身份证号码:
12365
1.可以是15位或者18位的数字
2.15位纯数字
3.18位最后一位是有X的,最后一位是确认码,0-9和X或者x.
异常:身份证号码不合法
package com.sxt.exceptiondemo;
import java.util.Scanner;
public class ExceptionDemo11 {
@SuppressWarnings("resource")
public static void main(String[] args) {
try {
System.out.println(Test.checkIDCard(new Scanner(System.in).next()) ? "合法身份证" : "非法身份证");
} catch (IDCardException e) {
e.printStackTrace();
}
System.out.println("身份证检查完毕");
}
}
class Test {
public static boolean checkIDCard(String idCard) throws IDCardException {
if (idCard.matches("\\d{15}|\\d{17}[\\dxX]")) {
return true;
} else {
throw new IDCardException("非法身份证!!!");
}
}
}
class IDCardException extends RuntimeException {
private static final long serialVersionUID = 392084157998377850L;
public IDCardException() {
}
public IDCardException(String message) {
super(message);
}
}