异常
- 在程序中如果有异常,jvm会在出现异常的地方New一个异常对象,并抛出
- 异常在Java中以类的形式存在,每一个异常类都可以创建异常对象
- 体系类图
Exception分为运行时异常和编译时异常,编译时异常,如果在编写代码时不进行异常出来,则会编译报错
比如:
/**
* 报错原因是dosome()抛出的是编译时异常,所以要进行异常处理
*/
public class Mytest01 {
public static void main(String[] args) {
try {
dosome();
} catch (GSSException e) {
e.printStackTrace();
}
}
public static void dosome() throws GSSException {
System.out.println("fjsdlj");
}
}
-
只要异常没有捕捉,就一直往上抛,后续代码不会执行
-
捕捉异常之后,后续代码可以执行
-
catch可以写多个,括号内的异常类型必须是从小到大的顺序
1、jdk7新特性
catch块里面可以采用“|”或运算符(只有当异常类型不存在子类关系时2才需要这个特性)
2、在实际开发中,如何选择是throws还是catch捕获处理
- 如果需要让调用者来处理,则选择throws,否则catch自己处理。
3、如何查看 异常的追踪信息,快速调试程序
- 异常追踪信息,从上往下一行行的看,SUN公司的代码不用看(看包名),主要看自己编写的代码上的第一行。
4、Throwable类常用方法:
- public string getMessage():返回异常发生时的简要描述
- public string toString():返回异常发生时的详细信息
- public string getLocalizedMessage():返回异常对象的本地化信息。使用 Throwable 的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与 getMessage()返回的结果相同
- public void printStackTrace():在控制台上打印 Throwable 对象封装的异常信息 ,后台打印异常堆栈追踪信息的时候,采用异步线程的方式
5、以下四种 情况finally不会执行。
- finally语句块第一行发生了异常。
- 在前面的代码中用了System.exit(int已退出程序。 exit 是带参函数 ;若该语句在异常语句之后,finally 会执行
- 程序所在线程死亡
- 关闭CPU
6、注意: 当 try 语句和 finally 语句中都有 return 语句时,在方法返回之前,finally 语句的内容将被执行,并且 finally 语句的返回值将会覆盖原始的返回值。如下:
public static int f(int value) {
try {
return value * value;
} finally {
if (value == 2) {
return 0;
}
}
}
如果调用 f(2),返回值将是 0,因为 finally 语句的返回值覆盖了 try 语句块的返回值。
自定义异常
1、编写一个类继承Exception或者RuntimeException
2、提供两个构造方法,一个无参,一个带有String参数的
比如:
public class MyException extends Exception{
public MyException() {
}
public MyException(String message) {
super(message);
}
}
public class MyException2 extends RuntimeException{
public MyException2(String message) {
super(message);
}
public MyException2() {
}
}
测试类:
public class Test03 {
public static void main(String[] args) {
MyException e = new MyException("自定义异常");
e.printStackTrace();
System.out.println(e.getMessage());
MyException2 e2 = new MyException2("自定义运行时异常");
e2.printStackTrace();
System.out.println(e2.getMessage());
}
}
输出结果:
com.feng.exception.MyException: 自定义异常
at com.feng.exception.Test03.main(Test03.java:5)
com.feng.exception.MyException2: 自定义运行时异常
at com.feng.exception.Test03.main(Test03.java:9)
自定义异常
自定义运行时异常
使用异常技巧
1、异常处理不能代替简单的测试
- 只在异常情况下使用异常
2、不要过分的细化异常
3、充分利用异常层次结构
- 不要只抛出RuntimeException。应该寻找一个适合的子类或创建自己的异常类
- 不要只捕获Throwable,否则,会使代码更难读,难维护
- 检查项异常:不要为逻辑错误抛出这些异常
- 如果一种异常可以转换成另外一个更加合适的异常,那么不要犹豫
4、不要压制异常
- 不要忽略异常,如果每个异常都非常重要,就应该适当的进行处理
- 在检查错误的时候,“苛刻”,要比放任更好
- 不要羞于传递异常:更高层的方法通常可以更好地通知用户发生了错误,或者放弃不成功的命令。
异常与方法覆盖
1、重写之后的方法不能比重写之前的方法更多(更宽泛)的异常。
异常处理总结:
- try:用于捕获异常,后面可以接零个或多个catch块,如果没有Catch块,必须要有一个Finally块
- Catch块:用于处理捕获的异常
- Finally:无论是否有异常或处理异常,都会执行。如果try块和catch块遇到return语句时,finally在返回之前被执行。
- Finally可以用于释放资源,不要把改变控制流的语句(return,throw,break,continue)放在finally中
- throws:在方法声明位置上使用,表示上报异常信息给调用者
- throw:手动抛异常
作业
自定义异常类:
public class RegisterException extends Exception{
public RegisterException(String message) {
super(message);
}
public RegisterException() {
}
}
注册
public class UserService {
public void register(String username, String password) throws RegisterException {
//判断为空最好放在前面,因为||运算一个为真后面就会判断了,判断为空最好null放在前面: null = username
if (null == username || username.length() < 6 || username.length() > 14) {
throw new RegisterException("用户名要求长度在6-14之间");
}
System.out.println("注册成功!欢迎:" + username);
}
}
测试
public class MyRegister {
public static void main(String[] args) {
UserService userService = new UserService();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String name = scanner.nextLine();
System.out.println("请输入密码:");
String pwd = scanner.nextLine();
try {
userService.register(name,pwd);
} catch (RegisterException e) {
e.printStackTrace();
}
}
}
结果: