看完这篇Exception 和 Error,和面试官扯皮就没问题了
在 Java 中的基本理念是 结构不佳的代码不能运行
,发现错误的理想时期是在编译期间,因为你不用运行程序,只是凭借着对 Java 基本理念的理解就能发现问题。但是编译期并不能找出所有的问题,有一些 NullPointerException 和 ClassNotFoundException 在编译期找不到,这些异常是 RuntimeException 运行时异常,这些异常往往在运行时才能被发现。
我们写 Java 程序经常会出现两种问题,一种是 java.lang.Exception ,一种是 java.lang.Error,都用来表示出现了异常情况,下面就针对这两种概念进行理解。
认识 Exception
Exception
位于 java.lang
包下,它是一种顶级接口,继承于 Throwable
类,Exception 类及其子类都是 Throwable 的组成条件,是程序出现的合理情况。
在认识 Exception 之前,有必要先了解一下什么是 Throwable
。
什么是 Throwable
Throwable 类是 Java 语言中所有错误(errors)
和异常(exceptions)
的父类。只有继承于 Throwable 的类或者其子类才能够被抛出,还有一种方式是带有 Java 中的 @throw
注解的类也可以抛出。
在Java规范中,对非受查异常和受查异常的定义是这样的:
The unchecked exception classes are the run-time exception classes and the error classes.
The checked exception classes are all exception classes other than the unchecked exception classes. That is, the checked exception classes are
Throwable
and all its subclasses other thanRuntimeException
and its subclasses andError
and its subclasses.
也就是说,除了 RuntimeException
和其子类,以及error
和其子类,其它的所有异常都是 checkedException
。
那么,按照这种逻辑关系,我们可以对 Throwable 及其子类进行归类分析
可以看到,Throwable 位于异常和错误的最顶层,我们查看 Throwable 类中发现它的方法和属性有很多,我们只讨论其中几个比较常用的
// 返回抛出异常的详细信息
public string getMessage();
public string getLocalizedMessage();
//返回异常发生时的简要描述
public public String toString();
// 打印异常信息到标准输出流上
public void printStackTrace();
public void printStackTrace(PrintStream s);
public void printStackTrace(PrintWriter s)
// 记录栈帧的的当前状态
public synchronized Throwable fillInStackTrace();
此外,因为 Throwable 的父类也是 Object
,所以常用的方法还有继承其父类的getClass()
和 getName()
方法。
常见的 Exception
下面我们回到 Exception 的探讨上来,现在你知道了 Exception 的父类是 Throwable,并且 Exception 有两种异常,一种是 RuntimeException
;一种是 CheckedException
,这两种异常都应该去捕获
。
下面列出了一些 Java 中常见的异常及其分类,这块面试官也可能让你举出几个常见的异常情况并将其分类
RuntimeException
序号 | 异常名称 | 异常描述 |
---|---|---|
1 | ArrayIndexOutOfBoundsException | 数组越界异常 |
2 | NullPointerException | 空指针异常 |
3 | IllegalArgumentException | 非法参数异常 |
4 | NegativeArraySizeException | 数组长度为负异常 |
5 | IllegalStateException | 非法状态异常 |
6 | ClassCastException | 类型转换异常 |
UncheckedException
序号 | 异常名称 | 异常描述 |
---|---|---|
1 | NoSuchFieldException | 表示该类没有指定名称抛出来的异常 |
2 | NoSuchMethodException | 表示该类没有指定方法抛出来的异常 |
3 | IllegalAccessException | 不允许访问某个类的异常 |
4 | ClassNotFoundException | 类没有找到抛出异常 |
与 Exception 有关的 Java 关键字
那么 Java 中是如何处理这些异常的呢?在 Java 中有这几个关键字 throws、throw、try、finally、catch 下面我们分别来探讨一下
throws 和 throw
在 Java 中,异常也就是一个对象,它能够被程序员自定义抛出或者应用程序抛出,必须借助于 throws
和 throw
语句来定义抛出异常。
throws 和 throw 通常是成对出现的,例如
static void cacheException() throws Exception{
throw new Exception();
}
throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throws 语句用在方法声明后面,表示再抛出异常,由该方法的调用者来处理。
throws 主要是声明这个方法会抛出这种类型的异常,使它的调用者知道要捕获这个异常。
throw 是具体向外抛异常的动作,所以它是抛出一个异常实例。
try 、finally 、catch
这三个关键字主要有下面几种组合方式 try...catch 、try...finally、try...catch...finally。
try...catch 表示对某一段代码可能抛出异常进行的捕获,如下
static void cacheException() throws Exception{
try {
System.out.println("1");
}catch (Exception e){
e.printStackTrace();
}
}
try...finally 表示对一段代码不管执行情况如何,都会走 finally 中的代码
static void cacheException() throws Exception{
for (int i = 0; i < 5; i++) {
System.out.println("enter: i=" + i);
try {
System.out.println("execute: i=" + i);
continue;
} finally {
System.out.println("leave: i=" + i);
}
}
}
try...catch...finally 也是一样的,表示对异常捕获后,再走 finally 中的代码逻辑。
JDK1.7 使用 try...with...resources 优雅关闭资源
Java 类库中有许多资源需要通过 close 方法进行关闭。比如 InputStream、OutputStream,数据库连接对象 Connection,MyBatis 中的 SqlSession 会话等。作为开发人员经常会忽略掉资源的关闭方法,导致内存泄漏。
根据经验,try-finally
语句是确保资源会被关闭的最佳方法,就算异常或者返回也一样。try-catch-finally 一般是这样来用的
static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
}finally {
br.close();
}
}
这样看起来代码还是比较整洁,但是当我们添加第二个需要关闭的资源的时候,就像下面这样
static void copy(String src,String dst) throws Exception{
InputStream is = new FileInputStream(src);
try {
OutputStream os = new FileOutputStream(dst);
try {
byte[] buf = new byte[100];
int n;
while ((n = is.read()) >= 0){
os.write(buf,n,0);
}
}finally {
os.close();
}
}finally {
is.close();
}
}
这样感觉这个方法已经变得臃肿起来了。
而且这种写法也存在诸多问题,即使 try - finally 能够正确关闭资源,但是它不能阻止异常的抛出,因为 try 和 finally 块中都可能有异常的发生。
比如说你正在读取的时候硬盘损坏,这个时候你就无法读取文件和关闭资源了,此时会抛出两个异常。但是在这种情况下,第二个异常会抹掉第一个异常。在异常堆栈中也无法找到第一个异常的记录,怎么办,难道像这样来捕捉异常么?
static void tryThrowException(String path) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
String s = br.readLine();
System.out.println("s = " + s);
}catch (Exception e){
e.printStackTrace();
}finally {
try {
br.close();
}catch (Exception e){
e.printStackTrace();
}finally {
br.close();
}
}
}
这种写法,虽然能解决异常抛出的问题,但是各种 try-cath-finally 的嵌套会让代码变得非常臃肿。
Java7 中引入了try-with-resources
语句时,所有这些问题都能得到解决。要使用 try-with-resources 语句,首先要实现 AutoCloseable
接口,此接口包含了单个返回的 close 方法。Java 类库与三方类库中的许多类和接口,现在都实现或者扩展了 AutoCloseable 接口。如果编写了一个类,它代表的是必须关闭的资源,那么这个类应该实现 AutoCloseable 接口。
java 引入了 try-with-resources 声明,将 try-catch-finally 简化为 try-catch,这其实是一种语法糖
,在编译时会进行转化为 try-catch-finally 语句。
下面是使用 try-with-resources 的第一个范例
/**
* 使用try-with-resources 改写示例一
* @param path
* @return
* @throws IOException
*/
static String firstLineOfFileAutoClose(String path) throws IOException {
try(BufferedReader br = new BufferedReader(new FileReader(path))){
return br.readLine();
}
}
使用 try-with-resources 改写程序的第二个示例
static void copyAutoClose(String src,String dst) throws IOException{
try(InputStream in = new FileInputStream(src);
OutputStream os = new FileOutputStream(dst)){
byte[] buf = new byte[1000];
int n;
while ((n = in.read(buf)) >= 0){
os.write(buf,0,n);
}
}
}
使用 try-with-resources 不仅使代码变得通俗易懂,也更容易诊断。以firstLineOfFileAutoClose
方法为例,如果调用 readLine()
和 close()
方法都抛出异常,后一个异常就会被禁止,以保留第一个异常。
异常处理的原则
我们在日常处理异常的代码中,应该遵循三个原则
- 不要捕获类似
Exception
之类的异常,而应该捕获类似特定的异常,比如InterruptedException
,方便排查问题,而且也能够让其他人接手你的代码时,会减少骂你的次数。 - 不要生吞异常。这是
看完这篇Exception 和 Error,和面试官扯皮就没问题了的更多相关文章
- 看完这篇HTTP,跟面试官扯皮就没问题了
我是一名程序员,我的主要编程语言是 Java,我更是一名 Web 开发人员,所以我必须要了解 HTTP,所以本篇文章就来带你从 HTTP 入门到进阶,看完让你有一种恍然大悟.醍醐灌顶的感觉. 最初在有 ...
- 看完这篇 final、finally 和 finalize 和面试官扯皮就没问题了
我把自己以往的文章汇总成为了 Github ,欢迎各位大佬 star https://github.com/crisxuan/bestJavaer 已提交此篇文章 final 是 Java 中的关键字 ...
- 看完这篇 HTTPS,和面试官扯皮就没问题了
下面我们来一起学习一下 HTTPS ,首先问你一个问题,为什么有了 HTTP 之后,还需要有 HTTPS ?我突然有个想法,为什么我们面试的时候需要回答标准答案呢?为什么我们不说出我们自己的想法和见解 ...
- 看完这篇 Session、Cookie、Token,和面试官扯皮就没问题了
Cookie 和 Session HTTP 协议是一种无状态协议,即每次服务端接收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录:Session 和 Cookie 的主要目的 ...
- 看完这篇 HashMap,和面试官扯皮就没问题了
HashMap 概述 如果你没有时间细抠本文,可以直接看 HashMap 概述,能让你对 HashMap 有个大致的了解. HashMap 是 Map 接口的实现,HashMap 允许空的 key-v ...
- APP的缓存文件到底应该存在哪?看完这篇文章你应该就自己清楚了
APP的缓存文件到底应该存在哪?看完这篇文章你应该就自己清楚了 彻底理解android中的内部存储与外部存储 存储在内部还是外部 所有的Android设备均有两个文件存储区域:"intern ...
- 关于 Docker 镜像的操作,看完这篇就够啦 !(下)
紧接着上篇<关于 Docker 镜像的操作,看完这篇就够啦 !(上)>,奉上下篇 !!! 镜像作为 Docker 三大核心概念中最重要的一个关键词,它有很多操作,是您想学习容器技术不得不掌 ...
- 【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?
简介 Floyd-Warshall算法(Floyd-Warshall algorithm),是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似.该算法名称以 ...
- [转帖]看完这篇文章你还敢说你懂JVM吗?
看完这篇文章你还敢说你懂JVM吗? 在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约 600m,Linux自身使用 ...
随机推荐
- 停下来,回头看 ——记2020BUAA软工第一次作业-热身!
description: 'Mar 1st, 2020 - Mar 3rd, 2020' 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 第一次作 ...
- .NET微服务从0到1:服务注册与发现(Consul)
目录 Consul搭建 基于Docker搭建Consul 基于Windows搭建Consul ServiceA集成Consul做服务注册 Ocelot集成Consul做服务发现 更多参考 Consul ...
- vue中的插槽(slot)
vue中的插槽,指的是子组件中提供给父组件使用的一个占位符,用<slot></slot>标签表示,父组件可以在这个占位符中填充任何模板代码,比如HTML.组件等,填充的内容会替 ...
- C# 存储相同键多个值的Dictionary
涉及到两个问题: 一.访问磁盘中文件夹.文件夹下面的文件夹 先看一下磁盘文件夹结构 C盘下面有个根文件夹SaveFile,SaveFIle下面有两个子文件夹分别为,2018.2019, 子文件下201 ...
- vue_相同组件,不同url跳转不重新渲染的解决方法
最近写的这个项目,有很多下拉菜单,每个菜单会有相应的两种类型.现在产品的需求是,跳转到不同的类型 需要页面重新渲染数据 那么问题来了. 我试了好几种方法,用watch监听路由去判断,但是发现输在inp ...
- python学习基础之变量
变量名只能包含字母.数字和下划线.变量名可以字母或下划线打头,但不能以数字打 头,例如,可将变量命名为message_1,但不能将其命名为1_message. 变量名不能包含空格,但可使用下划线来分隔 ...
- jenkins操作
jenkins忘记用户名以及登录密码的解决方法 1.jenkins 根目录下找到config.xml,修改配置 <useSecurity>true</useSecurity> ...
- Java探针技术-retransformclasses的介绍
retransformclasses void retransformclasses(class... classes) throws unmodifiableclassexception 重转换提供 ...
- 你知道吗,Flutter内置了10多种Button控件
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 Flutter内置了10多种Button(按钮)类控件供我 ...
- TCP/IP协议基本知识
1.TCP/IP协议中主机与主机之间通信的三要素: IP地址(IP address) 子网掩码(subnet mask) IP路由(IP router) 2.IP地址的分类及每一类的范围: A类1-1 ...
- 看完这篇HTTP,跟面试官扯皮就没问题了