目录
1异常
1.1异常的理解
我们编写代码的时候,例如打印一个数字除以0或者给定数组长度不够打印需要的数组下标等等问题
一旦出现了异常,程序就会终止。
异常就是程序在运行时出现错误提供给调用者(程序猿)的一种机制
- 比较严重的问题(例如和算钱相关的场景), 应该让程序直接崩溃, 防止造成更严重的后果
- 不太严重的问题(大多数场景), 可以记录错误日志, 并通过监控报警程序及时通知程序猿
- 可能会恢复的问题(和网络相关的场景), 可以尝试进行重试.
在我们当前的代码中采取的是经过简化的第二种方式. 我们记录的错误日志是出现异常的方法调用信息, 能很快
速的让我们找到出现异常的位置. 以后在实际工作中我们会采取更完备的方式来记录异常信息.
1.2调用栈 e.printStackTrace();
方法之间是存在相互调用关系的, 这种调用关系我们可以用 "调用栈" 来描述. 在 JVM 中有一块内存空间称为 "虚
拟机栈" 专门存储方法之间的调用关系. 当代码中出现异常的时候, 我们就可以使用 e.printStackTrace(); 的
方式查看出现异常代码的调用栈.
2异常体系
定义:当程序出现错误时能够最大化的减少损失的一种保护手段
Java中异常也是类
2.1异常的类继承关系:
只有Throwable以及子类能够进行异常捕获处理
如果一段代码可能抛出 受查异常, 那么必须显式进行处理.
- 受查异常:除了非受查异常的所有异常类都属于受查异常。--------强制用户进行异常处理。
- 非受查异常:Error/RuntimeException及其子类。-----------------------不强制用户进行异常处理。
2.2异常处理
出现异常时,尽量使得代码能够继续被执行
异常处理的格式:
try
[catch...]
[catch...]
...
[finally]
try..[1..N]catch..
try..finally..
try..[1..N]catch..finally
- try 代码块中放的是可能出现异常的代码
- catch 代码块中放的是出现异常后的处理行为, catch 进行类型匹配的时候, 不光会匹配相同类型的异常对象, 也会捕捉目标异常类型的子类对象.
- finally 代码块中的代码用于处理善后工作,无论是否存在异常, finally 中的代码一定(除了退出jvm-下面有例子)都会执行到. 保证最终一定会执行到 Scanner 的 close 方法.
- 其中 catch 和 finally 都可以根据情况选择加或者不加
一旦 try 中出现异常, 那么 try 代码块中的程序就不会继续执行, 而是交给 catch 中的代码来执行
catch 执行完毕会继续往下执行
2.2.1throw/throws:
throws:用在方法声明上,明确表示该方法可能会产生异常。当异常产生时,将异常对象扔回给调用者
throw:用在方法中,表示人为进行异常对象的产生-------------------------一般与自定义异常搭配使用
class Test {
public static void main(String[] args) {
System.out.println(test());
}
public static int test () {
try {
System.out.println(10 / 2);
return 0;
} catch (ArithmeticException e) {
return 1;
} finally {
return 2;
}
}
}
输出:
5
2
什么时候finally的代码不会被执行?----只有一种情况,退出JVM
class Test {
public static void main(String[] args) {
System.out.println(test());
}
public static int test () {
try {
System.out.println(10 / 2);
System.exit(0);//系统退出
} catch (ArithmeticException e) {
return 1;
} finally {
return 2;}
}
}
数组越界异常或者类型转换异常都可以用catch(Exception e)来处理
class Test{
public static void main(String[] args) {
System.out.println("1.数学计算开始前");
try {
int a=Integer.parseInt(args[0]);
int b=Integer.parseInt(args[1]);
System.out.println("2.数学计算开始"+(a/b));
} catch (Exception e) {
System.out.println("异常被正确的处理了");
}
finally{
System.out.println("一定会执行此代码");
}
System.out.println("3.数学计算结束");
}
}
输出结果:
1.数学计算开始前
异常被正确的处理了
一定会执行此代码
3.数学计算结束
堆栈溢出错误Error可以采用catch(Throwable e)/catch(Error e)来捕获异常
class Test{
public static void main(String[] args) {
System.out.println("1.数学计算开始前");
try {
System.out.println("2.数学计算开始");
fun();
} catch (Error e) {
System.out.println("异常被正确的处理了");
}
finally{
System.out.println("一定会执行此代码");
}
System.out.println("3.数学计算结束");
}
public static void fun(){
fun();//递归调用
}
}
输出结果:
1.数学计算开始前
2.数学计算开始
异常被正确的处理了
一定会执行此代码
3.数学计算结束
- throws:用在方法声明上,明确表示该方法可能会产生异常。当异常产生时,将异常对象扔回给调用者
public class Test{
public static void main(String args[]){
System.out.println(fun(5,0));//报错
}
public static int fun(int a,int b)throws Exception{
return a/b;
}
- throw:用在方法中,表示人为进行异常对象的产生-------------------------一般与自定义异常搭配使用
public class Test {
public static void main(String args[]) {
fun();
}
public static void fun() {
throw new RuntimeException("自定义异常!");
}
}
2.3自定义异常:
extends RuntimeException or Exception-----------一般用在架构设计时
假设用户登录时,设置用户名和密码
package se.SE.practice;
public class Test {
private static String userNamename="admin";
private static String passWord="123456";
public static void main(String[] args) {
login("admin","123456");
}
public static void login(String userNamename,String passWord){
if(!Test.userNamename.equals(userNamename)){
//处理用户名错误
}
if(!Test.passWord.equals(passWord)){
//处理密码错误
}
System.out.println("登录成功!");
}
}
处理用户名异常和密码异常:
基于已有的异常类(Exception类)进行扩展
查看Exception源码:
public Exception(String message) {
super(message);
}
/**
* Constructs a new exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
增加UserError和PassWordError 类继承Exception类
package se.SE.practice;
class UserError extends Exception{
public UserError(String message){
super(message);
}
}
class PassWordError extends Exception{
public PassWordError(String message){
super(message);
}
}
public class Test {
private static String userNamename="admin";
private static String passWord="123456";
public static void main(String[] args) {
try{
login("admin","123456");
}catch(UserError userError){
userError.printStackTrace();
}catch (PassWordError passWordError){
passWordError.printStackTrace();
}
}
public static void login(String userNamename,String passWord)throws UserError,PassWordError{
if(!Test.userNamename.equals(userNamename)){
//处理用户名错误
throw new UserError("用户名错误");
}
if(!Test.passWord.equals(passWord)){
//处理密码错误
throw new PassWordError("密码错误");
}
System.out.println("登录成功!");
}
}
//输出:登录成功!
- 自定义异常通常会继承自 Exception 或者 RuntimeException
- 继承自 Exception 的异常默认是受查异常
- 继承自 RuntimeException 的异常默认是非受查异常.
class AddException extends RuntimeException{
public AddException(String msg){
super(msg);
}
}
public class Test {
public static void main(String args[]) {
int a=100;
int b=100;
int c=a+b;
if(c==200){
throw new AddException("此时总数c不可以等于200");
}
}
}