Java基础(十)——IO

IO

数据的输入与输出流
将内存中的数据持久化到硬盘中
或者从硬盘读取数据临时存放在内存
都需要用到IO操作

File类

数据一般存储在文件中
Java提供了File类支持对文件的操作
静态变量:
pathSeparator	与系统有关的路径分隔符	window 是 ; Linux 是 :
separator	与系统有关的目录分隔符	window 是 \ Linux 是 /

构造方法:	通过一个文件或路径得到一个对象
window下路径不区分大小写
Linux区分大小写
new File(Filrpath)
new File(参照路径,相对路径)
new File(File对象,相对路径)
创建方法:
createNewFile():	创建文件的方法(当前文件夹存在的基础上)
boolean mkdir():	创建单级目录文件夹
boolean mkdirs():	创建多级目录文件夹
删除方法:
boolean delete():	删除文件或文件夹,不走回收站,从硬盘直接删除
					如果要删除的文件夹下有文件或子文件夹就无法删除
获取方法:
String[] list(): 将构造器传入的路径下当前目录下文件与文件夹的名字存入String数组并返回
					不能获取子文件夹的文件名
File[] listFiles(): 获取当前目录下所有的文件夹和文件组成的File对象传入File数组并返回
String getName():	返回路径中最后一级文件或文件夹的名字
long length(): 返回路径中表示文件的字节数,对文件夹无效
String getAbsolutePath():返回当前项目(非当前文件)的绝对路径,不区分.和..
String getCanonicalPath():返回当前项目(非当前文件)的绝对路径
File getAbsoluteFile():返回绝对路径的File对象
String getParent(): 获取上一级路径所在的绝对路径String
File getParentFile(): 获取上一级路径所在的绝对路径File对象
String lastModified():获取最后一次的修改时间,毫秒值
判断方法:
boolean exists(): 判断构造器中的路径参数是否真实存在此路径
boolean isDirectory(): 判断构造器中的路径是否是文件夹
boolean isFile(): 判断构造器中的路径是否是文件
boolean canRead():判断是否可读
boolean canWrite():判断是否可写
boolean isHidden():判断是否隐藏
File file = new File("D:\\sss\\a.txt");// 创建一个File对象
System.out.println(file);
file.mkdirs();//创建多级目录
file.createNewFile();
// 在当前文件夹存在的基础上,如果file对象中文件不存在就创建这个文件
// 如果文件文件存在就不在创建
//如果D:\\sss中sss文件夹不存在就会报错
System.out.println(file.length());
System.out.println(file.getAbsolutePath());
System.out.println(file.getAbsoluteFile());
System.out.println(file.getParent());
System.out.println(file.getParentFile());
System.out.println(file.exists());
System.out.println(file.isDirectory());
System.out.println(file.isFile());
file.delete();
1.new File("d:\\demo\\a.txt")表示指向这个地址不是创建文件
2.new File("d:\\demo",“a.txt”)
3.File f =  new File("d:\\demo")
	new File(f,"a.txt”)
以上三种效率是一样的,我们一般使用第一种

文件地址的获取

类名.class	获取class对象
class对象.getResource(path)  获取URL对象
	path不加/,就是当前路径的相对路径
	path加/,就是当前项目的根路径	
URL.getFile() 获取String类型的文件地址

在这里插入图片描述

src包下有path包
	path包下有a包
		a包下有b包和1文件
			b包下c包和2文件
				c包下有3文件
在b包使用一个TestPath类获取
不带/的相对路径写法	
上一级1文件的内容	TestPath.class.getResource("../1").getFile()
同级的2文件的内容	TestPath.class.getResource("2").getFile();
下一级3文件的内容	TestPath.class.getResource("c/3").getFile();
带/的相对路径写法	
上一级1文件的内容	TestPath.class.getResource("/path/a/1").getFile()
同级的2文件的内容	TestPath.class.getResource("/path/a/b/2").getFile();
下一级3文件的内容	TestPath.class.getResource("/path/a/b/c/3").getFile();
public class TestPath {
	public static void main(String[] args) {
		// String filepath = TestPath.class.getResource("../1").getFile();
		// String filepath = TestPath.class.getResource("2").getFile();
		String filepath = TestPath.class.getResource("c/3").getFile();
		try (FileInputStream in = new FileInputStream(new File(filepath));) {
			byte[] b = new byte[1024];
			int len = 0;
			while ((len = in.read(b)) > 0) {
				System.out.println(new String(b, 0, len));
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

文件地址包含中文

文件地址包含中文时,会抛出文件找不到的异常
需要对其进行转义
java.net.URLDecoder 类的 decode(filepath, "utf-8");
		String filepath = TestPath.class.getResource("含有中文的文件名").getFile();
		String decodePath = URLDecoder.decode(filepath, "utf-8");
		try (FileInputStream in = new FileInputStream(new File(decodePath));) {
			byte[] b = new byte[1024];
			int len = 0;
			while ((len = in.read(b)) > 0) {
				System.out.println(new String(b, 0, len));
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

文件过滤器

file[] listFiles(fileFilter) file对象的listFiles方法传入一个fileFilter对象
fileFilter是一个接口,需要我们自定义来实现
重写其中唯一的accept方法
package coollections;

import java.io.File;
import java.io.FileFilter;

public class MyFilter implements FileFilter {

	@Override
	public boolean accept(File pathname) {
		boolean flag = false;
		// File对象的最后一级文件/文件夹的名字
		String name = pathname.getName();
		if (name == null) {
			return flag;
		}
		//判断是否是文件
		if (name.contains(".")) {
			flag = true;
		}
		return flag;
	}

}

public static void main(String[] args)  {
		File file = new File("D:\\IO\\File");// 创建一个File对象
		File[] listFiles = file.listFiles(new MyFilter());
		//listFiles在遍历目录时会调用过滤器的accept方法
		//将遍历的路径传入accept方法的参数中
		//如果accept方法返回true,说明这个传入的路径指向一个文件,就存入File数组
		for (File file2 : listFiles) {//遍历文件
			System.out.println(file2);
		}

	}


目录的遍历

public static void main(String[] args)  {
		File file = new File("D:\\jar包\\IO\\File");// 创建一个File对象
		getAllFile(file);
	}

	public static void getAllFile(File f) {
		File[] listFiles = f.listFiles();// 获取当前目录下的文件及文件夹
		for (File file : listFiles) {
			if (file.isDirectory()) {// 如果是文件夹就继续遍历
				getAllFile(file);//递归
			} else {
				System.out.println(file);
			}
		}
	}

递归

方法内部调用自身
递归一定要有出口,不能是死循环
递归次数不能太多
构造方法禁止递归

斐波那契数列

不要在自身中调用两次递归
getArray(n):
		getArray(n-1) + getArray(n-2) 不建议
public static void main(String[] args) {
		getArray(9);

	}

	public static void getArray(int n) {
		int a = 0;
		int b = 1;
		for (int i = 0; i < n; i++) {
			int temp = b;
			b = a + b;
			a = temp;
			System.out.print(a + " ");
		}
	//1 1 2 3 5 8 13 21 34 
	}

//递归实现
public static void main(String[] args) {
		getNum(9);
	}

	public static void getNum(int num) {//取出第num位前所有的斐波那契数列的数值
		for (int a = 1; a <= num; a++) {
			int[] i = getArray(a);
			System.out.print(i[1] + " ");//取出第a位斐波那契数列的数值
		}
	}

	public static int[] getArray(int n) {//递归方法,每次返回斐波那契数列最后两位数		
		if(n < 1){
			int[] array = { 0, 0 };
				return array;
		}
		
		if (n == 1 || n == 2) {
			// i -= 1;
			int[] array = { 1, 1 };
			return array;
		} else {
			int[] re = getArray(n - 1);// 递归调用自身
			// i -= 1;
			// if (i == 0) {
			// return re;
			// }
			int temp = re[0];
			re[0] = re[1];
			re[1] = re[1] + temp;
			return re;
		}

	}

字节流

字节流有输入和输出流,操作数据的读取与存储
可以操作文本,视频,音乐,图片等

字节输出流OutputStream

抽象类,以字节操作数据的输出
所有字节输出流的父类
方法:
write(int b):写入单个字节的内容
write(byte[] b):写入字节数组中的内容
write(byte[] b,int start , int len):写入字节数组的一部分
close(): 先刷新流,再关闭流对象,释放与流有关的资源
flush(): 刷新缓存区,将缓存区剩余输出流的内容强制输出

字节输出流FileOutputStream

OutputStream的子类之一
构造方法参数可以传入一个文件路径或者File对象,必须是一个文件
如果这个文件不存在会自动创建这个文件

实现文件的追加与换行

public static void main(String[] args) throws IOException {
		File file = new File("D:\\IO\\File\\a.txt");
		// 传入File对象,第二参数为true,表示在文件末尾追加内容
		FileOutputStream fileOut = new FileOutputStream(file, true);
		fileOut.write("hello\r\n".getBytes());// 数据的传输类型一般是byte类型
		//\r\n是换行符
		fileOut.close();
	}

流的异常处理

package coollections;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class Streams {

	public static void main(String[] args) throws IOException {
		File file = new File("D:\\IO\\File\\a.txt");
		FileOutputStream fileOut = null;
		try {
			fileOut = new FileOutputStream(file, true);
			fileOut.write("hello\r\n".getBytes());
		}  catch (IOException e) {
			e.printStackTrace();
			throw new IOException("文件写入失败!");
		} finally {
			try {
				if (fileOut != null) {
					fileOut.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				throw new RuntimeException("文件流关闭失败!");
			}
		}

	}

}

字节输入流InputStream

抽象类
所有字节输入流的父类,用于读取文件
方法:
int read(int i)	按照单个字节读取,返回读取数据的ASCII编码值,读取到末尾返回-1
int read(byte[] b) 	按照字节数组长度读取字节存入数组中,返回读取的字节长度
					没有数据存入数组时返回-1
					数据存入数组,会覆盖之前存入数组的数据;
					新数据读取的长度不足覆盖数组长度,剩余的位置显示上一次数据
构造方法为流对象绑定数据源
参数可以为File对象或者String类型的FileName

FileInputStream

InputStream抽象类的子类
用于读取数据到数组缓冲区(byte数组)

单个字节读取文件内容

FileInputStream fileInputStream = new FileInputStream("D:\\IO\\File\\a.txt");
int num = 0;
while ((num = fileInputStream.read()) != -1) {
	System.out.print((char) num);
}
fileInputStream.close();

以数组读取文件内容

FileInputStream fileInputStream = new FileInputStream("D:\\IO\\File\\a.txt");
byte[] b = new byte[1024];
int len = 0;
while ((len = fileInputStream.read(b)) != -1) {//按照数组的形式读取
	System.out.print(new String(b, 0, len));//将byte数组转为String
}
fileInputStream.close();

获取文件编码的方法

转载https://blog.csdn.net/ardo_pass/article/details/86157619
gbk编码没问题,其他未测试,慎用
public static String codeString(String fileName) throws Exception {
		BufferedInputStream bin = new BufferedInputStream(new FileInputStream(fileName));
		int p = (bin.read() << 8) + bin.read();
		bin.close();
		String code = null;
		switch (p) {
		case 0xefbb:
			code = "UTF-8";
			break;
		case 0xfffe:
			code = "Unicode";
			break;
		case 0xfeff:
			code = "UTF-16BE";
			break;
		default:
			code = "GBK";
		}

		return code;
	}

文件的复制

最经典的文件复制,但效率低
	FileInputStream in = null;
	FileOutputStream out = null;
	try {
		in = new FileInputStream("D:\\jquery-1.10.2.zip");
		out = new FileOutputStream("E:\\a.zip");
		// 定义字节数组,缓冲
		byte[] b = new byte[1024];//数组大小越大,消耗时间会相对缩短(有极限)
		// 每次读取的数据长度
		int len;
		while ((len = in.read(b)) > 0) {// 将文件数据读取放入数组
			out.write(b, 0, len);// 将数组数据写入另一个文件
			out.flush();
		}
	} catch (IOException e) {
		e.printStackTrace();
		throw new RuntimeException("文件复制失败!");
	} finally {//嵌套关闭流
		try {
			if (out != null) {
				out.close();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("资源关闭失败!");
		} finally {
			try {
				if (in != null) {
					in.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				throw new RuntimeException("资源关闭失败!");
			}
		}
	}

转载文件复制的方法https://blog.csdn.net/karlin999/article/details/79756397

字符流

为了方便操作文本数据,Java提供了字符流
字符流只能操作文本数据

Writer

Java.Io.Writer是一个抽象类
所有字符输出流父类
方法:
write(int i) : 写入一个字符
write(char[] c) :写入一个char数组
...				写入char数组的一部分
write(String s):写入字符串
...				写入字符串的一部分

FileWriter

文件输出流,继承OutputStreamWriter(Writer的子类)
构造方法接收File对象或者String 文件名
字符输出流必须使用一个刷新功能flush()
将内存缓冲区的数据刷新进文件中
FileWriter fileWriter = new FileWriter("D:\\jar包\\IO\\File\\a.txt");
fileWriter.write("abhkjcfh");
//如果不是以追加的方式写入会先清空数据再写入
fileWriter.flush();//刷新数据进文件中
fileWriter.close();

Reader

Java.Io.Reader是一个抽象类
所有字符输入流的父类
方法:
int read() : 读取一个字符
int read(char[] c) : 读取一个字符数组
没有读取String的方法

FileReader

文件输入流,继承InputStreamReader(Reader的子类)
构造方法接收File对象或者String 文件名
FileReader fileReader = new FileReader("D:\\jar包\\IO\\File\\a.txt");
		char[] c = new char[1024];
		int len = 0;
		while ((len = fileReader.read(c)) > 0) {
			//可能出现乱码问题
			System.out.println(new String(c, 0, len));
		}

字符转化流

为了解决字符流操作文本文件可能出现的乱码问题

OutputStreamWriter

继承Writer抽象类
字符流转字节流的桥梁
工作过程: 写入中文时.OutputStreamWriter用要写入数据去查询已知编码的编码表,
			得到对应的字节,将字节交给对应字节输出流,用字节输出流去写入数据
作用就是改变数据的编码,解决中文乱码
构造器
OutputStreamWriter(OutputStream out)接收一个任意字节输出流对象
OutputStreamWriter(OutputStream out, String charsetName)接收字节输出流对象和编码
会清空原先文件数据
FileOutputStream fileInputStream = new FileOutputStream("D:\\a.txt");
OutputStreamWriter out = new OutputStreamWriter(fileInputStream, "GBK");
out.write("复赛放箭都");
out.close();

InputStreamReader

继承Reader抽象类
字符流转字节流的桥梁
InputStreamReader(FileInputStream out)接收一个任意字节输出流对象
InputStreamReader(FileInputStream out, String charsetName)接收字节输出流对象和编码

		FileInputStream fileInputStream = new FileInputStream("D:\\jar包\\IO\\File\\a.txt");
		InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "GBK");
		char[] c = new char[1024];
		int len = 0;
		while ((len = inputStreamReader.read(c)) > 0) {

			System.out.println(new String(c, 0, len));
		}

缓冲流

	为了提高IO流的读写速度而存在的缓冲流
	分为字节缓冲流和字符缓冲流

字节缓冲流

字节缓冲输出流:BufferedOutputStream
字节缓冲输入流:BufferedInputStream
内部都包含了一个缓冲区,通过缓冲区来读写数据,就提高了IO读写速度

BufferedOutputStream

字节缓冲输出流
继承FileOutputStream	
接收一个OutputStream对象作为构造器参数,提升这个对象的传输速度
会清空原先文件数据(除非以追加形式写入)
BufferedOutputStream buff = new BufferedOutputStream(new FileOutputStream("D:\\jar包\\IO\\File\\a.txt"));
byte[] b = "helflo".getBytes();
buff.write(b);
buff.close();

BufferedInputStream

字节缓冲输入流
继承FilterInputStream
接收一个InputStream对象作为构造器参数,提升这个对象的传输速度
BufferedInputStream bu = new BufferedInputStream(new FileInputStream("D:\\jar包\\IO\\File\\a.txt"));
		byte[] b = new byte[1024];
		int len = 0;
		while ((len = bu.read(b)) > 0) {
			System.out.println(new String(b, 0, len));
		}
在传输大数据文件时,字节缓冲流所用的时间是最少的
所以一般用字节缓冲流传输数据

字符缓冲流

实现文件的高速读取
字符缓冲输入流:BufferedReader
字符缓冲输出流:BufferedWriter

BufferedWriter

字符缓冲输出流
继承Writer抽象类
write() 可以传入单个字符,字符数组,字符串
构造方法
BufferedWriter(Writer w ) 传入任意字符输出流
FileWriter fileWriters = new FileWriter("D:\\jar包\\IO\\File\\a.txt", true);
BufferedWriter b = new BufferedWriter(fileWriters);
b.write("放得开".toCharArray());
b.flush();
b.close();

BufferedReader

字符缓冲输入流
继承Reader抽象类
readLine():读取一行数据
FileReader fileReader = new FileReader("D:\\jar包\\IO\\File\\a.txt");
BufferedReader bu = new BufferedReader(fileReader);
char[] c = new char[1024];
int len = 0;
while ((len = bu.read(c)) > 0) {
	System.out.println(new String(c, 0, len));
}

用字符缓冲流完成文本文件的复制

简略

BufferedReader bu = new BufferedReader(new FileReader("D:\\jar包\\IO\\File\\a.txt"));
BufferedWriter wr = new BufferedWriter(new FileWriter("D:\\jar包\\IO\\File\\c.txt"));
String line = null;
while ((line = bu.readLine()) != null) {
	wr.write(line);
	wr.flush();
}
wr.close();
bu.close();

IO使用

对文件或文件夹操作
文件夹操作
	File对象
文件操作
	流对象
		文本对象
			字符流
				要高效读写
					缓冲流
				非高效 
					视情况而定
				防止乱码
					转换流
		非文本对象
			字节流
				要高效读写
					缓冲流
				非高效 
					视情况而定

总结

java.io包
字节流
	InputStream(抽象类):所有字节输入流的父类,用于读取任意类型数据
		常用方法int read(byte[] b) 按照字节数组长度读取字节存入数组中
		常用子类FileInputStream	
	OutputStream(抽象类):所有字节输出流的父类,用于写入任意类型数据
		常用方法write(byte[] b):写入字节数组中的内容
		常用子类FileOutputStream
			new FileOutputStream(fileName, true);//追加文件

字符流

	Reader(抽象类):所有字符输入流的父类
		常用方法int read(char[] c) : 读取一个字符数组,没有读取String的方法
		常用子类FileReader:字符输入流,继承InputStreamReader(Reader的子类)
	
	Writer(抽象类):所有字符输出流父类,用于写入文本类型数据
		常用方法write(char[] c) :将文本数据写入char数组
		常用子类FileWriter:字符输出流,继承OutputStreamWriter(Writer的子类)
		字符对象写入数据需要flush刷新一下

字符转化流:
	为了解决字符流操作文本文件可能出现的乱码问题,将字符流转为字节流
		需要一个OutputStream对象和文本编码作为构造器的参数
		OutputStreamWriter继承Writer抽象类
		需要一个InputStream对象和文本编码作为构造器的参数
		InputStreamReader继承Reader抽象类

缓冲流:
	通过缓冲区来读写数据提高IO的读写速度
	
	字节缓冲输出流,接受一个OutputStream对象作为构造器的参数
	BufferedOutputStream(继承FileOutputStream)
	字节缓冲输入流,接受一个InputStream对象作为构造器的参数
	BufferedInputStream(继承FilterInputStream)

	字符缓冲输出流,接受一个Writer对象作为构造器的参数
	BufferedWriter(继承Writer抽象类)
	字符缓冲输入流,接受一个Reader对象作为构造器的参数
	BufferedReader(继承Reader抽象类)可以读取一行数据

以上是最常用的流,IO包中还有很多其它的流

字符串编码转换

new String(byte[] b , 0 , length , encodeing) 

Properties

Map集合子类
继承Hashtable(继承Dictionary抽象类,实现Map接口)
无序的
配合IO完成数据的持久化
没有泛型,key与value都是字符串类型

对键值对数据进行操作,很适合配置文件的读写
方法:
void load(InputStream in):接收任意字节输入流对象,从中读取键值对
void load(Reader read) :接收任意字符输入流对象,从中读取键值对
store(OutputStream out,String 描述信息):接收任意字节输出流,通过输出流将数据持久化
store(Write it,String 描述信息):接收任意字符输出流,通过输出流将数据持久化
setProperties(key,value):存放数据
getProperties(key):获取数据
Set<String> stringPropertyName():获取所有的key,返回一个Set集合
Properties p = new Properties();
String path = new File(".").getCanonicalPath();
String f = "src\\coollections\\pro.properties";
FileReader reader = new FileReader(new File(path, f));
p.load(reader);//数据的读取
reader.close();
System.out.println(p);
// {age=25, school=135, name=张三, sex=1}

p.setProperty("name", "李四");//如果key存在就覆盖原value值
p.setProperty("age", "24");
p.setProperty("sex", "3");

FileWriter fileWriter = new FileWriter(new File(path, f));
p.store(fileWriter, "text");
//数据的写入,输入的描述信息只能为英文,中文会自动转为unicode码
fileWriter.close();

//最后pro.properties文件内容:
//#text
//#Tue Feb 11 18:54:24 CST 2099
//age=24
//name=李四
//sex=3

try-with-resources释放资源

进行文件数据读写时,一般都会出现IO异常,需要我们主动捕获或抛出
同时对读写资源进行关闭,如果使用常见的try–catch-finally来关闭资源
1.就会使得finally中的代码十分臃肿
2.finally中如果抛出异常有时会覆盖try中抛出的异常
案例如下:
		FileInputStream in = null;
		FileOutputStream out = null;
		try {
			in = new FileInputStream("D:\\apache-tomcat-9.0.8-src.zip");
			out = new FileOutputStream("E:\\a");
			// 定义字节数组,缓冲
			byte[] b = new byte[1024];
			// 每次读取的数据长度
			int len;
			while ((len = in.read(b)) > 0) {// 读取文件
				out.write(b, 0, len);// 写入文件
				out.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("文件复制失败!");
		} finally {
			try {
				if (out != null) {
					out.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
				throw new RuntimeException("资源关闭失败!");
			} finally {
				try {
					if (in != null) {
						in.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
					throw new RuntimeException("资源关闭失败!");
				}
			}
		}

try–catch-finally方式将资源的关闭放在finally中,会使代码臃肿
try-with-resources将要释放的资源放在try(要释放的资源){}中
要释放的资源需要实现AutoCloseable 接口或Closeable接口
Closeable接口继承了AutoCloseable 接口

try-with-resources语句是一种声明了一种或多种资源的try语句
try-with-resources语句保证了每个声明了的资源在语句结束的时候都会被关闭。
任何实现了java.lang.AutoCloseable接口的对象,
和实现了java.io.Closeable接口的对象,都可以当做资源使用

所以无论try语句是正常结束还是异常结束,资源都会被被关闭
示例如下:
		try(FileInputStream in = new FileInputStream("D:\\apache-tomcat-9.0.8-src.zip");
			FileOutputStream out =	 new FileOutputStream("E:\\a");
		) {
			// 定义字节数组,缓冲
			byte[] b = new byte[1024];
			// 每次读取的数据长度
			int len;
			while ((len = in.read(b)) > 0) {// 读取文件
				out.write(b, 0, len);// 写入文件
				out.flush();
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException("文件复制失败!");
		} 
抽象类InputStream实现了Closeable接口
Closeable接口继承了AutoCloseable接口

要释放自定义资源的话,只要实现 AutoCloseable 接口,并提供 close() 方法的实现即可
class MyResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("关闭自定义的资源");
    }
    
    public void test() throws Exception{
        throw new Exception("test()");
    }
}
在处理必须关闭的资源时,考虑使用 try-with-resources,
而不是 try–catch-finally。
优点:
1.代码简洁
2.close方法中异常不会覆盖try语句块中抛出的异常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值