Java常用知识点汇总(中级:异常处理,输入输出流)
目录
异常处理
1.定义
2.常见的异常
3.如何处理
4.异常的分类
5.Throwable
6.自定义异常
输入输出流(I/O)
1.文件对象
2.什么是流
3.字节流
4.关闭流的方式
5.字符流
6.编码/中文问题
7.缓存流
8.数据流
9.对象流
10.System.in
11.流关系图
异常处理
1.定义
异常:导致程序的正常流程被中断的事件,叫做异常
比如要打开d盘的LOL.exe文件,这个文件是有可能不存在的
Java中通过 new FileInputStream(f) 试图打开某文件,就有可能抛出文件不存在异常FileNotFoundException
如果不处理该异常,就会有编译错误
2.常见的异常
NullPointerException 空指针异常
ArithmeticException 除数为零
ClassCastException 类型转换异常
OutOfIndexException 数组下标越界异常
ParseException 解析异常,日期字符串转换为日期对象的时候,有可能抛出的异常
OutOfMemoryError 内存不足
3.如何处理
异常处理常见手段: try catch finally throws
- try catch
1.将可能抛出FileNotFoundException 文件不存在异常的代码放在try里
2.如果文件存在,就会顺序往下执行,并且不执行catch块中的代码
3. 如果文件不存在,try 里的代码会立即终止,程序流程会运行到对应的catch块中
4. e.printStackTrace(); 会打印出方法的调用痕迹,如此例,会打印出异常开始于TestException的第16行,这样就便于定位和分析到底哪里出了异常
注:FileNotFoundException是Exception的子类,使用Exception也可以catch住FileNotFoundException
- 多异常捕捉方法1
有的时候一段代码会抛出多种异常,比如
new FileInputStream(f);
Date d = sdf.parse("2016-06-03");
这段代码,会抛出 文件不存在异常 FileNotFoundException 和 解析异常ParseException
解决办法之一是分别进行catch
- 多异常捕捉方法2
另一个种办法是把多个异常,放在一个catch里统一捕捉
catch (FileNotFoundException | ParseException e) {
这种方式从 JDK7开始支持,好处是捕捉的代码更紧凑,不足之处是,一旦发生异常,不能确定到底是哪种异常,需要通过instanceof 判断具体的异常类型
- finally
无论是否出现异常,finally中的代码都会被执行
- throws
考虑如下情况:
主方法调用method1,method1调用method2,method2中打开文件
method2中需要进行异常处理,但是method2不打算处理,而是把这个异常通过throws抛出去
那么method1就会接到该异常。 处理办法也是两种,要么是try catch处理掉,要么也是抛出去。
method1选择本地try catch住 一旦try catch住了,就相当于把这个异常消化掉了,主方法在调用method1的时候,就不需要进行异常处理了
- throw和throws的区别
throws与throw这两个关键字接近,不过意义不一样,有如下区别:
1. throws 出现在方法声明上,而throw通常都出现在方法体内。
2. throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw则是抛出了异常,执行throw则一定抛出了某个异常对象。
4.异常的分类
异常分类: 可查异常,运行时异常和错误3种
- 可查异常
可查异常: CheckedException
可查异常即必须进行处理的异常,要么try catch住,要么往外抛,谁调用,谁处理,比如 FileNotFoundException
如果不处理,编译器,就不让你通过
- 运行时异常
运行时异常RuntimeException指: 不是必须进行try catch的异常
常见运行时异常:
除数不能为0异常:ArithmeticException
下标越界异常:ArrayIndexOutOfBoundsException
空指针异常:NullPointerException
在编写代码的时候,依然可以使用try catch throws进行处理,与可查异常不同之处在于,即便不进行try catch,也不会有编译错误
Java之所以会设计运行时异常的原因之一,是因为下标越界,空指针这些运行时异常太过于普遍,如果都需要进行捕捉,代码的可读性就会变得很糟糕。
- 错误
错误Error,指的是系统级别的异常,通常是内存用光了
在默认设置下,一般java程序启动的时候,最大可以使用16m的内存
如例不停的给StringBuffer追加字符,很快就把内存使用光了。抛出OutOfMemoryError
与运行时异常一样,错误也是不要求强制捕捉的
5.Throwable
Throwable是类,Exception和Error都继承了该类
所以在捕捉的时候,也可以使用Throwable进行捕捉
如图: 异常分Error和Exception,Exception里又分运行时异常和可查异常。
6.自定义异常
- 创建自定义异常
一个英雄攻击另一个英雄的时候,如果发现另一个英雄已经挂了,就会抛出EnemyHeroIsDeadException
创建一个类EnemyHeroIsDeadException,并继承Exception
提供两个构造方法
1. 无参的构造方法
2. 带参的构造方法,并调用父类的对应的构造方法
- 抛出自定义异常
在Hero的attack方法中,当发现敌方英雄的血量为0的时候,抛出该异常
1. 创建一个EnemyHeroIsDeadException实例
2. 通过throw 抛出该异常
3. 当前方法通过 throws 抛出该异常
在外部调用attack方法的时候,就需要进行捕捉,并且捕捉的时候,可以通过e.getMessage() 获取当时出错的具体原因
输入输出流(I/O)
1.文件对象
文件和文件夹都是用File代表
- 创建一个文件对象
使用绝对路径或者相对路径创建File对象
- 文件常用方法1
注意1: 需要在D:\LOLFolder确实存在一个LOL.exe,才可以看到对应的文件长度、修改时间等信息
注意2: renameTo方法用于对物理文件名称进行修改,但是并不会修改File对象的name属性。
- 文件常用方法2
2.什么是流
什么是流(Stream),流就是一系列的数据
当不同的介质之间有数据交互的时候,JAVA就使用流来实现。
数据源可以是文件,还可以是数据库,网络甚至是其他的程序
比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流
输入流: InputStream
输出流:OutputStream
3.字节流
InputStream字节输入流
OutputStream字节输出流
用于以字节的形式读取和写入数据
- ASCII码
所有的数据存放在计算机中都是以数字的形式存放的。 所以字母就需要转换为数字才能够存放。
比如A就对应的数字65,a对应的数字97. 不同的字母和符号对应不同的数字,就是一张码表。
ASCII是这样的一种码表。 只包含简单的英文字母,符号,数字等等。 不包含中文,德文,俄语等复杂的。
- 以字节流的形式读取文件内容
InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取
- 以字节流的形式向文件写入数据
OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据
注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。
但是如果是文件 d:/xyz/lol2.txt,而目录xyz又不存在,会抛出异常
4.关闭流的方式
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。
- 在try中关闭
在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用
- 在finally中关闭
这是标准的关闭流的方式
1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
2. 在finally关闭之前,要先判断该引用是否为空
3. 关闭的时候,需要再一次进行try catch处理
这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患try的方式
- 使用try()的方式
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。
5.字符流
Reader字符输入流
Writer字符输出流
专门用于字符的形式读取和写入数据
- 使用字符流读取文件
FileReader 是Reader子类,以FileReader 为例进行文件读取
- 使用字符流把字符串写入到文件
FileWriter 是Writer的子类,以FileWriter 为例把字符串写入到文件
6.编码/中文问题
- 编码概念
计算机存放数据只能存放数字,所有的字符都会被转换为不同的数字。
就像一个棋盘一样,不同的字,处于不同的位置,而不同的位置,有不同的数字编号。
有的棋盘很小,只能放数字和英文
有的大一点,还能放中文
有的“足够”大,能够放下世界人民所使用的所有文字和符号
如图所示,英文字符 A 能够放在所有的棋盘里,而且位置都差不多
中文字符, 中文字符 中 能够放在后两种棋盘里,并且位置不一样,而且在小的那个棋盘里,就放不下中文
- 常见编码
经常接触的编码方式有如下几种:
ISO-8859-1 ASCII 数字和西欧字母
GBK GB2312 BIG5 中文
UNICODE (统一码,万国码)
其中
ISO-8859-1 包含 ASCII
GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文。
UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中
- UNICODE和UTF
如果完全按照UNICODE的方式来存储数据,就会有很大的浪费。
比如在ISO-8859-1中,a 字符对应的数字是0x61
而UNICODE中对应的数字是 0x00000061,倘若一篇文章大部分都是英文字母,那么按照UNICODE的方式进行数据保存就会消耗很多空间
在这种情况下,就出现了UNICODE的各种减肥子编码, 比如UTF-8对数字和字母就使用一个字节,而对汉字就使用3个字节,从而达到了减肥还能保证健康的效果
UTF-8,UTF-16和UTF-32 针对不同类型的数据有不同的减肥效果,一般说来UTF-8是比较常用的方式
- Java采用的是Unicode
写在.java源代码中的汉字,在执行之后,都会变成JVM中的字符。
而这些中文字符采用的编码方式,都是使用UNICODE. "中"字对应的UNICODE是4E2D,所以在内存中,实际保存的数据就是十六进制的0x4E2D, 也就是十进制的20013。
- 文件的编码方式-eclipse
eclipse的编码方式:右键任意文本文件,点击最下面的"property"
就可以看到Text file encoding
也有ISO-8859-1,GBK,UTF-8等等选项。
其他的US-ASCII,UTF-16,UTF-16BE,UTF-16LE不常用。
- 用FileInputStream 字节流正确读取中文
为了能够正确的读取中文内容
1. 必须了解文本是以哪种编码方式保存字符的
2. 使用字节流读取了文本后,再使用对应的编码方式去识别这些数字,得到正确的字符
如本例,一个文件中的内容是字符中,编码方式是GBK,那么读出来的数据一定是D6D0。
再使用GBK编码方式识别D6D0,就能正确的得到字符中
注: 在GBK的棋盘上找到的中字后,JVM会自动找到中在UNICODE这个棋盘上对应的数字,并且以UNICODE上的数字保存在内存中。
- 用FileReader 字符流正确读取中文
FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替,像这样:
new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"));
在本例中,用记事本另存为UTF-8格式,然后用UTF-8就能识别对应的中文了。
解释: 为什么中字前面有一个?
如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做BOM用来标志这个文件是用UTF-8来编码的。
7.缓存流
- 概念
以介质是硬盘为例,字节流和字符流的弊端: 在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。
为了解决以上弊端,采用缓存流。 缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。
就好比吃饭,不用缓存就是每吃一口都到锅里去铲。用缓存就是先把饭盛到碗里,碗里的吃完了,再到锅里去铲
缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作
- 使用缓存流读取数据
缓存字符输入流 BufferedReader 可以一次读取一行数据
- 使用缓存流写出数据
PrintWriter 缓存字符输出流, 可以一次写出一行数据
- flush
有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush
8.数据流
DataInputStream 数据输入流
DataOutputStream 数据输出流
- 直接进行字符串的读写
使用数据流的 writeUTF() 和 readUTF() 可以进行数据的格式化顺序读写
如本例,通过DataOutputStream 向文件 顺序写出 布尔值,整数和字符串。 然后再通过DataInputStream 顺序读入这些数据。
注: 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。
9.对象流
对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口
- 序列化一个对象
创建一个Hero对象,设置其名称为garen。
把该对象序列化到一个文件garen.lol。
然后再通过序列化把该文件转换为一个Hero对象
注:把一个对象序列化有一个前提是:这个对象的类,必须实现了Serializable接口
10.System.in
System.out 是常用的在控制台输出数据的
System.in 可以从控制台输入数据
- System.in
- Scanner读取整数和字符串
使用System.in.read虽然可以读取数据,但是很不方便
使用Scanner就可以逐行读取了
11.流关系图
Java常用知识点汇总(中级:异常处理,输入输出流)相关推荐
- Java常用知识点汇总(基础:数组,类与对象,接口与继承)
目录 数组 1.引用 2.增强型for循环 3.复制数组 arraycopy() 4.针对数组的工具类 Arrays 5.选择法排序 6.冒泡排序 7.练习-二维数组中的查找(剑指offer) 类与对 ...
- Java常用英语汇总
英语不好照样可以搞定Java编程-Java常用英语汇总 尚硅谷2016-11-11 14:48 题目:Java常用英语汇总(更新升级版) abstract (关键字) 抽象['.bstr.kt] ac ...
- JAVA常用单词汇总
Java 常用英语汇总 abstract (关键字) access 抽象 ['.bstr.kt] vt.访问,存取 ['.kses]'(n.入口,使用权) n.算法 ['.lg.riem] algor ...
- list python 访问 键值对_基础|Python常用知识点汇总(中)
字符串字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串.1.创建字符串 str1 = 'Hello World!' str2 = "Hello W ...
- Java常用命令汇总(笔记)
Java常用命令汇总 文章目录 Java常用命令汇总 1.javac 将文件编译成.class文件 2.java 执行 .class文件,若类中没有main函数,则不能执行. 3.jar 主要用于打包 ...
- Java常见知识点汇总
Java常见知识点汇总 基础概念与常识 1.Java 语言有哪些特点? 2.JVM vs JDK vs JRE 3.什么是字节码?采用字节码的好处是什么? 4.为什么不全部使用 AOT 呢? 5.为什 ...
- java基础知识大全,java 基础知识点汇总
java 基础知识点汇总 问题一:我声明了什么! String s = "Hello world!"; 许多人都做过这样的事情,但是,我们到底声明了什么?回答通常是:一个Strin ...
- JAVA中级二 输入输出流,常见文件操作
文章目录 输入输出流,常见文件操作 01 文件对象 1.1 创建一个文件对象 1.2 文件的常用方法1 1.3 文件的常用方法2 1.4 练习 02 什么是流 2.1 流的理解 2.2 文件输入流 2 ...
- 1.6 Java字节流的使用:字节输入/输出流、文件输入/输出流、字节数组输入/输出流
InputStream 是 Java 所有字节输入流类的父类, OutputStream 是 Java 所有字节输出流类的父类, 它们都是一个抽象类,因此继承它们的子类要重新定义父类中的抽象方法. 下 ...
最新文章
- openresty 前端开发序
- 62 Celery远程调用
- java基础包的基本信息_JAVA 基础 之 基本数据类型、引用类型和包...
- 如何在 ASP.Net Core 使用 分布式缓存
- 使用Spring MVC进行资源版本控制
- poi为什么所有celltype都是string_不是所有向日葵都向阳,你知道为什么吗
- 帮助中心 开源_如何不获得开源帮助
- java ee 第二周作业 web应用后台运行过程
- Arduino IDE和ArduBlock 的下载安装
- Maven - 安装 配置
- 【图像压缩】基于matlab GUI DCT图像无损压缩【含Matlab源码 726期】
- 家里的无线网最近总是网速不稳定,一阵一阵的卡,是怎么回事?
- 关于扫码点餐多人实时共享订单的思考
- 新代系统9服务器警报,新代系统数控铣加工中心。新代系统龙门加工中心故障与报警...
- PS实战操作之蒙版、路径
- 【小玩意】锟斤拷语加密器
- 如何调教ChatGpt 让它听话
- i.MX6ULL终结者电容触摸实验程序设计
- RDLC报表 报表数据(参数栏)不显示怎么办?
- iOS 苹果开发者账号--个人账号、公司账号、企业账号的区别