异常:
程序中一些程序处理不了的特殊情况
异常类 Exception 继承自 Throwable 类(可抛出的)
Error:错误/事故,Java程序无法处理,如 OOM内存溢出错误、内存泄漏...会导出程序崩溃
常见的异常:
NullPointerException 空指针异常
ArrayIndexOutOfBoundException 数组下标越界异常
StringIndexOutOfBoundsException 字符串下标越界
ArithmeticException: / by zero 数学运算异常:除数为0
...
异常的种类:
1.检查性异常(编译异常):在编译时就会抛出的异常(代码上会报错)
需要在代码中编写处理方式,直接继承自 Exception
常出现在和程序之外的资源进行访问,如 FileNotFoundException 异常,文件找不到
2.运行时异常:在代码运行阶段可能会出现的异常
可以没有明文处理,可以通过代码避免异常的发生,继承自 RunTimeException
编写代码规避异常:
String str = null;
String name = "张三";
boolean bool = name.equals(str);//确定的值放在前面比较
System.out.println(bool);
if(str!=null){
System.out.println(str.length());
}else {
System.out.println("str是null值");
}
int i=12;
int a=0;
if(a!=0){
System.out.println(i/a);
}else {
System.out.println(a);
}
处理异常 try...catch...finally
try:尝试捕捉异常,其中是可能抛出异常的代码块
catch:捕获到的异常类型以及后续要进行处理的代码
finally:无论是否出现异常都会执行的代码块,常用于关闭资源,如关闭流、连接、线程池...
//以处理文件为例
File file = new File("D:\\easy.text");
FileInputStream fis = null;//声明在外,提升作用域
//检查性异常(编译异常)
try{
//try尝试捕捉异常,其中是可能抛出异常的代码
fis = new FileInputStream(file);
//中间代码如果有异常抛出被catch捕捉,后续代码没有机会执行
}catch (FileNotFoundException e){
//捕捉到异常后要处理的代码
e.printStackTrace();//打印异常日志
}finally {
//无论是否出现异常都会执行的代码块
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
当try的代码块中可能抛出多个异常需要处理时:
1.用多个catch块依次捕获异常(catch异常捕捉的顺序:子类异常优先处理,父类异常后置处理)
try{
List list = new ArrayList();//IndexOutOfBoundsException
list.remove(8);
int[] arr = new int[2];//ArrayIndexOutOfBoundsException
arr[8] = 22;
String strA = "abc";//StringIndexOutOfBoundsException
strA.charAt(8);
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}catch (StringIndexOutOfBoundsException e){
e.printStackTrace();
}catch (IndexOutOfBoundsException e){
e.printStackTrace();
}
2.合并处理方案,用一个catch块捕捉多种异常:使用 | 声明多种异常
//合并处理方案,一个catch块捕捉多种异常
try{
System.out.println(12/0);
Object strA = "";
System.out.println((Integer)strA);
fis = new FileInputStream(file);
}catch (ArithmeticException|ClassCastException|FileNotFoundException e){
System.out.println("出现异常");
}
3.通过声明父类异常来捕捉所有子类异常
//通过声明父类异常来捕捉所有子类异常
try{
System.out.println(12/0);
Object strA = "";
System.out.println((Integer)strA);
fis = new FileInputStream(file);
}catch(Exception e){
e.printStackTrace();
}
注意:如果在catch块中抛出异常,后面没有finally就会中断程序;
如果有finally,finally会运行,并且正常返回,此方法会正常运行结束。
public static int test(){
try{
System.out.println(12/0);
return 1;
}catch (Exception e){
//throw new Exception();
return 2;//执行,暂存2
}finally {
return 3;//运行,最后返回3,参考出栈将2覆盖,返回最后执行的return
//如果方法没有正常结束,不会有返回值
}
}
try不能单独编写,后面必须有其他语句块(catch和finally之一)
检查性异常必须有catch明文处理,只有try和finally而没有catch时不能有检查性异常;
try块中没有检查性异常时,不能在catch块中随意捕捉检查性异常;
运行时异常在try中没有时也可以捕捉,可以捕捉Exception。
自定义异常:
检查性异常:直接继承Exception类
运行时异常:继承RunTimeException
异常声明
class StudentNameIsNullException extends Exception{
public StudentNameIsNullException(){}
public StudentNameIsNullException(String msg){
super(msg);//传入消息
}
}
在方法中声明并抛出异常:
throw 用于抛出一个具体的异常对象
throws 用于在方法上声明此方法要向上抛出哪种异常
public void introduce() throws StudentNameIsNullException,NullPointerException, IOException {
//name==null是一种特殊情况,不符合业务需求
if(name==null){
//检查性异常要在方法后抛出:告知此处出现一种特殊情况要注意
//具体抛出哪一种异常对象
throw new StudentNameIsNullException("Student name is null");
}
System.out.println("我的名字是"+name);
}
注意:抛出的异常在语法上可以扩展到父类,但是在具体业务中不应该扩展;
throw和throws没有处理异常,只是抛给上级调用者;
检查性异常要在方法后抛出,告知此处出现一种特殊情况需要处理;
运行时异常可以不用throws抛出。
class CollegeStudent extends Student{
@Override
public void introduce()throws StudentNameIsNullException{
//重写的方法抛出异常只能更少,更精确,范围更小,可以没有,不能扩大
}
}
方法重写时:子类对父类中继承过来的方法进行重新定义
约束:返回值类型、方法名、参数列表不能变;
访问权限只能更开放;
抛出的异常只能更少,更精确,可以没有,不能扩大。
文件处理
java中对文件处理使用 java.io包
常用方法:
1.声明一个文件类型,传入一个字符串作为地址
File f = new File("D:\\easy.txt");
2.是否存在该文件 exists()
boolean bool = f.exists();//是否存在
System.out.println(bool);
3.创建文件(或文件夹)createNewFile()
if (!bool){//如果文件不存在
try {
bool = f.createNewFile();
if(bool == true){
System.out.println("成功创建文件");
}
}catch (IOException e){
e.printStackTrace();
}
}
4.删除文件(或文件夹)delete()
删除文件夹时,这个文件夹必须是空文件夹
//删除文件夹时,这个文件夹必须是空的文件夹
//f = new File("D:\\123");
bool = f.delete();//删除
System.out.println("成功删除文件"+bool);
5.判断是否是文件 isFile()
bool = f.isFile();//是否是文件
System.out.println(bool);
6.判断是否是文件夹 isDirectory()
bool = f.isDirectory();//是否是文件夹
System.out.println(bool);
7.创建文件夹
mkdir() 前面的路径必须都存在才能创建文件夹
mkdirs() 只需要有盘,会把包括路径上不存在的文件夹都依次创建
//前面的路径必须都存在才能创建文件夹
f.mkdir();
//只需要有盘,会把路径上不存在的文件夹依次创建
f.mkdirs();
8.获取文件路径 getPath()
String str = f.getPath();//获取路径
System.out.println(str);
9.获取长度(二进制多少B)length()
//获取长度
long len = f.length();//返回long类型
System.out.println(len/1024/1024+"MB");
IO输入输出流
流:流动的是数据,是二进制
流的分类:
1.根据流动的方向不同:输入流和输出流
2.根据流动的介质(单位)不同:字符流和字节流
字符流只能读取文本文件如: .txt .xml .properties .html .csv等
字节流可以读取所有文件类型
3.根据功能(作用)不同:节点流、工具流、打印流、数据流、对象流
字节输入流 InputStream
//字节流输入流
public static void readFile(){
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\easy.txt");
byte[] arr=new byte[1024];
int lenth=0;
while ((lenth=fis.read(arr))!=-1){
//arr中就是读取的数据
String str = new String(arr,0,lenth);
System.out.print(str);
String.valueOf(arr);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if (fis!=null){
try{
fis.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
字符输入流 Reader
//字符输入流
public static void readFile(){
FileReader fr=null;
try{
fr = new FileReader("D:\\0723.txt");
char[] arr=new char[1024];
int lenth=0;
while ((lenth=fr.read(arr))!=-1){
String str = new String(arr,0,lenth);
System.out.print(str);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if(fr!=null){
try{
fr.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
字符缓冲流 BufferedReader
工具流,字节转换流:把几个字节转换成一个字符,把字节流转换成字符流
缓冲流,有一个默认容量8192的字符数组,对输入的数据进行缓存,方便读写操作。
//字符缓存流
public static void readFileBuffer(){
FileInputStream fis=null;
InputStreamReader isr = null;
BufferedReader br=null;
try{
fis = new FileInputStream("D:\\0723.txt");
isr = new InputStreamReader(fis);
br = new BufferedReader(isr);
String line;
while ((line = br.readLine())!=null){
System.out.println(line);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if(fis!=null){
try{
fis.close();
}catch (IOException e){
e.printStackTrace();
}
}
if(isr!=null){
try{
isr.close();
}catch (IOException e){
e.printStackTrace();
}
}
if(br!=null){
try{
br.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
字节输出流 OutputStream
默认会覆盖文件原本的内容,如果想在原内容上追加,需要传入第二个参数为true。
//字节输出流
public static void writeFile(){
String str = "老崔很水";
byte[] arr=str.getBytes();
FileOutputStream fos = null;
try{
//默认覆盖,如果像在原本内容上追加,传入第二个参数为true
fos = new FileOutputStream("D:\\easy.txt",true);
fos.write(arr);
}catch (IOException e){
e.printStackTrace();
}finally {
if(fos!=null){
try{
fos.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
对象输出流 ObjectOutputStream
序列化:将内存对象转换成序列(流)的过程;
进行序列化的对象必须是可序列化的,实现Serializable接口(标识接口,不需要实现方法)
//对象输出流
public static void writeObject(){
//将内存对象转换成序列(流)的过程叫做序列化
//这个对象必须是可序列化的Serializable,标识接口,不需要实现方法
Staff staff=new Staff();
staff.name="张三";
staff.sex="男";
staff.salary=3500;
//对象输出流
ObjectOutputStream oos = null;
FileOutputStream fos = null;
try{
fos=new FileOutputStream("D:\\easy.txt");
oos=new ObjectOutputStream(fos);
oos.writeObject(staff);
}catch (IOException e){
e.printStackTrace();
}finally {
try{
if(fos!=null){
fos.close();
}
}catch (IOException e){
e.printStackTrace();
}
try{
if(oos!=null){
oos.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
对象输入流 ObjectInputStream
反序列化:将对象序列读入程序,转换成对象的方式。反序列化会创建新的对象。
public static void readObject(){
//将对象序列读入程序,转换成对象的方式:反序列化
//反序列化会创建新的对象
FileInputStream fis = null;
ObjectInputStream ois = null;
try{
fis = new FileInputStream("D:\\easy.txt");
ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
System.out.println(obj);
}catch (Exception e){
e.printStackTrace();
}finally {
try{
if(fis!=null){
fis.close();
}
}catch (IOException e){
e.printStackTrace();
}
try{
if(ois!=null){
ois.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
创建对象的方式:1.new 2.克隆 3.反序列化 4.反射
字节流、字符流与缓冲流的区别与联系
字节流(Byte Streams)
用途:
- 用于读写原始字节数据,不关心数据的编码方式。
- 适用于处理所有类型的二进制数据,如图片、视频、音频文件等。
主要类:
InputStream
:字节输入流,用于从源读取字节数据。OutputStream
:字节输出流,用于向目标写入字节数据。
特点:
- 直接操作字节序列,不解析或修改数据内容。
- 适用于文件操作、网络通信等场景。
字符流(Character Streams)
用途:
- 专门用于读写字符数据,特别是文本数据。
- 涉及字符编码和解码,能够处理不同字符集之间的转换。
主要类:
Reader
:字符输入流,用于读取字符数据。Writer
:字符输出流,用于写入字符数据。
特点:
- 以字符为单位进行读写,方便处理文本数据。
- 自动处理不同平台的字符编码差异。
缓冲流(Buffered Streams)
用途:
- 作为字节流或字符流的包装器,通过内部缓冲区提高读写效率。
主要类:
- 字节缓冲流:
BufferedInputStream
、BufferedOutputStream
- 字符缓冲流:
BufferedReader
、BufferedWriter
特点:
- 减少实际的I/O操作次数,提高性能。
- 一次性读取或写入大块数据到内存中的缓冲区。
区别与联系
区别:
- 用途:字节流用于二进制数据,字符流用于文本数据,缓冲流用于提高读写效率。
- 编码:字节流不关心编码,字符流需要考虑字符编码。
- 性能:缓冲流通过减少I/O操作次数显著提高性能。
联系:
- 缓冲流可以包装在任何类型的字节流或字符流之上。
- 所有这些流类型的最终目标都是实现数据的输入和输出。
- 字节流和字符流是基础,缓冲流是优化手段,可以相互结合使用以达到最佳效果。