文章目录
周末天气很好,张三骑上自己的自行车上山感受大自然…
情况一:张三下楼发现自行车车胎没有气了。(必须处理,不然没办法去旅行)
情况二:张三骑到半路轮胎泄气了,张三用嘴吹起来骑行一段距离后轮胎又瘪了。(旅行过程中出现的问题,旅行必须要中止去解决车胎问题)
情况三:半途中发现上山唯一的路塌陷了,及时刹车。(人算不如天算,没办法)
一、什么是错误和异常?
相信聪明的小伙伴儿已经理解到倒霉的张三遇到的三种情况如何对应java中的错误与异常,
在java中,Throwable是所有异常的超类,而Throwable主要分为受检查异常(Exception中的RuntimeException及其子类以外的异常)和不可检查异常(RuntimeException、Error)。错误与异常最明显的区别就是:异常能被程序本身处理,而错误一旦发生就无法处理。
那么下面我们继续探究:
1. 错误
Error:在java中,错误通过Error的子类描述,是程序无法处理的,表示应用程序中比较严重的问题,如:虚拟机错误(Virtual MachineError)、内存溢出(OutOfMemoryError)、线程死锁(ThreadDeath)
2. 异常
Exception:程序本身可以处理,主要分为运行时异常和编译异常,
运行时异常:RuntimeException及其子类,这类异常一般是由程序逻辑错误引起的,而java编译器是不会检查它,就算不处理也会编译通过,避免这类异常的发生应该养成良好的编程习惯,控制好程序的逻辑。
编译异常:
3. 常见的异常
常见的运行时异常:
- NullPointerException:空指针异常。
- IndexOutOfBoundsException:数组下标越界异常。
- ClassCaseException:类转换异常。
- ArrayStoreException:数组存放对象与申明类型不兼容。
常见编译异常:
- ArithmeticException:出现异常的运算条件,如被除数为0。
- IOException:发生IO异常。
- SQLException :数据库相关异常。
- FileNotFoundException :打开文件失败。
- ClassNotFoundException : 找不到指定类。
二、异常的捕获与处理
1. try - catch 语句:
try{
//监控区域
} catch (Exception1 e1){
//捕获并处理异常一
} catch (Exception2 e2){
//捕获并处理异常二
}
java方法在运行的过程中出现异常,则创建异常对象,并将异常抛出监控区域之外,然后寻找匹配的catch子句中的异常,若出现与之匹配的异常,则运行处理异常的代码,最后try-catch语句结束(一般情况下可以用 switch - case
语句来对比理解),如果没有找到匹配的异常,那么就会交给JVM进行处理了。
2. try - catch - finally 语句:
try{
//监控区域
} catch (Exception1 e1){
//捕获并处理异常一
} catch (Exception2 e2){
//捕获并处理异常二
} finally{
//无论是否发生异常都会执行的代码块
}
此语句与 try - catch
语句差不多,只是多了 finally
部分,finally是整个语句中最后执行的部分,而且不管有没有发生异常都必须要执行的部分,面试题来了:
final、finally、finalize 有什么区别?
- final可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写
- finally用于异常处理,finally代码块内语句无论是否发生异常,都会在执行finally,常用于一些流的关闭。
- finalize方法用于垃圾回收。
三、关键字 throw与 throws
如果一个方法可能出现异常,但是没有能力处理这个异常,例如张三的自行车车胎问题,自行车本事是没办法处理的,必须要张三或者找修理厂进行处理,那么这就是throw
和throws
的作用,抛出异常给方法的调用者处理或者继续向上抛出异常。
throw :
throw总是用于在方法体中,用来抛出一个Throwable类型的异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
public static void main(String[] args){
divide(5,2);
//结果为 2.5
divide(5,0);
// 报出异常: java.lang.ArithmeticException: 被除数不能为0
}
public float divide(float a, float b){
if (b == 0){
throw new ArithmeticException("被除数不能为0");
}
return a/b;
}
throws :
throws用在方法头声明该方法要抛出的异常类型,多个异常可使用逗号分割
founction() throws Exception1,Exception2,..,ExceptionN { }
当方法抛出异常列表的异常时,方法将不对这些类型及其子类类型的异常作处理,而抛向调用该方法的方法,由他去处理,如果调用者不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的调用者。
总结:
- throw作用在方法内,表示抛出具体异常,由方法体内的语句处理
- throws作用在方法声明上,表示可能抛出的异常,由调用者来处理异常,但不一定会发生异常。
四、自定义异常
当java提供的异常类不够我们使用时,或者我们需要自己定义发生异常时程序需要做什么,我们就需要用到自定义异常
。
自定义异常必须继承RuntimeException或者Exception继承Exception:那么自定义的异常类就是一个编译期异常,如果出现了编译期异常就必须处理,要么throws ,要么try catch。继承RuntimeException:那么自定义的异常就是一个运行期异常,无需处理,交给虚拟机处理,中断处理。
//定义一个自己的异常类
public class BusinessException extends RuntimeException {
public BusinessException(String message){
super(message);
}
}
public class ExceptionController {
public Map handler(Exception e){
Map<String,Object> map = new HashMap();
if (e instanceof BusinessException){
map.put("code","400");
map.put("Msg",e.getMessage());
}else {
map.put("code","500");
map.put("Msg","系统开小差了,请稍后再试!");
SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 HH小时mm分钟ss秒");
System.out.println("-------------------"+format.format(new Date())+"-------------------");
e.printStackTrace();
}
return map;
}
}
//使用自定义异常,这里我是使用的我以前项目中登录业务,大家如需测试不要照搬,学习使用方式即可
public Map<String,Object> userLogin(String username, String password) {
JsonResult jsonResult = new JsonResult();
try {
SysUser byUsername = sysUserMapper.findByUsername(username);
if (byUsername != null) {
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username,password);
Subject subject = SecurityUtils.getSubject();
subject.login(usernamePasswordToken); //完成登录
SysUser user = (SysUser) subject.getPrincipal();
jsonResult.setCode("200");
jsonResult.setData(user);
jsonResult.setMsg("登录成功");
}
}catch(UnknownAccountException uae){
System.out.println("对用户[" + username + "]进行登录验证..验证未通过,未知账户");
throw new BusinessException("未知账户");
}catch(IncorrectCredentialsException ice){
System.out.println("对用户[" + username + "]进行登录验证..验证未通过,错误的凭证");
throw new BusinessException("密码不正确");
}catch(LockedAccountException lae){
System.out.println("对用户[" + username + "]进行登录验证..验证未通过,账户已锁定");
throw new BusinessException("账户已锁定");
}catch(ExcessiveAttemptsException eae){
System.out.println("对用户[" + username + "]进行登录验证..验证未通过,错误次数过多");
throw new BusinessException("用户名或密码错误次数过多");
}catch(AuthenticationException ae){
//通过处理Shiro的运行时AuthenticationException就可以控制用户登录失败或密码错误时的情景
System.out.println("对用户[" + username + "]进行登录验证..验证未通过,堆栈轨迹如下");
ae.printStackTrace();
throw new BusinessException("用户名或密码不正确");
}
return jsonResult.getValues();
}
学无止境。老狗在此欢迎各位大神指出鄙人之不足,提出你们宝贵意见。
- 转载请注明出处