写在前面:本文注重针对异常的处理,对于文中的 IO 操作没有过多解释
对于 Java 异常处理,其实对于所有的语言而言,我们在使用的时候,必须先了解其基本语法
try-catch、throws、throw...
public static void main(String args[]) throws Exception{
/**
* 读取 C 盘下面的文件,写到 D 盘下面
*/
String filePath = "C:\\Users\\17323\\Desktop\\优惠-批量添加权限.txt";
String remotePath = "D:\\2.txt";
//将 C 盘下的文件读取为字节流
byte[] bytes=new byte[1024];
InputStream is = new FileInputStream(filePath);
is.read(bytes);
//将字节流写到 D 盘的文件中
OutputStream os = new FileOutputStream(remotePath);
os.write(bytes);
}
首先肯定一下,这个功能是完成了的
- 能够将C盘下的文件内容写到D盘的文件中
throws
用法:在方法名后面接 throws + 异常类;声明一个方法可能抛出的各种异常
在上面的代码中,我们在 main() 方法上抛出异常。
反正在我写过这么些的业务代码中,从来没有看到过这样的写法,直接在方法上抛出一个的大的异常,(这里为什么要说一个大的异常,因为一个方法下面受检查异常可能有很多,而且范围也可能不一样)
public static void main(String args[]) throws FileNotFoundException
那么 is.read 和 os.write 会报错,因为捕获他们的异常大于 FileNotFoundException
我们在一个具体的方法中,应该针对某一个具体的行为,比如上面的:
InputStream is = new FileInputStream(filePath);
is.read(bytes);
。。。,
如:对一个数据库返回对象判空等
throw
用法:抛出一个新的异常类;用来明确地抛出一个异常
//这只是一个简单的示例,我们通过再次封装,将 throw new TestException("map 没有数据"); 的内容直接返给前台,这样就很友好
Map map=new HashMap();
if(map==null||map.isEmpty()){
throw new TestException("XXX工号没有权限");
}
//自己定义了一个简易的异常类
class TestException extends RuntimeException {
TestException(String msg){
super(msg);
}
}
try-catch
/**
* 读取 C 盘下面的文件到 D 盘下面
*/
String filePath = "C:\\Users\\17323\\Desktop\\优惠-批量添加权.txt";
String remotePath = "D:\\2.txt";
//读取为字节流
byte[] bytes = new byte[1024];
try{
InputStream is = new FileInputStream(filePath);
is.read(bytes);
}catch (IOException e){
System.out.println("本地路径找不到");
}
try{
OutputStream os = new FileOutputStream(remotePath);
os.write(bytes);
}catch (IOException e){
e.printStackTrace();
}
//读取的时候发生错误,会打印出:本地路径找不到,这在前台展示的时候更友好,而不是打印出一堆的堆栈错误
当然我们在 catch 的时候,可以指定更加合适的 Exception 类,也可有多个catch「尽管有多个catch,也只会匹配一个,不像 switch 必须在 case 下加上 break ,才不会执行其他的 case」
//大范围的异常类必须放在后面 try{ InputStream is = new FileInputStream(filePath); is.read(bytes); }catch ( FileNotFoundException e){ System.out.println("本地路径找不到"); }catch (IOException e){ System.out.println("读取数据出错"); }
finally
一般都是 try-cathc-finally 结合使用,finally 对资源进行关闭等
我们开始的代码还差了点事,资源没关闭呢
//只展示读取为字符流的代码
//读取为字节流
byte[] bytes = new byte[1024];
InputStream is=null;
try{
is = new FileInputStream(filePath);
is.read(bytes);
}catch ( IOException e){
System.out.println("本地路径找不到");
}
// finally 下面关闭资源
finally {
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
看着代码都烦,对不对,太麻烦臃肿了。
try-with-resources
自 Java7 出现的语法糖:自动关闭资源,不用在写上面的 finally ,手动的关闭资源了。
InputStream isIs=null;
//读取为字节流
byte[] bytes = new byte[1024];
/**核心代码,编写的时候只需要这个即可**/
try(InputStream is = new FileInputStream(filePath)){
isIs=is;
is.read(bytes);
}catch ( IOException e){
System.out.println("本地路径找不到");
}
//这里只是验证,是否关闭了
finally {
try {
isIs.read(bytes);
} catch (IOException e) {
e.printStackTrace();//若关闭了,会报错 java.io.IOException: Stream Closed
}
}
是不是觉得又学到了一个另外的小技能:如何验证 IO 流已经关闭 :)
具体案例1
try-catch
public class ForCheckAnyObject {
public static void run(){
Map map=new HashMap();
map.get("ad").toString();
}
public static void main(String args[]) {
/**
* 上面讲的都是受检查异常,现在来讲运行时异常
* 而我们开发业务代码中,大多数遇到都是业务代码,都是运行时异常
*/
try{
run();
}catch(Exception e){
System.out.println("上层报错");
}
}
}
//上层报错
这就是当调用 run() 方法时内部错误,run() 的 catch 捕获到,这样其实,我们就不能直观的看出错误到底是什么,还要必须要具体分析。所以这个时候我们应该优化
//run方法中修改如下:如打印出真正出错的地方以及原因
Map map=new HashMap();
try{
map.get("ad").toString();
}catch (NullPointerException e){
e.printStackTrace();
}
但是我们一般都不像上面这样用,而是下面这样:
if(map.isEmpty()||map==null) {
//抛出一个具体的错误(显示友好的)
}
具体案例2
try-catch-finally 解释和执行过程
try 块:如果在方法内部抛出了异常(或者在方法内部调用其他方法抛出了异常),这个方法将在抛出异常的过程中结束。如果不希望就此结束,可以设置一个特殊的块,用来尝试各种(可能产生的异常)方法调用,这就是 try 块。
catch :捕获异常,如果 try 中方法抛出了异常,那么 catch 会捕获到并进行处理。
finally :对于一些代码块,可能希望无论 try 块是否抛出异常,都能得到执行。通常适用于内存回收之外的情况:比如,已经打开的文件或网络连接
那么 finally 一定会被执行吗?
一、假如 try 中有 return 语句,那么 finally 还会被执行吗?
public class ForCheckAnyObject {
public static String run(int i) {
String s="";
try {
i++;
System.out.println("try i=" + i);
return s;
} catch (Exception e) {
} finally {
System.out.println("yes");
return s;
}
}
public static void main(String args[]) {
String j=run(2);
System.out.println(j);
}
}
/**
* try i=3
* yes
*/
因为return表示的是要整个方法体返回,所以,finally中的语句会在return之前执行 。
二、finally 什么时候不执行?
- 如果对应的 try 块没有被执行,那么对应的 finally 也不会被执行
- try/catch块中有System.exit(0)强制退出JVM,也不会执行