文章目录
一、异常机制
1.碰到过的异常
- 下标越界
- 空指针异常
- 类型转换异常
- 栈内存溢出
2.概述
- 异常是Java中提供的一种识别及响应错误情况的一致性机制。有效地异常处理能使程序更加健壮、易于调试。
- 异常发生的原因有很多,比如:
-
- 用户输入了非法数据
- 要打开的文件不存在
- 网络通信时连接中断
- JVM内存溢出
- 这些异常有的是因为用户错误易引起,有的是程序错误引起的,还有一些是因为物理错误引起的
- try…catch… 处理异常的
- throws 抛出异常
- throw 异常源点
- finally 必须执行的语句块
目的:增强程序的鲁棒性,就是健壮性
3.继承体系
4.Error
系统内部错误,这类错误由系统进行处理,程序本身无需捕获处理。
比如:OOM(内存溢出错误)、VirtualMachineError(虚拟机错误)、StackOverflowError(堆栈溢出错误)等,一般发生这种情况,JVM会选择终止程序。
5.Exception
5.1.概述
Exception是所有异常类的父类。分为非RuntimeException和RuntimeException
-
非RuntimeException
n 指程序编译时需要捕获或处理的异常,如IOException、自定义异常等。属于checked异常
-
RuntimeException
指程序编译时不需要捕获或处理的异常,如:NullPointerException等。属于unchecked异常。一般是由程序员粗心导致的。如空指针异常、数组越界、类型转换异常等
5.2.常用方法
5.3.Try…catch…
5.3.1.第一种
int a = 10;
int b = 0;
if (b != 0) {
// 这里就会出现一个错误,除数不能为零
// java.lang.ArithmeticException: / by zero
System.out.println(a / b);
} else {
System.out.println("除数不能为0");
}
try {
// 如果a/b 有错,那么就将错误抛出,直接去执行catch,不再执行try中剩余代码
System.out.println(a / b);
System.out.println(5);
System.out.println(6);
//如果try中代码顺利执行完,那么将不再执行catch
} catch (ArithmeticException e) {
// e.getMessage()获取错误信息,一般给用户看
System.out.println(e.getMessage());
// 打印错误详细栈帧,一般给程序员看,用于改错
e.printStackTrace();
}
5.3.2.第二种
try {
System.out.println(a / b);// 除数不能为0
String string = null; // 空指针
string.toString();
// 注意:多个catch只会有一个执行,因为try中只要发现一个错误就会执行catch
// 多个catch 传入的异常类型必须是 从子到父 的,也就是最先判断是否属于前面的那个异常,与多分支类似
} catch (ArithmeticException e) {
System.out.println("除数不能为零");
} catch (NullPointerException e) {
System.out.println("空指针异常");
} catch (Exception e) {
System.out.println("其他异常");
}
5.3.3.第三种
try {
System.out.println(a / b);// 除数不能为0
String string = null; // 空指针
string.toString();
// 从java1.7开始,开始支持 异常类型 | 异常类型 | ..... 变量
// 多个异常不能有继承关系,如果有则直接写父类即可
} catch (ArithmeticException | NullPointerException e) {
// TODO: handle exception
} catch (Exception e) {
// TODO: handle exception
}
5.3.4.第四种
java1.7之后有两个改进:
- 多个异常可以在一个catch中使用 | 隔开,不能有继承关系
- 自动关闭资源
try(打开资源){
高风险代码
}catch(异常类型 变量){
异常处理
}
FileInputStream files2=null;
try(FileInputStream files1 = new FileInputStream("E://a.txt");) {
files2=files1;
System.out.println("txt:"+files1.read());
} catch (IOException e) {
e.printStackTrace();
}
try {
//java.io.IOException: Stream Closed
System.out.println("txt:"+files2.read());
} catch (IOException e) {
e.printStackTrace();
}
5.4.Throws
- throws:抛出异常,并不会处理掉异常,如果最终没有出现try,依然会终止生命周期
- 是一种提醒机制,告诉大家,这里可能有问题,但是没有解决,多注意
public static void main(String[] args)throws NullPointerException,
IOException, ArithmeticException, Exception {
try {
m1();
} catch (Exception e) {
e.printStackTrace();
}
}
// 调用者抛出的异常要么和被调用的方法一样,要么比被调用的抛出的异常更大
public static void m1() throws Exception {
m2();
}
public static void m2() throws RuntimeException {
m3();
}
public static void m3() throws ArithmeticException {
}
5.5.Finally
- 必须执行的语句块,除了System.exit()关闭 JVM 虚拟机之外,finally 一定会执行
- 所以一般用于做一些关闭资源操作
- finally 不能单独使用,需要和 try 或者 try…catch… 一起使用
// 作用域提高指的是声明提高,而不是赋值
FileInputStream files = null;
try {
// 打开对应文件,可能会找不到(如果不存在的话)
files = new FileInputStream("E://a.txt");
// 读取文件内容
System.out.println("txt:"+files.read());
} catch (IOException e) {//IOException : 输入输出异常
// 当进行文件读写、网络通信、数据库操作等输入输出操作时,如果发生了IO错误或出现了不可预料的情况,就会抛出IOException异常
e.printStackTrace();
} finally {
// 关闭资源
if (files != null) {
try {
files.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.6.不能有更宽泛的异常
class A{
public void m1() throws IOException{
}
}
//子类要么不抛出异常,要么抛出小于等于父类的异常,绝对不可以比父类异常还要大(就是不能抛出父类异常的父类)
class B extends A{//这里就不能抛出 Exception
public void m1(){}
}
5.7.final、finally、finalize有什么区别
- ,final 是修饰符,修饰类不能继承,成员方法不能覆写,变量是常量没有默认值,不能二次赋值
- finalize 垃圾自动回收时会自动调用该对象的 finalize 方法,一般用于关闭资源等操作,垃圾是没有任何引用指向这个对象时,这个对象就是垃圾,等待被系统回收
- finally 不许执行的语句块,不能单独出现,必须和 try 或 try…catch… 一起使用
6.自定义异常类
6.1.语法
- 继承一个已有的异常类,如果是运行时异常则继承 RuntimeException ,否则一般直接继承Exception即可
- 构造方法,一般需要一个无参构造和一个有参构造用于传入错误信息
public class NameLengthException extends Exception{
public NameLengthException(){
}
public NameLengthException(String msg){
super(msg);
}
}
public class UserService {
public static void register(String name) throws NameLengthException{
if (name.length()<6) {
//个人理解
// throw 应该和 return 有异曲同工之妙,就是功能大概差不多
//只不过 throw 是抛出, return 是返回 ,但是都会终止方法执行
//后面的 new NameLengthException() 就像新创建的对象 ( 自定义异常的新对象 )
//里面的内容 ( 这里指"用户名不能小于六位!" ) 就是错误信息,给用户看的
// 更准确的说法 : throw 会创建一个异常对象,称为异常源
throw new NameLengthException("用户名不能小于六位!");
}
}
}
public class Client {
public static void main(String[] args) {
Scanner scanner =new Scanner(System.in);
System.out.println("请输入用户名");
String name=scanner.next();
try {
UserService.register(name);
System.out.println("注册成功!");
} catch (NameLengthException e) {
//e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
这样就可以实现一个简单的用户名鉴定了 ( 未分层 )
6.2.需求
完成用户登录 ( 分层 )
- 如果用户名不是 admin 则提示用户名未注册
- 如果密码不是 root 则提示密码错误
6.3.实体类
实体类 封装数据
public class User {
private String username;
private String password;
private String inckname;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getInckname() {
return inckname;
}
public void setInckname(String inckname) {
this.inckname = inckname;
}
public User(String username, String password, String inckname) {
super();
this.username = username;
this.password = password;
this.inckname = inckname;
}
public User() {
super();
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password
+ ", inckname=" + inckname + "]";
}
}
6.4.异常类
异常类做 提醒机制
public class UserException extends Exception {
public UserException() {
}
public UserException(String msg) {
super(msg);
}
}
6.5.Controller
Controller 是有 main 方法的地方,做前后端交互
public class UserController {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
UserService userService=new UserService();
System.out.println("请输入用户名:");
String username=scanner.next();
System.out.println("请输入密码:");
String password=scanner.next();
try {
User name=userService.login(username, password);
System.out.println("欢迎登录!"+name.getUsername());
} catch (UserException e) {
System.out.println(e.getMessage());
}
}
}
6.6.Dao
Dao层负责数据库相关的操作
public class UserDao {
private User[] users = { new User("admin", "root", "管理员"),
new User("test", "1111", "测试用户") };
//模块化分层使代码复用性增强
public User loadByUsername(String username) {
for (int i = 0; i < users.length; i++) {
if (users[i].getUsername().equals(username)) {
return users[i];
}
}
return null;
}
}
6.7.Service
Service做业务逻辑处理
public class UserService {
private UserDao userDao=new UserDao();
public User login(String username, String password) throws UserException {
//接受用户传入的数据
//根据用户名去数据库传输局,如果有就比较密码,,没有则提示用户名不存在
User oldUser=userDao.loadByUsername(username);
//比较密码
if (oldUser==null) {
//异常机制的用法,自己的代码用法,否则用try...catch...
throw new UserException("用户名不存在");
}
if (oldUser.getPassword().equals(password)) {
return oldUser;
}else {
throw new UserException("密码错误!");
}
}
}