- 1 概念
- 2 基本异常
- 3 捕获异常
- 4 创建自定义异常
- 5 异常说明
- 6 捕获所有异常
- 7 java标准异常
- 8 使用finally进行清理
- 9 异常的限制
- 10 构造器
- 11 异常匹配
- 12 其他可选方式
- 13 异常使用指南
- 14 总结
java的基本理念是"结构不佳的代码不能够运行"
发现错误的理想时机是编译阶段,然而,编译期间并不能找出所有的错误,余下的问题必须在运行时期解决。
1 概念
2 基本异常
异常情形(exceptional conditin)是指阻止当前方法或作用域继续执行的问题.
普通问题是指在当前环境下能得到足够的信息,总能处理这个错误
当抛出异常后,有几件事会随之发生。首先,同Java中其它对象的创建一样,将使用new在堆上创建异常对象。然后,当前的执行路径被终止,并且从当前环境中弹出对异常对象的引用。此时,异常处理机制接管程序,并开始寻找一个恰当的地方来继续执行程序。这个恰当的地方就是异常处理程序,它的任务是将程序从错误状态中恢复,以使程序要么换一种方式运行,要么继续运行下去。
if(t == null) throw new NullPointerException();//这样就把错误信息传播到更大的环境中,
标准异常都有两个构造器:一个是默认构造器,一个是接受字符串作为参数,以便能把有关信息放入异常对象的构造器;
能够抛出任意类型的Throwable对象,它是异常的根类
3 捕获异常
监控区域(guarded region):一段可能产生异常的代码,并且后面跟着处理这些异常的代码
- try块
如果在方法内部抛出异常后,这个方法将在抛出异常的过程中结束,如果不想就此结束,可以设置一个try块来捕获异常
try{
//Code that might generate exception
}
2.异常处理程序
异常处理程序紧跟在try块之后,以关键字catch表示,异常处理程序必须紧跟在try块之后,当异常被抛出时,异常处理机制将负责搜寻参数与异常类型想匹配的第一个处理程序,然后进入catch子句执行,此时认为异常得到了处理,一旦catch子句结束才处理程序的查找过程结束,并不会在调用其它catch子句.
异常处理模型
终止模型:错误非常关键,一旦异常被抛出,即终止程序
4 创建自定义异常
编译器创建了默认构造器,它将自动调用基类的默认构造器,一般不会用Excetption(String)这样的构造器,这种构造器不实用,对异常来说最重要的是类名
package exceptions;
class SimpleException extends Exception{}
// 编译器创建了默认构造器,自动调用基类的默认构造器
/*
public class Exception extends Throwable
public Exception() {
super();
}
public class Throwable implements Serializable
public Throwable() {
fillInStackTrace();
}
*/
public class InheritingExceptions{
public void f() throws SimpleException{
System.out.println("Throw SimpleException from f()");
throw new SimpleException();
}
public static void main(String[] args) {
InheritingExceptions sed = new InheritingExceptions();
try{
sed.f();
}catch (SimpleException e){
System.out.println("Caught it");
}
}
}
/*
Throw SimpleException from f()
Caught it
*/
也可以通过写入System.err而将错误发送给标准错误流,更容易被用户注意。
通常这比System.out要好,因为System.out也许被重定向
package exceptions;
class MyException extends Exception{
public MyException(){}
public MyException(String msg){ super(msg);} //接受字符串参数的构造器
}
public class FullConstructors {
public static void f() throws MyException {
System.out.println("Throwing MyException from f()");
throw new MyException();
}
public static void g() throws MyException {
System.out.println("Throwing MyException from g()");
throw new MyException("Originate in g()");
}
public static void main(String[] args) {
try {
f();
} catch (MyException e) {
// e.printStackTrace(); // 默认 标准错误流,不会被重定向,容易引起用户注意
e.printStackTrace(System.err); // 标准错误流,不会被重定向,容易引起用户注意
e.printStackTrace(System.out); // 标准输出流,也许会被重定向
}
try {
g();
} catch (MyException e) {
e.printStackTrace(System.out);
}
}
}
/*
Throwing MyException from f()
exceptions.MyException
at exceptions.FullConstructors.f(FullConstructors.java:11) // printStackTrace 打印 从方法调用处 直到异常抛出处的方法调用序列。
at exceptions.FullConstructors.main(FullConstructors.java:21)
Throwing MyException from g()
exceptions.MyException: Originate in g()
at exceptions.FullConstructors.g(FullConstructors.java:16)
at exceptions.FullConstructors.main(FullConstructors.java:28)
*/
作业1
package exceptions.e1;
public class E1 {
public static void main(String[] args) {
try {
throw new Exception("An exception in E1 main");
} catch (Exception e) {
System.out.println(e.getMessage());
// e.printStackTrace();
}finally {
System.out.println("In finally clause");
}
}
}
/*
An exception in E1 main
In finally clause
*/
作业2
package exceptions.e2;
public class E2 {
public static void main(String[] args) {
String s = null;
try{
s.toString();
}catch (Exception e){
e.printStackTrace();
}
}
}
/
java.lang.NullPointerException
at exceptions.e2.E2.main(E2.java:8)
/
作业3
package exceptions.e3;
public class E3 {
public static void main(String[] args) {
String[] strings = new String[5];
for (int i = 0; i < strings.length; i++) {
strings[i] = Integer.toString(i);
}
try {
System.out.println(strings[6]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("e: " + e);
}
}
}
/*
e: java.lang.ArrayIndexOutOfBoundsException: 6
*/
作业4
package exceptions.e4;
class MyException extends Exception {
String msg;
public MyException(String msg) {
this.msg = msg;
}
public void printMsg() {
System.out.println("msg = " + msg);
}
}
// Or take a more clever approach,
// noting that string storage and printing are
// built into Exception:
class MyException2 extends Exception {
public MyException2(String s) {
super(s);
}
}
public class E4 {
public static void main(String[] args) {
try {
throw new MyException("MyException message");
} catch (MyException e) {
e.printMsg();
}
try {
throw new MyException2("MyException2 message");
} catch (MyException2 e) {
System.out.println(
"e.getMessage() = " + e.getMessage());
}
}
}
作业5
package exceptions.e5;
/*终止模型 Java支持
错误非常关键,一旦异常被抛出,即终止程序
*/
/*恢复模型
恢复模型:意思是异常处理程序的工作是修正错误,然后重新尝试调用出问题的方法,并认为第二次可以成功
如果要用java实现类似的恢复行为,那么在遇到错误时,就不能抛出异常,
而时调用正确的方法来修正该错误,或者把try块放进一个while循环里,这样就不断进入while块,直到得到满意的结果。
*/
class ResumerException extends Exception {
}
class Resumer {
static int count = 3;
static void f() throws ResumerException {
if (--count > 0)
throw new ResumerException();
}
}
public class E5 {
public static void main(String[] args) {
while (true) {
try {
Resumer.f();
} catch (ResumerException e) {
e.printStackTrace();
continue;// 停止当前while迭代,退回循环起始处,开始下一次迭代
}
System.out.println("Got through...");
break;//强行退出while循环,不执行剩余语句
}
System.out.println("Successful execution");
}
}
/*
exceptions.e5.ResumerException
at exceptions.e5.Resumer.f(E5.java:22)
at exceptions.e5.E5.main(E5.java:30)
exceptions.e5.ResumerException
at exceptions.e5.Resumer.f(E5.java:22)
at exceptions.e5.E5.main(E5.java:30)
Got through...
Successful execution
*/
4.1异常与记录日志
1.利用java.util.logging工具将输出记录到日志中
package exceptions;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;
class LoggingException extends Exception{
private static Logger logger = Logger.getLogger("LoggingException");
//Logger.getLogger()方法创建了一个String参数相关联的Logger对象(通常是与错误相关的包名或类名)
//这个Logger对象会将其输出发送到System.err
public LoggingException(){
StringWriter trace = new StringWriter();
printStackTrace(new PrintWriter(trace));
//printStackTrace不会产生默认字符串,为了获取字符串,我们使用重载的
//printStackTrace()方法,它接受一个java.io.PrintWriter()对象作为参数,如果我们将一个SrtingWriter对象传递给
//这个Printwrite()构造器,那么就可以调用toString()方法,就可以抽取为一个String
logger.severe(trace.toString());//severe写入日志
}
}
public class LoggingExceptions {
public static void main(String[] args) {
try{
throw new LoggingException();
}catch (LoggingException e){
System.out.println("Caught " + e);
}
try{
throw new LoggingException();
}catch (LoggingException e){
System.out.println("Caught " + e);
}
}
}
/*
十一月 19, 2019 5:45:16 下午 exceptions.LoggingException <init>
严重: exceptions.LoggingException
at exceptions.LoggingExceptions.main(LoggingExceptions.java:24)
Caught exceptions.LoggingException
十一月 19, 2019 5:45:16 下午 exceptions.LoggingException <init>
严重: exceptions.LoggingException
at exceptions.LoggingExceptions.main(LoggingExceptions.java:30)
Caught exceptions.LoggingException
*/
2.捕获和记录其它人编写的异常
尽管LoggingException将所有记录日志的基础设施都构建在了异常自身中,使用它非常方便.
但更常见的是我们需要捕获和记录其它人编写的异常,必须在异常处理程序中生成日志消息
package exceptions;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;
public class LoggingExceptions2 {
private static Logger logger =
Logger.getLogger("LoggingExceptions2");
static void logException(Exception e) {
StringWriter trace = new StringWriter();
e.printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch(NullPointerException e) {
logException(e);
}
}
}
/*
十一月 19, 2019 5:56:10 下午 exceptions.LoggingExceptions2 logException
严重: java.lang.NullPointerException
at exceptions.LoggingExceptions2.main(LoggingExceptions2.java:17)
*/
3.自定义异常
自定义异常,比如加入额外的构造器和成员,因为我们必须在异常处理信息中生成日志信息
对异常类来说,覆盖了 Throwable的 getMessage
public String getMessage() {
return detailMessage;
}
getMessage() { //相当于toString()方法
package exceptions;
import static net.mindview.util.Print.print;
class MyException2 extends Exception {
private int x;
public MyException2() {}
public MyException2(String msg) { super(msg); }
public MyException2(String msg, int x) {
super(msg);
this.x = x;
}
public int val() { return x; }
public String getMessage() { //相当于toString()方法
return "Detail Message: "+ x + " "+ super.getMessage();
}
}
public class ExtraFeatures {
public static void f() throws MyException2 {
print("Throwing MyException2 from f()");
throw new MyException2();
}
public static void g() throws MyException2 {
print("Throwing MyException2 from g()");
throw new MyException2("Originated in g()");
}
public static void h() throws MyException2 {
print("Throwing MyException2 from h()");
throw new MyException2("Originated in h()", 47);
}
public static void main(String[] args) {
try {
f();
} catch(MyException2 e) {
e.printStackTrace(System.out);
}
try {
g();
} catch(MyException2 e) {
e.printStackTrace(System.out);
}
try {
h();
} catch(MyException2 e) {
e.printStackTrace(System.out);
System.out.println("e.val() = " + e.val());
}
}
}
/*
Throwing MyException2 from f()
exceptions.MyException2: Detail Message: 0 null
at exceptions.ExtraFeatures.f(ExtraFeatures.java:22)
at exceptions.ExtraFeatures.main(ExtraFeatures.java:34)
Throwing MyException2 from g()
exceptions.MyException2: Detail Message: 0 Originated in g()
at exceptions.ExtraFeatures.g(ExtraFeatures.java:26)
at exceptions.ExtraFeatures.main(ExtraFeatures.java:39)
Throwing MyException2 from h()
exceptions.MyException2: Detail Message: 47 Originated in h()
at exceptions.ExtraFeatures.h(ExtraFeatures.java:30)
at exceptions.ExtraFeatures.main(ExtraFeatures.java:44)
e.val() = 47
*/
作业6
package exceptions.e6;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;
class LoggingException1 extends Exception {
private static Logger logger = Logger.getLogger("LoggingException1");
public LoggingException1() {
StringWriter trace = new StringWriter();
printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
}
class LoggingException2 extends Exception {
private static Logger logger = Logger.getLogger("LoggingException2");
public LoggingException2() {
StringWriter trace = new StringWriter();
printStackTrace(new PrintWriter(trace));
logger.severe(trace.toString());
}
}
public class E6 {
public static void main(String[] args) {
try {
throw new LoggingException1();
} catch (LoggingException1 e) {
System.out.println("Caught" + e);
}
try {
throw new LoggingException2();
} catch (LoggingException2 e) {
System.out.println("Caught " + e);
}
}
}
/*
每个异常都使用自己的logger实例,分别是LoggingException1和LoggingException2。
十一月 19, 2019 6:15:02 下午 exceptions.e6.LoggingException1 <init>
严重: exceptions.e6.LoggingException1
at exceptions.e6.E6.main(E6.java:33)
Caughtexceptions.e6.LoggingException1
十一月 19, 2019 6:15:02 下午 exceptions.e6.LoggingException2 <init>
严重: exceptions.e6.LoggingException2
at exceptions.e6.E6.main(E6.java:39)
Caught exceptions.e6.LoggingException2
*/
作业7
package exceptions.e7;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.logging.Logger;
public class E3 {
private static Logger logger = Logger.getLogger("E3");
static void logExcption(Exception e) {
StringWriter trace = new StringWriter();
e.printStackTrace();
new PrintWriter(trace);
logger.severe(trace.toString());
}
public static void main(String[] args) {
String[] strings = new String[5];
for (int i = 0; i < strings.length; i++) {
strings[i] = Integer.toString(i);
}
try {
System.out.println(strings[6]);
} catch (ArrayIndexOutOfBoundsException e) {
logExcption(e);
}
}
}
/*
e: java.lang.ArrayIndexOutOfBoundsException: 6
*/
5 异常说明
异常说明使用了附加的关键字 throws ,后面接一个所有潜在异常类型的列表,方便客户端程序员查看.
public static void main(String[] args)
throws NullPointerException,NoSuchFieldError //这里就是异常说明
{
try {
throw new NullPointerException();
} catch(NullPointerException e) {
logException(e);
}
}
自顶向下强制执行对异常说明机制,java在编译时候就保证一定水平对异常准确性。
要么处理这个异常,要么就在异常说明中表面此方法将产生异常。
“作弊”方法:声明方法将抛出异常,实际不抛出:为异常占个位置,以后就可以抛出异常而不用修改已有代码。在抽象基类和接口定义时这种能力很重要,派生类或接口实现就能抛出预先声明的异常。
作业7
package exceptions.e8;
class MyException extends Exception {
public MyException(String s) {
super(s);
}
}
class Thrower {
// public void f(){
// throw new MyException("MyException in f()");
// }
public void g() throws MyException {
throw new MyException("MyException in g()");
}
}
public class E8 {
public static void main(String[] args) {
Thrower t = new Thrower();
try{
t.g();
} catch (MyException myException2) {
myException2.printStackTrace();
}
}
}
/*
exceptions.e8.MyException: MyException in g()
at exceptions.e8.Thrower.g(E8.java:15)
at exceptions.e8.E8.main(E8.java:23)
*/