应用背景:
许多App 有UGC评价系统。对于用户量比较多的评价系统我们所需要的是 保证系统的稳定性以及高并发。
实战学习积累:
1、理论学习 异常 断言 日志 调试
当用户在运行程序期间由于输入错误造成程序崩溃,Java会使用一种异常处理错误捕获机制来处理。所以首先,介绍Java的异常处理。在测试期间又会有大量的检测操作来验证程序的正确性,如果总是测试时放入,测试完删掉的话就会很乏味。那么我们需要使用断言来有选择性的启动检测。最后,当程序出现错误的时候并不是我们总是能够时时刻刻的和用户或者前端进项沟通。因此我们需要的是记录下出现的问题,以便后续进行分析。
一、异常处理
(1)处理错误
错误可能:文件包含了错误信息;网络连接出现问题;使用了无效的数组下标;试图使用一个没有被赋值的对象引用
稳定性较好的程序要求:返回一种安全的状态并能够让用户执行一些其他的命令;允许用户保存所有操作结果,并以适当的方式终止程序。
异常处理的任务:将控制权从错误产生的地方转移给能够处理这种情况的错误处理器。
为了能够在程序中处理异常情况,必须研究程序中可能会出现的错误和问题,以及哪类为题需要关注。
1、用户输入错误:比如用户请求连接一个URL但语法不正确。程序代码中要对它进行一个检查,如果没有检查的话网络层就会报错。
2、设备错误:例如打印机打印过程中没有纸了。
3、物理限制:磁盘空间满了。
4、方法可能返回了一个错误答案或错误的调用了其他方法。
如何处理:如果某个方法不能够采用正常的途径完成它的任务,就可以通过另外一个途径退出方法。这种情况下方法不返回任何值,而是抛出(throw)一个封装了错误信息的对象。这个方法将会立刻退出不会返回任何值,即调用了这个方法那么代码就不会将无法继续进行,但,与此同时,异常处理机制开始搜索能够处理这种异常状况的异常处理器。
(2)异常分类
查看Java的API文档即可!
(3)声明已检查的异常
why:一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误。
然而,在自己编写方法的时候不是所有可能抛出的异常都要进行声明,但是遇到下面四种情况的话就一定要抛出来:
1、调用一个抛出已检查异常的方法,例如,FiledInputStream构造器
2、程序运行过程中发现错误,并且利用throw 语句抛出一个已检查异常
3、程序出现错误,例如数组越界这些
4、Java虚拟机和运行时库出现的内部错误
【如果出现两种情况之一,则必须告诉调用这个方法的程序员有可能抛出异常。因为任何一个有可能抛出异常的方法都可能是个死亡陷阱。如果没有处理器去捕获这个异常,当前执行的线程就会结束。】
how:
do:
(4)捕获异常
程序写法:
try
{
code
more code
more code
}
catch(Exception e)
{
handle for this type
}
程序内部执行解析:
如果我们想看看这个异常的信息:
catch(Exception e)
{
System.out.println(e.getMessage()); //输出错误的原因
System.out.println(e.toString()); //异常名称:异常出现的位置
e.printStackTrace(); //异常名称,异常信息,异常出现的位置。
//其实jvm默认的异常处理机制,就是在调用printStackTrace方法
//打印异常的堆栈的跟踪信息
}
多异常的处理:
1、首先在声明的时候最好声明更为具体的异常,这样在处理起来就更具体一些。例如:
try
{
code that might throw exceptions
}
catch(FileNotFoundException e)
{
emergency action for missing files
}
catch(UnknownHostException e)
{
emergency action for unknown hosts
}
catch(IOException e)
{
emergency action for all other I/O problems
}
2、对方声明几个异常,就对应有几个cache块。 如果多个catch 块中的异常出现继承关系,父类异常catch块放在最下面。(注意:一定是放在最下面!!!对方声明几个异常就对应几个catch块,千万不要定义多余的catch块)
try
{
code that might throw exceptions
}
catch(FileNotFoundException e)
{
emergency action for missing files
}
catch(UnknownHostException e)
{
emergency action for unknown hosts
}
catch(Exception e)
{
emergency action for maybe appear problems
}
finally子句的使用:
1、正常情况下:
不管是否有异常被捕获,finally子句中的代码都会被执行。所以当我们认为需要关闭资源的时候finally子句是一种不错的选择。
这里展示一种示例:
InputStream in = ...;
try
{
try
{
code might throw exceptions
}
finally
{
in.close();
}
}
catch(IOException e)
{
show error massage
}
//内层的try语句块只有一个职责,就是确保关闭输入流。
//外层的try语句块也只有一个职责,就是确保报告出现的错误。
//这种设计方式不仅清楚,而且还具有一个功能就是将会报告finally子句中出现的错误。
2、遇见return的情况下:
当finally子句中包含return语句时,将会出现一种意想不到的结果。假设利用return语句从try 语句块中退出。在方法返回前,fina子句中的内容将被执行。如果finally子句中也有一个return语句,那么这个返回值将会覆盖原始的返回值。
throw 和 throws的区别:
(一)
throws使用在函数上。
throw使用在函数内。
(二)
throws后面跟的异常类,可跟多个,用逗号隔开。
throw后面跟的是异常对象。
特别说明下:带资源的try 语句(try-with-resources)的最简形形式为:
try(Resource res = ...)
{
work with res
}
try块退出时,会自动调用res.close() 。