1、异常处理
java 2种异常处理:
a:自己将该问题处理,然后继续运行(try catch)
try{
… //可能产生异常的地方
}catch(Exception e){
e.printStackTrace();
… //出异常后,捕获异常进行处理,jvm默认就用这种方式处理异常
return;
}finally{
… //释放资源,一定会执行,比如关闭已打开的io流。
}
注意:
被finally控制的语句体一定会执行,特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
return语句在执行之前,会检查有没有finally,如果有就将finally执行
b:将异常抛出(throws):定义功能方法时,需要把出现的问题暴露出来让调用者去处理。
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setAge(-17);
System.out.println(p.getAge());
}
throw的概述以及和throws的区别
throws:用在方法声明后面,跟的是异常类名; 可以跟多个异常类名,用逗号隔开; 表示抛出异常,由该方法的调用者来处理
throw:用在方法体内,跟的是异常对象名; 只能抛出一个异常对象名; 表示抛出异常,由方法体内的语句处理
也可以自定义异常:
class AgeOutOfBoundsException extends Exception {
public AgeOutOfBoundsException() {//不带参数的构造函数
super();
}
public AgeOutOfBoundsException(String message) {//带参数的构造函数
super(message);
}
}
final、finally、finalize区别
final:可以修饰类,不能被继承 ; 修饰方法,不能被重写 ; 修饰变量,只能赋值一次
finally:是try语句中的一个语句体,不能单独使用,用来释放资源
finalize:是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
如果catch里面有return语句,finally的代码会执行,但是在finally中定义的变量值不会改变,会使用return之前语句的变量值
try {
x = 20;
System.out.println(1/0);
return x;
} catch (Exception e) {
x = 30;
return x;
} finally {
x = 40;
//return x; 千万不要在finally里面写返回语句
}
//结果会返回x=30
2、File类:文件和目录路径名的抽象表示形式
构造方法:
File(String pathname) //根据一个路径得到File对象,pathname是个绝对路径”C:\Users\user\Desktop\java\test.txt”
File(String parent, String child) //parent目录 child目录或文件名称
File(File parent, String child) //parent 是File对象(目录的File对象),child 文件名称或者目录
基本的方法:
File file = new File("a.txt");
file.createNewFile(); //如果没有就创建,返回true
file.mkdir(); //创建文件夹 如果存在这样的文件夹,就不创建了
file.mkdirs("aa\\bb"); //创建文件夹,如果父文件夹不存在,会帮你创建出来,创建2个层级目录
boolean isDirectory() //判断是否是目录
boolean isFile() //判断是否是文件
boolean exists() //判断是否存在
boolean canRead() //判断是否可读
boolean canWrite() //判断是否可写
boolean isHidden() //判断是否隐藏
boolean getAbsolutePath() //获取绝对路径
String getPath() //获取路径
String getName() //获取名称
long length() //获取长度。字节数
long lastModified() //获取最后一次的修改时间,毫秒值
练习:获取d盘目录下所有的txt文件
File dir = new File("E:\\");
String[] arr = dir.list(); //获取d盘下所有的文件或文件夹
for (String string : arr) {
if(string.endsWith(".txt")) { //endsWith 判断是否以.txt结尾
System.out.println(string);
}
3、IO流:IO流用来处理设备之间的数据传输,Java用于操作流的类都在IO包中。
流按流向分为两种:输入流,输出流。
流按操作类型分为两种:
字节流 (Byte:8位0/1): 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
字节流的抽象父类:
InputStream
OutputStream
字符流 (char:具体的大小由编码表决定): 字符流只能操作纯字符数据,比较方便。
字符流的抽象父类:
Reader
Writer
字节流使用:
a、FileInputStream基本用法:
FileInputStream fis = new FileInputStream("a.txt"); //创建流对象
int b; //定义变量,记录每次读到的字节,注意使用的是int类型接受
while((b = fis.read()) != -1) { //将每次读到的字节赋值给b并判断是否是-1
System.out.println(b); //打印每一个字节
}
fis.close(); //关闭流释放资源
注意:
read()方法读取的是一个字节,为什么返回是int,而不是byte?
因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型。
b、FileOutputStream基本用法:
FileInputStream fis = new FileInputStream("a.txt"); //创建流对象
FileOutputStream fos = new FileOutputStream("b.txt"); //创建输出流对象,关联b.txt
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
fos.close();
c、使用FileInputStream,FileOutputStream每次读取一个byte和写出一个byte效率太低了!!!
解决办法可以定义一个小数组接受
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt");
int len;
byte[] arr = new byte[1024 * 8]; //自定义字节数组,默认缓冲的大小也是1024*8 byte
while((len = fis.read(arr)) != -1) {
//fos.write(arr); //如果这样写了,就会多些数据,因为读到末尾的时候不一定就是1024*8个字节
fos.write(arr, 0, len); //写出字节数组写出有效个字节个数
}
fis.close();
fos.close();
d、java也考虑到了读取效率低的问题,所以封装了一个BufferedInputStream和BufferedOutputStream类来使用。
BufferedInputStream 会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个int长度;程序再次读取时, 就不用找文件了, 直接从缓冲区中获取,直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个byte。
BufferedOutputStream 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中,直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
因为使用buffer操作的是内存,比直接操作硬盘效率要高很多。
FileInputStream fis = new FileInputStream("a.mp3"); //创建文件输入流对象,关联a.mp3
BufferedInputStream bis = new BufferedInputStream(fis); //创建缓冲区对fis装饰
FileOutputStream fos = new FileOutputStream("b.mp3"); //创建输出流对象,关联b.mp3
BufferedOutputStream bos = new BufferedOutputStream(fos); //创建缓冲区对fos装饰
int b; //读取的有效长度
while((b = bis.read()) != -1) { //从硬盘中读取1024*8 byte
bos.write(b);
}
bis.close(); //只关装饰后的对象即可
bos.close();
小数组的读写和带Buffered的读取哪个更快?
定义小数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组。
flush和close方法的区别
用来刷新缓冲区的,刷新后可以再次写出,例如qq聊天的窗口
用来关闭流释放资源的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出
字节流读写中文问题:
读中文的时候有可能会出现乱码,因为一个中文2个字符。假设文件全是中文且没有标点,字母等字符,设置arr为2的整数倍读取没有问题
只要有标点或字母,读取的时候就可能出现读到半个中文,码表找不到的中文会用?代替。
字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组,例如写出回车换行
write("\r\n".getBytes());
e、流的标准处理异常代码1.6版本及其以前
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("a.txt");
fos = new FileOutputStream("b.txt");
int b;
while((b = fis.read()) != -1) {
fos.write(b);
}
} finally {
try {
if(fis != null)
fis.close();
}finally {
if(fos != null)
fos.close();
}
}
f、给数据加密(原理是数据异或两次后就是自己)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg")); //可以不用分开写
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg")); //可以不用分开写
int b;
while((b = bis.read()) != -1) {
bos.write(b ^ 123);
}
bis.close();
bos.close();
字符流使用:字符流是可以直接读写字符的IO流
字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要写出字符, 需要把字符转为字节再写出。
a、FileReader基本用法:
FileReader类的read()方法可以按照字符大小读取
FileReader fr = new FileReader("a.txt"); //创建输入流对象,关联aaa.txt
int ch; //文件是用二进制数据存储的,读取的时候会使用int类型接受,
//字符大小根据码表不同而定 GBK一个中文2个字符
while((ch = fr.read()) != -1) { //将读到的字符赋值给ch
System.out.println((char)ch); //将读到的字符强转后打印
}
fr.close(); //关流
b、FileWriter基本用法:
FileWriter fw = new FileWriter("b.txt");
fw.write("aaa");
fw.close();
c、字符流的拷贝:
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
int ch;
while((ch = fr.read()) != -1) {
fw.write(ch);
}
fr.close();
fw.close();
d、什么情况下使用字符流?
字符流也可以拷贝文本文件, 但不推荐使用. 因为读取时会把字节转为字符, 写出时还要把字符转回字节;
程序需要读取一段文本, 或者需要写出一段文本的时候可以使用字符流;
读取的时候是按照字符的大小读取的,不会出现半个中文;
写出的时候可以直接将字符串写出,不用转换为字节数组。
注意:
字符流是不可以拷贝非纯文本的文件,因为在读的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用?代替。
e、自定义字符数组的拷贝:
FileReader fr = new FileReader("a.txt"); //创建字符输入流,关联a.txt
FileWriter fw = new FileWriter("b.txt"); //创建字符输出流,关联b.txt
int len;
char[] arr = new char[1024*8]; //创建字符数组
while((len = fr.read(arr)) != -1) { //将数据读到字符数组中
fw.write(arr, 0, len); //从字符数组将数据写到文件上
}
fr.close(); //关流释放资源
fw.close();
f、带缓冲的字符流:
BufferedReader br = new BufferedReader(new FileReader("a.txt")); //创建字符输入流对象,关联a.txt
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt")); //创建字符输出流对象,关联b.txt
int ch;
while((ch = br.read()) != -1) { //read一次,会先将缓冲区读满,从缓冲去中一个一个的返给临时变量ch
bw.write(ch); //write一次,是将数据装到字符数组,装满后再一起写出去
}
br.close(); //关流
bw.close();
g、readLine()和newLine()方法
BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
BufferedWriter的newLine()可以输出一个跨平台的换行符号"\r\n"
例如:
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
String line;
while((line = br.readLine()) != null) {
bw.write(line);
//bw.write("\r\n"); //只支持windows系统
bw.newLine(); //跨平台的
}
br.close();
bw.close();
h、使用指定的码表读写字符
BufferedReader br = //高效的用指定的编码表读
new BufferedReader(new InputStreamReader(new FileInputStream("UTF-8.txt"), "UTF-8"));
BufferedWriter bw = //高效的用指定的编码表写
new BufferedWriter(new OutputStreamWriter(new FileOutputStream("GBK.txt"), "GBK"));
int ch;
while((ch = br.read()) != -1) {
bw.write(ch);
}
br.close();
bw.close();