文章目录
- 异常
- 小总结
- 编译时异常和运行时异常
- 小总结
- 异常在代码中的两个作用
- 异常的方式
- JVM虚拟机默认处理异常的方式
- 自己处理(捕获异常)
- 灵魂四问
- 抛出异常
- 异常中的常见方法
- 小总结
- 小练习
- 自定义异常
- File----路径
- File的概述和构造方法
- 小总结
- File的成员方法
- 判断、获取
- 创建、删除
- 获取并遍历----1
- 获取并遍历----2
- 小练习
- 练习-1
- 练习-2
- 练习-3
- 练习-4
- 练习-5
- 练习-6
- IO流
- IO流的概述
- IO流的分类
- 小总结
- IO流的体系
- 字节输出流
- 字节输出流基本用法
- 字节输出流的细节
- FileOutputStream写数据的3种方式
- FileOutputStream写数据的两个小问题
- 小总结
- 字节输入流
- 字节输入流的基本用法
- FileInputStream书写细节
- FileInputStream循环读取
- 文件拷贝
- FileInputStream读取的问题
52~134
异常
异常就是代表程序出现的问题
误区:不是让我们以后不出异常,而是程序出现异常之后,该如何处理
打人家玻璃是不对的
现在学习的不是让你以后不打别人家的玻璃
而是打碎别人家的玻璃之后该怎么处理
Erroe:代表的系统级别错误(属于严重问题)
系统一旦出现问题,sun公司会把这些错误封装成Error对象
Erroe是给sun公司自己用的,不是给我们程序员用的,
因此我们开发人员不管他
Exception:叫做异常,代表程序可能出现的问题
我们通常会用Exception以及他的子类来封装程序出现的问题
运行时异常:RuntimeException及其子类,编译阶段不会出现异常提醒
运行时出现的异常(如:数组索引越界异常)
编译时异常:编译阶段就会出现异常提醒的。(如:日期解析异常)
小总结
1、异常是什么?
程序中可能出现的问题
2、一场体系的最上层父类是谁?异常分几类?
父类:Exception
异常分为两类:编译时异常、运行时异常
3、编译时异常和运行时异常的区别?
编译时异常:没有继承RuntimeException的异常,直接继承于Exception。编译阶段就会错误提示
运行时异常:RuntimeException本身和子类
编译阶段没有错误提示,运行时出现的
编译时异常和运行时异常
String name = "2030年1月1日";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
Date date = sdf.parse(time);
System.out.println(date);
parse正常情况下会报错,需要在main函数的后面加上throws ParseException
才能将报错取消
这就是编译时异常,在编译阶段,必须要手动处理,否则代码报错
int[] arr = {1,2,3,4,5};
System.out.println(arr[10]);
数组越界异常,标准的运行时异常,在编译阶段是不需要处理的,是代码运行时出现的异常
为什么分两种异常?
在编译阶段,java不会运行diamagnetic,只会检查语法是否错误,或者做一些性能的优化,更多的是提醒程序员检查本地信息
运行时异常就是代码出错而导致程序出现问题
小总结
运行时异常和编译时异常的区别?
编译时异常:除了RuntimeException和他的子类,其他都是编译时异常,编译阶段需要进行处理,作用在于提醒程序员
运行时异常:RuntimeException本身和所有子类,都是运行时异常,编译阶段不报错,是程序运行时出现的,一般是由参数传递错误带来的问题
异常在代码中的两个作用
作用一:异常是用来查询bug的关键参考信息
作用二:异常可以作为方法内部的一种特殊返回值,以便通知调用者底层的执行情况
public void setAge(int age){
if(age < 18 || age > 40){
throw new RuntimeException();
}else {
this.age=age;
}
}
学生类中的赋值年龄成员函数,如果是年龄小于18或者大于40的打印输出语句提示错误,只是在控制台打印出来,并不能直接告诉调用处(代码编写处)
这样就可以有两种解决方法,第一种自己处理掉问题,或者打印在控制台上
异常的方式
1、JVM虚拟机默认处理异常的方式
2、自己处理
3、抛出异常(交给调用者)
JVM虚拟机默认处理异常的方式
把异常的名称,异常原因及异常出现的位置等信息输出在了控制台上
程序停止运行,下面的代码不会再执行了
System.out.println("狂踹瘸子那条好腿");
System.out.println(2/0);
System.out.println("是秃子终会发光");
System.out.println("火鸡味锅巴");
自己处理(捕获异常)
格式:
下面展示一些 内联代码片
。
try{
可能出现异常的代码;
} catch(异常类名 变量名){
异常的处理代码;
}
自己处理捕获异常的目的就是当代码出现问题的时候,可以让程序继续往下执行
int[] arr = {1,2,3,4,5,6};
try {
System.out.println(arr[10]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("索引越界了");
}
System.out.println("看看我执行了吗");
灵魂四问
灵魂一问:如果try中没有遇到问题,怎么执行?
会把try里面的代码全部执行完毕,不会执行catch里面的代码
注意:只有当出现了异常才会执行catch里面的代码
灵魂二问:如果try中可能会遇到多个问题,怎么执行?
要写多个catch与之对应
细节:如果我们要捕获多个异常,这些异常中如果存在父子关系的话,那么父类一定要写在下面
了解性:在JDK7之后,我们可以在catch中同时捕获多个异常,中间用|进行隔开
表示如果出现了A异常或者B异常的话,采取同一种处理方案
灵魂三问:如果try中遇到的问题没有被捕获,怎么执行?
相当于try…catch的代码白写了,最终还是会交给虚拟机进行处理
灵魂四问:如果try中遇到了问题,那么try下面的其他代码还会执行吗?
下面的代码就不会运行了,直接跳转到对应的catch当中,执行catch里面的语句体
但是如果没有对应catch与之匹配,那么还是会交给虚拟机进行处理
抛出异常
throws:
注意:写在方法定义出,表示声明一个异常
告诉调用者,使用本方法可能会有哪些异常
public void 方法()throws 异常类名1,异常类名2...{
...
}
编译时异常:必须要写
运行时异常:可以不写
throw:
注意:写在方法内,结束方法
手动抛出异常对象,交给调用者
方法中下面的代码不再执行了
public void 方法(){
throw new NullPointerException();
}
public static void main(String[] args) {
int[] arr = {};
try{
int max = getMax(arr);
}catch (NullPointerException e){
System.out.println("空指针异常");
}catch (ArrayIndexOutBoundsException e){
System.out.println("索引越界异常");
}
System.out.println(max);
}
public static int getMax(int[] arr){
if(arr == null){
//手动创建一个异常,并把这个异常交给方法的调用者处理
//此时方法就会结束,下面的代码不会再执行了
throw new NullPointerException();
}
if(arr.length == 0){
throw new ArratIndexOutOfBoundsException();
}
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]>max){
max = arr[i];
}
}
return max;
}
异常中的常见方法
Throeable的成员方法
public String getMessage()//返回此Throwable的详细信息字符串
public String toString()//返回此可抛出的简短描述
public void printStackTrace()//把异常的错误信息输出在控制台,仅仅是打印红字信息,不会停止程序运行
小总结
1、虚拟机默认处理异常的方式
把异常信息以红色字体打印在控制台,并结束程序
2、捕获:try…catch
一般用在调用出,能让代码继续往下运行
3、抛出:throw throws
在方法中,出现异常了
方法就没有继续运行下去的意义了,采取抛出异常
让该方法结束运行并告诉调用者出现了问题
小练习
需求:
键盘录入自己心仪的女朋友姓名和年龄
姓名的长度在3~10之间
年龄的范围为18~40岁
超出这个范围是异常数据不能赋值,需要重新录入,一直录到正确为止
提示:
需要考虑用户在键盘录入时的所有情况
比如:录入年龄时超出范围,录入年龄时录入了abc等情况
Scanner sc = new Scanner(System.in);
GrilFriend gf = new GrilFriend();
while (true) {
try {
System.out.println("请输入你心仪的女朋友的名字");
String name = sc.nextLine();
gf.setName(name);
System.out.println("请输入你心仪的女朋友的年龄");
String ageStr = sc.nextLine();
int age = Integer.parseInt(ageStr);
gf.setAge(age);
//如果所有的数据都是正确的,那么跳出循环
break;
} catch (NumberFormatException e) {
System.out.println("年龄的格式有误,请输入数字");
continue;
} catch (RuntimeException e){
System.out.println("姓名的长度 或者 年龄的范围有误");
continue;
}
}
System.out.println(gf);
public class GrilFriend {
private int age;
private String name;
public GrilFriend(int age, String name) {
this.age = age;
this.name = name;
}
public GrilFriend() {
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age<18||age>40){
throw new RuntimeException();
}
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
int len = name.length();
if (len<3 || len>10){
throw new RuntimeException();
}
this.name = name;
}
}
自定义异常
创建自定义异常
1、定义异常类
2、写继承关系
3、空参构造
4、带参构造
自定义异常的意义就是为了让控制台的报错信息更加的见名知意
public class NameFormatException extends RuntimeException{
//技巧:
//NameFormat:当前异常的名字,表示姓名格式化问题
//Exception:表示当前类是一个异常类
//继承问题
//运行时异常:RuntimeException
//编译时异常:Exception 核心 提醒程序员检查本地信息
public NameFormatException() {
}
public NameFormatException(String message) {
super(message);
}
}
public class AgeOutOfBoundsException extends RuntimeException{
public AgeOutOfBoundsException() {
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
File----路径
File的概述和构造方法
File对象就表示一个路径,可以是文件的路径、也可以是文件夹的路径
这个路径可以是存在的,也允许是不存在的
public File(String pathname)//根据文件路径创建文件对象
public File(String parent, String child)//根据父路径名字符串和子路径名字符串创建文件对象
public File(File parent, String child)//根据父路径对应文件对象和子路径名字符串创建文件对象
以“C:\Users\xiaoyou\Desktop\a.txt”为例
父级路径就是“C:\Users\xiaoyou\Desktop”
子级路径就是“a.txt”
小总结
1、File表示什么?
File对象表示路径,可以是文件、也可以是文件夹
这个路径可以是存在的,也可以是不存在的
2、绝对路径和相对路径是什么意思?
绝对路径是带盘符的
相对路径是不带盘符的,默认到当前项目下去找
3、File三种构造方法的作用
public File(String pathname)//根据文件路径创建文件对象
public File(String parent, String child)//根据父路径名字符串和子路径名字符串创建文件对象
public File(File parent, String child)//根据父路径对应文件对象和子路径名字符串创建文件对象
File的成员方法
判断、获取
public boolean isDirectory()//判断路径名表示的File是否为文件夹
public boolean isFile()//判断此路径名表示的File是否为文件
public boolean exists()//判断此路径名表示的File是否存在
public long length()//返回文件的大小(字节数量)
public String getAbsolutePath()//返回文件的绝对路径
public String getPath()//返回定义文件时使用的路径
public String getName()//返回文件的名称,带后缀
public long lastModeidied()//返回文件的最后修改时间(时间毫秒值)
length细节:
细节1、
这个方法只能获取文件的大小,单位是字节
如果单位我们要是M,G可以不断地除以1024
细节2、
这个方法无法获取文件夹的大小,(0/4096)
如果我们要获取一个文件夹的大小,需要把这个文件夹里面所有的文件大小都累加在一起
getName细节:
细节1、
如果调用者是个文件,会返回文件名和后缀名
细节2、
如果调用者是文件夹,返回的就是文件夹的名字
String str = "C:\\Users\\xiaoyou\\Desktop\\信息.txt";
File f1 = new File(str);
Date date = new Date(f1.lastModified());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
System.out.println(sdf.format(date));
创建、删除
public boolean creatNewFile()//创建一个新的空的文件
public boolean mkdir()//创建单级文件夹
public boolean mkdirs()//创建多级文件夹
public boolean delete()//删除文件夹、空文件夹
delete方法默认只能删除文件和空文件夹,delete方法直接删除不走回收站
createNewFile细节:
细节1、
如果当前路径表示的文件是不存在的,则创建成功,方法返回true
如果当前路径表示的文件是存在的,则创建失败,方法返回false
细节2、
如果父级路径是不存在的,那么方法会有异常IOException
细节3、
createNewFile方法创建的一定是文件,如果路径中不包含后缀名,则创建一个没有后缀名的文件
mkdir细节:
细节1、
Windows当中路径一定是唯一的,如果当前路径已经存在,则创建失败,返回false
细节2、
mkdir方法只能创建单级文件夹,无法创建多级文件夹
mkdirs细节:
即可以创建单级的,又可以创建多级的文件夹
delete细节
细节1、
如果删除的是文件,则直接删除,不走回收站
如果删除的是空文件夹,则直接删除,不走回收站
如果删除的是有内容的文件夹,则删除失败
获取并遍历----1
public File[] listFiles()//获取当前该路径下所有内容
//1、创建File对象
File f = new File("D:\\aaa");
//2、listFiles方法
//作用:获取aaa文件夹里面的所有内容,把所有的内容放到数组中返回
File[] files = f.listFiles();
for (File file : files){
//file依次表示aaa文件夹里面的每一个文件或者文件夹
System.out.println(file);
}
listFiles细节
1、当调用者File表示的路径不存在时,返回null
2、当调用者File表示的路径是文件时,返回null
3、当调用者File表示的路径是一个空文件夹时,返回一个长度为0的数组
4、当调用者File表示的路径是一个有内容的文件夹时,将里面所有的文件和文件夹的路径放在File数组中返回
5、当调用者File表示的路径是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路劲放在File数组中返回,包含隐藏文件
6、当调用者File表示的路径是需要权限才能访问的文件夹时,返回null
获取并遍历----2
public static File[] listRoots()//列出可用的文件系统根
public String list()//获取当前该路径下所有内容
public String list(FilenameFilter filter)//利用文件名过滤器获取当前该路径下所有内容
public File[] listFiles()//获取当前该路径下所有内容
public File[] list(FileFilter filter)//利用文件名过滤器获取当前该路径下所有内容
public File[] listFiles(FilenameFilter filter)//利用文件名过滤器获取当前该路径下所有内容
list(FilenameFilter filter)
accept方法的形参,依次表示aaa文件夹李米娜每一个文件或者文件夹路径
参数一:父级路径
参数二:子级路径
返回值:如果返回值为true,就表示当前路径保留;如果返回值为false,就表示当前路径舍弃不要
小练习
练习-1
练习-2
练习-3
练习-4
练习-5
练习-6
IO流
IO流的概述
IO流:存储和读取数据的解决方案
File:表示系统中文件或者文件夹的路径
获取文件信息(大小,文件名,修改时间)、判断文件类型、创建文件/文件夹、删除文件/文件夹…
File类只能对文本本身进行操作,不能读写文件里面存储的数据
IO流:用于读写文件中的数据(可以读写文件,或网络中的数据…)
IO流中,谁在读,谁在写?以谁为参照物看读写的方向呢?
以程序(内存)为参照物
IO流的分类
按流的方向可以分为输入流和输出流
输入流:读取
输出流:写去
按操作文件类型可以分为字节流和字符流
字节流可以操作所有类型的文件
字符流只能操作纯文本文件
纯文本文件:Windows自带的记事本打开能读懂
小总结
1、什么是IO流?
存取和读取数据的解决方案
I:input
O:output
流:像水流一样传输数据
2、IO流的作用?
用于读写数据(本地文件,网络)
3、IO流按照流向可以分类哪两种流?
输出流:程序---->文件
输入流:文件---->程序
4、IO流按照操作文件的类型可以分类哪两种流?
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
5、什么是纯文本文件?
用Windows自带的记事本打开能读懂
txt文件,md文件,xml文件,lrc文件等
IO流的体系
字节输出流
字节输出流基本用法
FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
书写步骤
1、创建字节输出流对象
2、写数据
3、释放资源
FileOutStream fos = new FileOutputStream("myio//a.txt");
fos.write(97);
fos.close();
FileOutputStream的原理
FileOutputStream就是创建了一个程序与文件之间的通道,
write就是将书写的内容通过通道传输到文件之中
close就是再将这个连接的通道“敲碎”
字节输出流的细节
1、创建字节输出流对象
细节1:参数是字符串表示的路径或者是File对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件
2、写数据
细节:write方法的参数是整数,但是实际上写道本地文件中的是整数在ASCII上对应的字符
3、释放资源
每次使用完流之后都要释放资源,就是将文件从内存运行中停止,这样后续就能够继续操作文件了,不然是操作不了的
FileOutputStream写数据的3种方式
void write(int b)//一次写一个字节数据
void write(byte[] b)//一次写一个字节数组数据
void write(byte[] b, int off, int len)//一次写一个字节数组的部分数据
关于wirte的第三种使用
参数一:数组
参数二:起始索引
参数三:个数
FileOutputStream写数据的两个小问题
写数据的两个小问题:想要换行写以及再次写不会清空而是继续写的续写
换行写:
再次写出一个换行符就可以了
windows:\r\n
Linux:\n
Mac:\r
细节:
在Windows操作系统当中,java对回车换行进行了优化,
虽然完整的是\r\n,但是我们写其中一个\r或者\n就可以
java也可以实现换行,因为java在底层会补全
建议:不要省略,还是写全了
续写:
如果想要续写,打开续写开关即可
开关位置:创建对象的第二个参数
默认false:表示关闭续写,此时创建对象会清空文件
手动传递true:表示打开续写,此时创建对象不会清空文件
FileOutputStream fos = new FileOutputStream("myrio\\a.txt");
Stirng str = "laozizhengshuai";
byte[] bytes = str.getBytes();
fos.write(bytes);
String wrap = "\r\n";
byte[] bytes2 = wrap.getBytes();
fos.write(bytes2);
String str2 = "666";
byte[] byte3 = str2.getBytes();
fos.write(bytes3);
fos.close();
小总结
1、FileOutputStream的作用
可以把程序中的数据写到本地文件上,是字节流的基本流
2、书写步骤
创建对象,写出数据,释放资源
3、三步操作的细节
创建对象:文件存在、文件不存在、追加写入
写出数据:写出整数、写出字节数组、换行写
释放资源:关闭通道
字节输入流
字节输入流的基本用法
FileInputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来
书写步骤:
1、创建字节输入流对象
2、读数据
3、释放资源
FileInputStream fis = new FileInputStream("巴拉巴拉路径");
int b1 = fis.read();//只能读取一个字符,读不到了就返回-1
System.out.println(b1);
fis.close();
FileInputStream书写细节
1、创建字节输入流对象
细节:如果文件不存在,就直接报错
java为什么会这么设计呢?
输出流:不存在,创建——把数据写到文件当中
输入流:不存在,而是报错?
因为创建出来的文件是没有数据的,没有任何意义。
所以java就没有设计这种无意义的逻辑,文件不存在直接报错
程序中最重要的是:数据。
2、读取数据
细节1:一次读一个字节,读出来的是数据在ASCII上对应的数字
细节2:读到文件末尾了,read方法返回-1。
3、释放资源
细节:每一次使用完流必须要释放资源
FileInputStream循环读取
FileInputStream fis = new FileInputStream("巴拉巴拉路径");
int b;
while((b == fis.read()) != -1){
System.out.println((char)b);
}
fis.close();
文件拷贝
注意:先选择一个比较小的文件,不要太大
//1、创建对象
FileInputStream fis = new FileInputStream("巴拉巴拉路径");
FileOutputStream fos = new FileOutputStream("巴啦啦路径");
//2、拷贝
//核心思想:边读边写
int b;
while((b = fis.read()) != -1){
fos.write(b);
}
//3、释放资源
//规则:先开的最后关闭
fos.close();
fis.close()
FileInputStream读取的问题
IO流:如果拷贝的文件过大,那么速度会不会有影响?
当然,会很慢
FileInputStream一次读写一个字节
弊端:一次读写一个字节,太慢了
File InputStream一次读取多个字节:
public int read()//一次读一个字节数据
public int read(byte[] buffer)//一次读一个字节数组数据
注意:一次读一个字节数组的数据,每次读取会尽可能把数组装满
数组的长度一般都是1024的整数倍
//1、创建对象
FileInputStreamfis = new FileInputStream("巴拉巴拉路径");
//2、读取数据
byte[] bytes = new byte[2];
//一次读取多个字节数据,具体读多少,跟数组的长度有关
//返回值:本次读取到了多少个字节数据
int len = fis.read(bytes);
System.out.println(len);//2
String n str = new String(bytes);
System.out.println(str);
//3、释放资源
fis.close();