class Life{ public static void main(String[] args){ int alive; while(alive) { eat(); sleep(); code(); repeat(); } } }
老人说,这不丢脸,也无损真正的骄傲.
关于异常,你不知道的是?
什么是异常:非正常的,不同于平常的,异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行。异常处理是衡量一门语言是否成熟的标准之一,主流的语言Java,C++,C#等支持异常处理机制。异常处理机制可以让程序有更好的容错性,使我们的代码更健壮。C语言却没有异常,此时只能程序员通常使用方法的特定返回值来表示异常情况,并且使用if语句来判断正常和非正常情况。
如果没有异常处理机制?
- 使用方法的返回值来表示异常情况有限,无法穷举所有的异常情况.
- 异常流程代码和正常流程代码混合一起,增大了程序的复杂性,可读性也不好.
- 随着系统规模的不断扩大,程序的可维护性极低.
异常体系(java.lang.Throwable):Java语言中所有错误和异常的超类。
- Error:错误,一般情况下,不编写针对性的代码进行处理,通常是 jvm 发生的,
需要对程序进行修正。 - Exception:异常,可以有针对性的处理方式。
- 无论是错误还是异常,它们都有具体的子类体现每一个问题,它们的子类都有一个共性,就是都以父类名才作为子类的后缀名(NullPointerException),这个体系中的所有类和对象都具备一个独有的特点,就是可抛性。
捕获异常
使用try-catch捕获单个异常,try和catch都不能单独使用,必须连用。
try{ 编写可能会出现异常的代码 }catch(异常类型 e){ 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 }
使用try-catch捕获多个异常。
try{ 编写可能会出现异常的代码 }catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获. 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 }catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获. 处理异常的代码 //记录日志/打印异常信息/继续抛出异常 } /*注意: * 1:一个catch语句,只能捕获一种类型的异常,如果需要捕获多种异常,就得使用多个catch语句. * 2):代码在一瞬间只能出现一种类型的异常,只需要一个catch捕获,不可能同时出现多个异常. */
3.finally 代码块(常用于关闭资源,无论是否发生异常,资源都必须进行关闭)
//finally语句块表示最终都会执行的代码,无论有没有异常.
//finally也不能单独使用
//如果在try,catch中调用了退出JVM的相关方法便不再执行,程序都关闭了还执行什么
try {
System.out.println("begin...");
int ret = 10/0;
System.out.println("结果= "+ ret);
} catch (ArithmeticException e) {
System.out.println("出现异常情况");
// System.exit(0); //退出JVM
}finally{
System.out.println("关闭资源"); //如果有system.exit语句 ,则此处不执行
}
System.out.println("end...");
finally 的两种语法:
- try…finally: 此时没有catch来捕获异常,因为此时根据应用场景,我们会抛出异常,自己不处理。
- try…catch….finally:自身需要处理异常,最终还得关闭资源。
获取异常信息
- String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因)。
- String toString():获取异常的类型和异常描述信息。
- void printStackTrace():打印异常的跟踪栈信息并输出到控制台。不需要使System.out.println。
异常分类
编译时被检查的异常,只要是 Exception 及其子类都是编译时被检测的异常。
运行时异常,其中 Exception 有一个特殊的子类 RuntimeException,以及RuntimeException 的子类是运行异常,也就说这个异常是编译时不被检查的异常。
抛出异常
throw: 运用于方法内部,用于给调用者返回一个异常对象,和return一样会结束当前方法.
public class ThrowDemo { public static void main(String[] args) { System.out.println("------------"); try { int ret = divide(10,2); System.out.println(ret); } catch (ArithmeticException e) { System.out.println(e.getMessage()); } } private static int divide(int num1, int num2) { System.out.println("begin..."); if (num2 == 0) { // System.out.println("除数不能为0"); // return 1; throw new ArithmeticException("除数不能为0"); } System.out.println("==================");// 当num2 =0的时候,此处代码执行不到, // throw相当于return,返回的是一个错误结果 try { int ret = num1 / num2; System.out.println("结果 =" + ret); return ret; } catch (ArithmeticException e) { e.printStackTrace(); } System.out.println("end...."); return 0; } }
throws: 运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
public class ThrowsDemo { public static void main(String[] args) throws Exception { divide(10, 0); } //在本方法中不处理某种类型的异常 private static int divide(int num1, int num2) throws Exception { System.out.println("begin..."); if (num2 == 0) { throw new Exception("除数不能为0");//此处如果为RuntimeException就不会编译出错 } try { int ret = num1 / num2; System.out.println("结果 =" + ret); return ret; } catch (ArithmeticException e) { e.printStackTrace(); } System.out.println("end...."); return 0; } }
3.如果每一个方法都放弃处理异常都直接通过throws声明抛出,最后异常会抛到main方法,如果此时main方法不处理,继续抛出给JVM,底层的处理机制就是打印异常的跟踪栈信息.
自定义异常类
为什么需要自定义异常:Java中不同的异常类,分别表示着某一种具体的异常情况,那么在开发中总是有些异常情况是SUN没有定义好的,此时我们根据自己业务的异常情况来定义异常类.
自定义异常的步骤:
- 定义一个子类继承 Exception 或 RuntimeException,让该类具备可抛性(既可以使用 throw 和 throws 去调用此类)。
- 通过 throw 或者 throws 进行操作。
异常的转换思想:当出现的异常是调用者处理不了的,就需要将此异常转换为一个调用者可以处理的异常抛出。
class LogicException extends RuntimeException {
private static final long serialVersionUID = 1L;
public LogicException() {
super();
}
public LogicException(String message, Throwable cause) {
super(message, cause);
}
public LogicException(String message) {
super(message);
}
}
public class RegisterDemo {
// 假设数据库中已经存在的账号
public static void main(String[] args) {
try {
// 可能出现的异常代码
isExist("will");
System.out.println("注册成功");
} catch (Exception e) {
// 处理异常
System.out.println("用户:" + e.getMessage());// 对不起,用户名will已存在
}
}
// 判断当前注册的账号是否存在
private static boolean isExist(String username) {
String[] data = { "will", "lucy", "xiaoming" };
for (String name : data) {
if (name.equals(username)) {
throw new LogicException("该名字已经被注册"); // 返回错误的结果给catch(调用者)
}
}
return true;
}
}
处理异常的原则
- 异常只能用于非正常情况,try-catch的存在也会影响性能.
- 需要为异常提供说明文档,比如Java doc,如果自定义了异常或某一个方法抛出了异常,我们应该记录在文档注释中.
- 尽可能避免异常.
- 异常的粒度很重要,应该为一个基本操作定义一个 try-catch 块,不要为了简便,将几百行代码放到一个 try-catch 块中.
- 不建议在循环中进行异常处理,应该在循环外对异常进行捕获处理(在循环之外使用try-catch).
- 自定义异常尽量使用RuntimeException类型的.
Note中的Code是从学习笔记上Copy下来的,这些天被多线程玩得欲仙欲死。
CNcots CN Caprice of the stone的简写, 译为石头的随想曲.
博客中有网上摘抄的资料. 有个人的一些小心得 ,有什么不对的地方, 还请各位观客老爷们指出.
JavaNote系列博客, 纯属个人学习时间段整理的一些笔记, 会坚持每周至少一更,多多关照.