通过异常处理错误
异常情形:是指阻止当前方法或作用域继续执行的问题。
监控区域:一段可能产生异常的代码区域,即try区域。
异常处理程序:处理异常的地点,即catch区域。
异常处理的两种模型
终止模型:一旦抛出异常,将无法返回产生异常处。
恢复模型:在产生异常时不抛出异常,而是通过方法或者将try放到循环语句中以修补异常。
注意:恢复模型容易增强程序耦合性
自定义异常
import java.util.logging.Logger;
public class MyException {
private static void f() throws CustomException{
System.out.println("f:");
throw new CustomException();
}
private static void g(String msg)throws CustomException{
System.out.println("g:");
throw new CustomException(msg);
}
private static void h(){
int x,y,z;
x=4;
y=0;
try {
z=x/y;
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String... args) {
try {
f();
} catch (CustomException e) {
e.printStackTrace(System.out);
}
try {
g("msg");
} catch (CustomException e) {
e.printStackTrace(System.out);
}
h();
}
}
class CustomException extends Exception{
private Logger logger=Logger.getLogger("CustomException");
public CustomException(){
}
public CustomException(String msg){
super(msg);
}
@Override
public String getMessage() {
//return super.getMessage();
return "This is my custom error info";
}
}
当注释掉return super.getMessage():
f:
thinkinjava.CustomException: This is my custom error info
at thinkinjava.MyException.f(MyException.java:7)
at thinkinjava.MyException.main(MyException.java:26)
g:
thinkinjava.CustomException: This is my custom error info
at thinkinjava.MyException.g(MyException.java:11)
at thinkinjava.MyException.main(MyException.java:32)
h:
java.lang.ArithmeticException: / by zero
at thinkinjava.MyException.h(MyException.java:19)
at thinkinjava.MyException.main(MyException.java:36)
当注释掉return “This is my custom error info”:
f:
thinkinjava.CustomException
at thinkinjava.MyException.f(MyException.java:7)
at thinkinjava.MyException.main(MyException.java:26)
g:
thinkinjava.CustomException: msg
at thinkinjava.MyException.g(MyException.java:11)
at thinkinjava.MyException.main(MyException.java:32)
h:
java.lang.ArithmeticException: / by zero
at thinkinjava.MyException.h(MyException.java:19)
at thinkinjava.MyException.main(MyException.java:36)
getMessage类似于toString方法
异常与记录日志
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;
public class LoggerException {
private static Logger logger=Logger.getLogger("LoggerException");
private static void logprint(Exception e){
StringWriter sw=new StringWriter();
PrintWriter pw=new PrintWriter(sw);
e.printStackTrace(pw);
logger.severe(pw.toString());
}
public static void main(String...args){
try {
throw new NullPointerException();
} catch (NullPointerException e) {
logprint(e);
}
}
}
五月 01, 2018 9:31:36 下午 thinkinjava.LoggerException logprint
严重: java.io.PrintWriter@330bedb4
throw:抛错误给上一层处理
public class Thrower {
static void demoproc() {
try {
throw new NullPointerException("demo");
} catch(NullPointerException e) {
System.out.println("Caught inside demoproc.");
throw e;
}
}
public static void main(String args[]) {
try {
demoproc();
} catch(NullPointerException e) {
System.out.println("Recaught: " + e);
}
}
}
Caught inside demoproc.
Recaught: java.lang.NullPointerException: demo
栈轨迹
public class StackTracer {
private static void a(){
try{
throw new Exception();
}catch (Exception e){
for(StackTraceElement stackTraceElement:e.getStackTrace())
System.out.println(stackTraceElement.getMethodName());
}
}
private static void b(){
a();
}
private static void c(){
b();
}
public static void main(String...args){
a();
System.out.println("-------------");
b();
System.out.println("-------------");
c();
}
}
输出:
a
main
-------------
a
b
main
-------------
a
b
c
main
从栈底开始调用,类似于递归
若把当前异常重新抛出,printStackTrace()显示的仍然是原来异常抛出点的调用栈信息
private static void d() throws Exception{
throw new Exception("throw new Exception from d");
}
private static void e() throws Exception{
try{
d();
}catch (Exception e){
System.out.println("e try catch");
e.printStackTrace(System.out);
throw e;
}
}
private static void f() throws Exception{
try{
d();
}catch (Exception e){
System.out.println("f try catch");
e.printStackTrace(System.out);
throw (Exception) e.fillInStackTrace();
}
}
public static void main(String...args){
try {
e();
}catch (Exception e){
System.out.println("main try catch from e");
e.printStackTrace(System.out);
}
try {
f();
}catch (Exception e){
System.out.println("main try catch from f");
e.printStackTrace(System.out);
}
}
e try catch
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.d(StackTracer.java:19)
at thinkinjava.StackTracer.e(StackTracer.java:24)
at thinkinjava.StackTracer.main(StackTracer.java:44)
main try catch from e
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.d(StackTracer.java:19)
at thinkinjava.StackTracer.e(StackTracer.java:24)
at thinkinjava.StackTracer.main(StackTracer.java:44)
f try catch
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.d(StackTracer.java:19)
at thinkinjava.StackTracer.f(StackTracer.java:34)
at thinkinjava.StackTracer.main(StackTracer.java:51)
*main try catch from f
java.lang.Exception: throw new Exception from d
at thinkinjava.StackTracer.f(StackTracer.java:38)
at thinkinjava.StackTracer.main(StackTracer.java:51)
如最后一个输出结果,其已经不再输出原来的那个抛出点了d了
若抛出的是两个不同的自定义异常,那么就无法关联,即第二次抛出点打印出的栈轨迹不会有第一次的任何信息,这是如果我们也要打印第一次抛出点的栈轨迹,则需要用到异常链:
public class ExceptionLink {
class MyException2 extends Exception{
public MyException2(Throwable throwable){
super(throwable);
}
public MyException2(){
super();
}
}
class MyException1 extends Exception{
public MyException1(){
super();
}
}
private void a() throws MyException1{
throw new MyException1();
}
private void b() throws MyException2{
try {
a();
}catch (MyException1 exception1){
System.out.println("b try catch");
exception1.printStackTrace(System.out);
throw new MyException2();
//throw new MyException2(exception1);
}
}
public static void main(String...args){
ExceptionLink exceptionLink=new ExceptionLink();
try {
exceptionLink.b();
} catch (MyException2 myException2) {
System.out.println("main try catch");
myException2.printStackTrace(System.out);
}
}
}
输出:
b try catch
thinkinjava.ExceptionLink$MyException1
at thinkinjava.ExceptionLink.a(ExceptionLink.java:18)
at thinkinjava.ExceptionLink.b(ExceptionLink.java:22)
at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)
main try catch
thinkinjava.ExceptionLink$MyException2
at thinkinjava.ExceptionLink.b(ExceptionLink.java:26)
at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)
如上在第二个抛出点并没有抛出第一个抛出点所抛出的信息,因为这是两个不同异常类
若将注释掉的那行取消掉注释则会输出:
b try catch
thinkinjava.ExceptionLink$MyException1
at thinkinjava.ExceptionLink.a(ExceptionLink.java:18)
at thinkinjava.ExceptionLink.b(ExceptionLink.java:22)
at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)
main try catch
thinkinjava.ExceptionLink$MyException2: thinkinjava.ExceptionLink$MyException1
at thinkinjava.ExceptionLink.b(ExceptionLink.java:26)
at thinkinjava.ExceptionLink.main(ExceptionLink.java:32)
Caused by: thinkinjava.ExceptionLink$MyException1
at thinkinjava.ExceptionLink.a(ExceptionLink.java:18)
at thinkinjava.ExceptionLink.b(ExceptionLink.java:22)
... 1 more
这便是异常链
finally语句在return语句中使用
try{
return;
}finally{
System.out.println("before return")
}
其会在返回前输出”before return”
异常丢失
造成异常丢失的两种情况:
try{
throw new Exception1();
}finally{
throw new Exception2();
}
try{
throw new MyException();
}finally{
return;
}