作业10-异常
1.本周学习总结
1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容。
1.捕捉异常
Java中的异常捕获结构由try
、catch
和finally
三个部分组成。其中try
语句用于存放可能发生异常的语句,catch
语句用于激发被捕获的异常,finally
语句是异常结构最后处理的部分,无论有无异常发生,都会被执行,一般用于关闭资源。
但是在Java7中可以使用try-catch-resources
用来自动尝试关闭资源。
另外,finally语句块在下面四种特殊情况下不会被执行:
- 在finally语句块中发生了异常
- 在finally语句块之前使用
System.exit()
退出程序。 - 程序所在的线程死亡
- 关闭CPU
2.Java常见异常
异常类 | 说明 |
---|---|
ClassCastExctption | 类型转换异常 |
ClassNotFoundExctption | 未找到相应类异常 |
ArithmeticExctption | 算数异常 |
ArrayIndexOutOfBoundsExctption | 数组下标越界异常 |
ArrayStoreExctption | 数组中包含不兼容的值抛出的异常 |
SQLExctption | 操作数据库异常 |
NullPointerExctption | 空指针异常 |
NoSuchFieldExctption | 字段未找到异常 |
NoSuchMethodExctption | 方法未找到抛出的异常 |
NumberFormatExctption | 字符串转换为数字抛出的异常 |
NegativeArraySizeExctption | 数组元素个数为负数抛出的异常 |
StringIndexOutOfBoundsExctption | 字符串索引超出范围抛出的异常 |
IOExctption | 输入输出异常 |
IllegalAccessExctption | 不允许访问某类异常 |
InstantiationExctption | 当应用程序试图使用Class类中的newInstance()方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该异常 |
EOFExctption | 文件已结束异常 |
FileNotFoundExctption | 文件未找到异常 |
顺便分享一个偶然看到的很有趣的对各种异常的解释链接
3.自定义异常
使用Java异常类可以描述在编程时出现的大部分异常的情况,我们只需要继承异常类就可以进行自定义异常的操作。
自定义异常的步骤:
- 创建自定义异常
- 在方法中通过throw关键字抛出异常对象
- 如果在当前抛出异常的方法中处理异常,可以使用
try-catch
语句块捕获并处理,否则在方法的声明处通过throws
关键字指明要抛出给方法调用者的异常 - 在出现异常方法的调用者中捕获并处理异常
4.Java异常类的结构
Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常, 这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。
2.书面作业
本次PTA作业题集异常
1. 常用异常
结合题集题目7-1回答
1.1 自己以前编写的代码中经常出现什么异常、需要捕获吗(为什么)?应如何避免?
答:之前编写的代码经常出现NullPointerException
(空指针异常)和ArrayIndexOutOfBoundsException
(数组下标越界异常)。
通过查询JDK文档:
可以看出这两个异常都继承自RuntimeException
(运行时异常),都属于Unchecked Exception
,因此无需进行捕获,系统会对其进行检测。
对于空指针异常,可以在使用对象时判断对象是否为空,而下标越界异常则是要判断下标是否在数组长度的范围内,总之Unchecked Exception
这类的异常就是要通过我们自己检查代码行进行代码的修改来避免异常。
1.2 什么样的异常要求用户一定要使用捕获处理?
答:在Throwable
下面有三个类:Error
、Exception
、RuntimeExcepyion
,其中Error
、RuntimeExcepyion
及其子类的的异常都属于Unchecked Exception
,不用进行捕获处理,而Exception
类中的其他异常都属于checked Exception
,需要使用try-catch
进行捕获或是使用throw
关键字进行抛出。
2. 处理异常使你的程序更加健壮
题集题目7-2
2.1 实验总结。并回答:怎么样才能让你的程序更加健壮?
这题只要在进行字符串转换为数字时进行'try-catch'的处理,如果出现异常除了要输出外还要记得将下标减1。
对程序进行异常处理可以有效的提高程序的健壮性,就像在这一题中,如果不进行相应的异常处理,那当程序中出现非整形数据时就会出错,程序就会停止运行,但是当我们加上异常处理后,程序就可以正常运行并告知我们错误信息。但是也要记住,不是所有的地方都要进行异常处理,我们要忽略掉一些可以忽略的异常,因为过多的异常处理在程序运行的时候还有可能会影响到程序的性能。
3. throw与throws
题集题目7-3
阅读Integer.parsetInt
源代码
3.1 Integer.parsetInt
一开始就有大量的抛出异常的代码,这种做法有什么好处?
答:源代码太长,就不贴出来了,通过源代码可以看出, Integer.parsetInt
虽然只有一种异常,即NumberFormatException
,但是在一开始,它就考虑了多种能够产生该异常的情况进行异常的抛出,这样可以在传入的数据的时候就进行判断,看是否符合条件,这样可以避免传入错误的参数而导致程序崩溃的情况,让程序更加健壮。
3.2 结合自己编写的程序与3.1,分析自己编写的方法抛出异常时一般需要传递给调用者一些什么信息?
答:本题的代码中,产生的异常只有IllegalArgumentException
但是根据不同的输入数据,其产生该异常的原因也不同,因此在自己编写方法时就要告诉调用者产生异常的具体原因,像begin>end或是begin和end范围错误的关系。同样的,在Integer.parsetInt
中也是如此,它也是只有NumberFormatException
一种异常,但是可能是由空值等原因产生的。因此在编写代码时我们要告诉调用者的不仅仅是产生了什么异常,还要准确的告诉调用者产生异常的具体原因。
4. 用异常改进ArrayIntegerStack
题集题目6-3
4.1 结合6-3代码,回答使用抛出异常的方式代表程序运行时出错有什么好处?比单纯的返回错误值,有何优点?
答:当程序运行时出错时,这时的程序已经是产生了让程序无法自己执行下去的错误,只能靠系统干预来强行终止程序,也就是程序崩溃的情况。但是如果我们使用抛出异常的方法来代替程序的运行时出错,虽然二者都能告诉我们错误信息,但是后者中程序不会崩溃,就算是程序不去处理异常而导致程序的退出,也只是依靠程序的自身流程,属于正常情况。而且,我们还可以通过对异常进行处理来使程序能够继续执行下去。就像本题中,我们可以通过异常处理来使得程序接收到非法参数时不会立即崩溃,而且可以正常的执行下去,使这个程序变得更加健壮。
对于异常和返回错误本身的区别,那就是>异常是强类型的,类型安全的分支处理技术;而返回错误是其弱化的,不安全的版本。
相比于单纯返回错误值,使用异常机制来处理有如下几个优点
- 异常能够携带的信息量比返回值多,如果想要知道详细的信息,使用异常更加方便。
- 对于一些没有返回值的方法,想要第一时间得到异常信息,只能使用异常。
- 异常必须被处理,否则程序会退出,而使用返回值,不去处理也不会发生什么,但这并不是我们所想要的。
- 异常机制使用的是一个独立的传播途径,不需要占用我们的返回值,这样我们就不必去专门设置特定的返回值来指示错误信息。
4.2 如果一个方法内部的内码抛出的是RuntimeException类型的异常,那么方法声明是否应该使用throws
关键字,如果使用throws
关键字声明该方法抛出的异常,能给我们带来什么好处吗?
答:RuntimeException
类型的异常属于Unchecked Exception
,在程序运行中系统会自动进行检测,例如前面提到的空指针异常以及数组下标越界异常等,不需要使用throws
关键字来声明。
如果用throw
关键字来声明RuntimeException
类型的异常,虽然系统可以编译通过,但是只能说这种方法有点画蛇添足了。对于一般的运行时异常,我们一般都是对其进行排错处理,将错误代码改正过来,而不是去报告错误信息。再者,如果所有的运行时异常都要用try-catch
来处理,那我们的程序的性能反而会下降,因此最好不要用throw
关键字来声明RuntimeException
类型的异常。
5. 函数题-多种异常的捕获
题集题目6-1
5.1 结合6-1代码,回答:一个try块中如果可能抛出多种异常,且异常之间可能有继承关系,捕获时需要注意些什么?
答:对于存在继承关系的异常,要注意要让子类的异常在父类异常的前面,否则子类的异常就不会被捕获到,这是无意义的,当然,编译器也不允许我们这么写。
5.2 一个try块中如果可能抛出多种异常,使用Java8的多重异常捕获语法需要注意些什么?
答:Java8中的多重异常捕获可以使我们在一个catch语句中捕获多个异常,如下:
try{
//一段代码
}
catch(IOException | SQLException | Exception ex){
throw new MyException(ex.getMessage());
}
可以看出,不同的异常之间使用”|”来分隔,当然,这种多重异常捕获的方法也同样要注意异常之间的继承关系,子类的异常一定要在父类异常的左边,否则编译器也会报错。
6. 为如下代码加上异常处理
byte[] content = null;
FileInputStream fis = new FileInputStream("testfis.txt");
int bytesAvailabe = fis.available();//获得该文件可用的字节数
if(bytesAvailabe>0){
content = new byte[bytesAvailabe];//创建可容纳文件大小的数组
fis.read(content);//将文件内容读入数组
}
System.out.println(Arrays.toString(content));//打印数组内容
6.1 改正代码,并增加如下功能。当找不到文件时,需提示用户找不到文件xxx,请重新输入文件名,然后尝试重新打开。 如果是其他异常则提示打开或读取文件失败!
答:改正后的代码如下:
public class Test2 {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
String file;
int flag=1;
byte[] content = null;
FileInputStream fis = null;
while(flag==1){
try {
file = sc.next();
fis = new FileInputStream(file);
flag=0;
int bytesAvailabe = fis.available();// 获得该文件可用的字节数
if (bytesAvailabe > 0) {
content = new byte[bytesAvailabe];// 创建可容纳文件大小的数组
fis.read(content);// 将文件内容读入数组
}
System.out.println(Arrays.toString(content));// 打印数组内容
}catch(FileNotFoundException e){
System.out.println("找不到文件,请重新输入文件名");
file = sc.next();
}
catch (IOException e) {
System.out.println("打开或读取文件失败");
} finally{
try {
fis.close();
System.out.println("关闭文件ing");
} catch (Exception e) {
System.out.println("关闭文件失败");
}
}
}
}
}
6.2 结合题集6-2代码,要将什么样操作放在finally块?为什么?使用finally关闭资源需要注意一些什么?
答:无论是否抛出异常,finally
语句块总是会被执行,因此finally
语句块一般用来释放资源,进行在使用finally关闭资源的时候,要注意close
也可能会产生空指针异常,因此也要对其进行try-catch
处理。
6.3 使用Java7中的try-with-resources来改写上述代码实现自动关闭资源。简述这种方法有何好处?
使用try-with-resources
改写代码:
public static void main(String[] args) throws IOException {
byte[] content = null;
try (FileInputStream fis = new FileInputStream("testfis.txt");){
int bytesAvailabe = fis.available();// 获得该文件可用的字节数
if (bytesAvailabe > 0) {
content = new byte[bytesAvailabe];// 创建可容纳文件大小的数组
fis.read(content);// 将文件内容读入数组
}
System.out.println(Arrays.toString(content));// 打印数组内容
} catch(FileNotFoundException e){
System.out.println("找不到文件,请重新输入文件名");
}
catch (IOException e) {
System.out.println("打开或读取文件失败");
}
}
}
}
使用这种方法来改写代码只要将需要关闭的资源放进try语句的圆括号里即可,它可以在最后自动帮我们关闭我们所打开的资源,我们就不需要再去另写一个finally来关闭这个资源。
7. 面向对象设计作业(分组完成,每组不超过3个同学)
登录lib.jmu.edu.cn,对图书进行搜索。然后登录图书馆信息系统,查看我的图书馆。如果让你实现一个图书借阅系统,尝试使用面向对象建模。
7.1 该系统的使用者有谁?
答:使用者有借书的用户(程序中以学生来代替)和管理员。
7.2 主要功能模块(不要太多)
用户:
- 用户注册
- 用户登录
- 查看图书
- 借阅图书
- 归还图书
管理员:
- 添加图书
- 删除图书
- 查看图书
7.3 该系统的主要的类设计及类图(可用)
7.4 你准备如何存储图书信息、解决信息、读者信息等
答:存储图书信息使用Map键值对,key值存放图书,value值存放数量。
借阅信息也使用Map键值对存储
读者信息使用Set集合存储
9. 选做:使用静态代码扫描工具 扫描自己的购物车代码
9.1 分析自己代码中在规范方面出现的问题。
截图了部分扫描中出现的问题,发现自己在代码规范中主要还是起名的问题,之前也比较不会注意这方面,类名包名方法名之类的不会去在意大小写的问题。然后对于if还有for语句没有大括号的原因主要还是因为平时写的代码的行数都不多,因此用不用大括号感觉都不会有什么影响,可能在比较大的程序里会有一定的影响吧。
9.2 思考如何解决这些问题。
答:对类或者方法、成员变量起名的时候还是要注意名字的合法性和准确性。不能像以前一样为了方便随便用一个字母变量来代替
3.码云及PTA
题目集:异常
3.1. 码云代码提交记录
- 在码云的项目中,依次选择“统计-Commits历史-设置时间段”, 然后搜索并截图
3.2 截图PTA题集完成情况图
需要有两张图(1. 排名图。2.PTA提交列表图)
3.3 统计本周完成的代码量
需要将每周的代码统计情况融合到一张表中。
周次 | 总代码量 | 新增代码量 | 总文件数 | 新增文件数 |
---|---|---|---|---|
2 | 607 | 607 | 15 | 15 |
3 | 1642 | 1035 | 33 | 18 |
5 | 2044 | 402 | 42 | 9 |
6 | 2874 | 830 | 57 | 15 |
7 | 3161 | 287 | 63 | 6 |
8 | 4299 | 1138 | 72 | 9 |
9 | 4831 | 532 | 81 | 9 |
10 | 5475 | 644 | 93 | 12 |
11 | 5958 | 483 | 102 | 9 |