一、定义
程序执行过程中的不正常行为称为异常。
二、异常的体系结构
1.Throwable:是异常体系的顶层类,其派生出两个重要的子类, Error 和 Exception
2. Error:指的是Java虚拟机无法解决的严重问题,比如:JVM的内部错误、资源耗尽等,典型代表:StackOverflowError和OutOfMemoryError,一旦发生回力乏术,需要程序员来修正。
3. Exception:异常产生后程序员可以通过代码进行处理,也可以由JVM处理,使程序继续执行。
三、异常的分类
1.编译时异常(受检查异常)
2.运行时异常(非受检查异常):有RunTimeException
注解:语法错误(拼写出错)不是异常,而是拼写错误。
在Java中,标识符是用来命名变量、方法、类等的名称。标识符必顮要遵守以下规则:
- 必须以字母、下划线(_)或者美元符($)开头
- 其他部分可以是字母、数字、下划线(_)或者美元符($)
- 大小写敏感
根据这些规则,"system" 是一个合法的标识符,与大小写有区别。因此,在Java中,"system" 和 "System" 被视为不同的标识符。因此,如果你将 "System" 错误地拼写为 "system",编译器会将其视为另一个不同的标识符,可能导致意外的行为或错误。
四、异常处理的方法
分类
1.防御式编程:LBYL形处理:把正常流程与错误流程混在一起处理,比如if(){}else(){}混用。
2.事后认错形处理:EAFP:try{}catch{}finally{}
使用方法
依靠五个关键字:throw,throws,try,catch,final
一、抛出异常(throw)
1.throw必须写在方法体内部
2. 抛出的对象必须是Exception 或者 Exception 的子类对象
3. 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给JVM来处理
4. 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
5. 异常一旦抛出,其后的代码就不会执行
二、捕获异常(1.异常声明throws 2.捕获处理try,catch)
1.处在方法声明时参数列表之后,当方法中抛出编译时异常,用户不想处理该异常,此时就可以借助throws将异常抛给方法的调用者来处理。即当前方法不处理异常,提醒方法的调用者处理异常。
2.处理:
try{}花括号内写可能发生异常的语句,catch(异常类型 变量名){处理},finally{}里面的代码不管有无异常都会执行,根据这个特性可以进行文件关闭等操作。
注解:
1. try块内抛出异常位置之后的代码将不会被执行
2. 如果抛出异常类型与catch时异常类型不匹配,即异常不会被成功捕获,也就不会被处理,继续往外抛,直到JVM收到后中断程序----异常是按照类型来捕获的
3. try中可能会抛出多个不同的异常对象,则必须用多个catch来捕获----即多种异常,多次捕获
如果异常之间具有父子关系,一定是子类异常在前catch,父类异常在后catch,否则语法错误:
可以通过一个catch捕获所有的异常,即多个异常,一次捕获(不推荐)
由于 Exception 类是所有异常类的父类. 因此可以用这个类型表示捕捉所有异常.
自定义异常(以及实战代码)
import java.util.Scanner;
class userNameException extends Exception{
public userNameException(String message){
super(message);
}
}
class userPasswordException extends Exception{
public userPasswordException(String message){
super(message);
}
}
public class user {
private static String name="admin";
private static String password="123";
public static void login()throws userNameException, userPasswordException{
Scanner p=new Scanner(System.in);
String name1=p.nextLine();
String password1=p.nextLine();
if(!name.equals(name1)){
throw new userNameException("用户名异常。。。。");
}
if(!password.equals(password1)) {
throw new userPasswordException("密码异常。。。。");
}
}
public static void main(String[] args) {
while(true){
try{
login();
System.out.println("登录成功");
break;
}catch(userNameException e){
e.printStackTrace();
System.out.println("用户名异常,请重新输入");
continue;
}catch(userPasswordException e){
e.printStackTrace();
System.out.println("密码异常,请重新输入");
continue;
}finally {
System.out.println("。。。。。。。");
}
}
}
}
需要注意的点:
1.写的是自定义的子类,表示自定义的类型错误,需要继承父类的Exception方法,而子类调用父类,父类有构造方法时,需要使用super来访问父类构造方法。
在Java中,异常类的构造方法通常会接受一个字符串参数,这个字符串参数就是用来描述异常情况的信息。当在抛出异常时使用throw new ExceptionType("message")
语句时,其中的"message"
会被传递给异常类的构造方法,然后在异常对象被创建时,这个字符串信息就会被存储在异常对象中。
当异常被捕获和处理时,可以通过异常对象的getMessage()
方法来获取这个字符串信息,并据此进行相应的处理。因此,在自定义异常类时,通过构造方法传入字符串参数,可以使得在抛出异常时能够携带相关的描述信息,方便在异常被捕获后理解异常的原因。
2.login方法中没有处理异常,要使用throws关键字抛出异常,给调用的函数处理
3.catch的参数,一定要写类型名+变量名,不能只写一个类型名
下面,来讲讲我在写这份代码时遇到的问题,以下是初始代码:
import java.util.Scanner;
class userNameException extends Exception{
public userNameException(String message){
super(message);
}
}
class userPasswordException extends Exception{
public userPasswordException(String message){
super(message);
}
}
public class user {
private static String name="admin";
private static String password="123";
static Scanner p=new Scanner(System.in);
static String name1=p.nextLine();
static String password1=p.nextLine();
public static String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Scanner getP() {
return p;
}
public void setP(Scanner p) {
this.p = p;
}
public static String getName1() {
return name1;
}
public void setName1(String name1) {
this.name1 = name1;
}
public static String getPassword1() {
return password1;
}
public void setPassword1(String password1) {
this.password1 = password1;
}
public static void login()throws userNameException, userPasswordException{
String name1=getName1();String name=getName();
String password1=getPassword1();String password=getPassword();
if(!name.equals(name1)){
throw new userNameException("用户名异常。。。。");
}
if(!password.equals(password1)) {
throw new userPasswordException("密码异常。。。。");
}
}
public static void main(String[] args) {
while(true){
try{
login();
System.out.println("登录成功");
break;
}catch(userNameException e){
e.printStackTrace();
System.out.println("用户名异常,请重新输入");
continue;
}catch(userPasswordException e){
e.printStackTrace();
System.out.println("密码异常,请重新输入");
continue;
}finally {
System.out.println("。。。。。。。");
}
}
}
}
一开始,输入正确的用户名和密码可以正常登录,但是输入错误的就死循环了,这是因为,尽管重新调用login,却没有重新赋值,因此死循环