异常使得我们可以将每件事都当作一个事务来考虑,而异常可以看护着这些事务的底线 “… 事务的基本保障是我们所需的在分布式计算中的异常处理。事务是计算机中的合同法,如果出了什么问题,我们只需要放弃整个计算。” 我们还可以将异常看作是一种内建的恢复(undo)系统,因为(在细心使用的情况下)我们在程序中可以拥有各种不同的恢复点。如果程序的某部分失败了,异常将 “恢复” 到程序中某个已知的稳定点上。
自定义异常
不必拘泥于 Java 中已有的异常类型。Java 提供的异常体系不可能预见所有的希望加以报告的错误,所以可以自己定义异常类来表示程序中可能会遇到的特定问题。
要自己定义异常类,必须从已有的异常类继承,最好是选择意思相近的异常类继承(不过这样的异常并不容易找)。建立新的异常类型最简单的方法就是让编译器为你产生默认构造器,所以这几乎不用写多少代码.
class SimpleException extends Exception {}
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!");
}
}
}
class SimpleException extends Exception {}
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!");
}
}
}
class MyException extends Exception {
MyException() {}
MyException(String msg) { super(msg); }
}
class MyException extends Exception {
MyException() {}
MyException(String msg) { super(msg); }
}
栈轨迹
public class LoggingExceptions {
static void f() {
try {
throw new Exception();
} catch(Exception e) {
e.printStackTrace(); // 打印调用栈
for(StackTraceElement ste : e.getStackTrace()) {
System.out.println(ste.getMethodName()); // 调用方法
}
}
}
static void g() { f(); }
static void h() { g(); }
public static void main(String[] args) {
f();
System.out.println("*******");
g();
System.out.println("*******");
h();
}
}
public class LoggingExceptions {
static void f() {
try {
throw new Exception();
} catch(Exception e) {
e.printStackTrace(); // 打印调用栈
for(StackTraceElement ste : e.getStackTrace()) {
System.out.println(ste.getMethodName()); // 调用方法
}
}
}
static void g() { f(); }
static void h() { g(); }
public static void main(String[] args) {
f();
System.out.println("*******");
g();
System.out.println("*******");
h();
}
}
// e.printStackTrace();
java.lang.Exception
at xx.LoggingExceptions.f(LoggingExceptions.java:18)
at xx.LoggingExceptions.main(LoggingExceptions.java:29)
java.lang.Exception
at xx.LoggingExceptions.f(LoggingExceptions.java:18)
at xx.LoggingExceptions.g(LoggingExceptions.java:26)
at xx.LoggingExceptions.main(LoggingExceptions.java:31)
java.lang.Exception
at xx.LoggingExceptions.f(LoggingExceptions.java:18)
at xx.LoggingExceptions.g(LoggingExceptions.java:26)
at xx.LoggingExceptions.h(LoggingExceptions.java:27)
at xx.LoggingExceptions.main(LoggingExceptions.java:33)
f
main
*******
f
g
main
*******
f
g
h
main
// e.printStackTrace();
java.lang.Exception
at xx.LoggingExceptions.f(LoggingExceptions.java:18)
at xx.LoggingExceptions.main(LoggingExceptions.java:29)
java.lang.Exception
at xx.LoggingExceptions.f(LoggingExceptions.java:18)
at xx.LoggingExceptions.g(LoggingExceptions.java:26)
at xx.LoggingExceptions.main(LoggingExceptions.java:31)
java.lang.Exception
at xx.LoggingExceptions.f(LoggingExceptions.java:18)
at xx.LoggingExceptions.g(LoggingExceptions.java:26)
at xx.LoggingExceptions.h(LoggingExceptions.java:27)
at xx.LoggingExceptions.main(LoggingExceptions.java:33)
f
main
*******
f
g
main
*******
f
g
h
main
Java使用框架集成的log4j2、logback等统一打印日志,尽量不使用catch的e.printStackTrace()
原文链接:https://blog.csdn.net/ChenShiAi/article/details/106064606
1、占用太多内存,造成锁死
e.printStackTrace()要打印字符串输出到控制台上,需要字符串常量池所在的内存块有足够的空间。由于e.printStackTrace() 语句要产生的字符串记录的是堆栈信息,太长太多,内存被填满了!大量线程产出字符串等待有内存被释放,会造成相互等待内存(字符串池所属的那么点非堆内存空间),导致整个应用挂掉了。
2、日志交错混合,不易读
从开始学习java,老师就教我们写代码要具有可读性,易读性。同样,日志的输出如果不具有易读性,也是让程序员非常头疼的一件事。那么为什么e.printStackTrace输出的日志具有不易读性了呢?
printStackTrace()默认使用了System.err输出流进行输出,与System.out是两个不同的输出流,那么在打印时自然就形成了交叉。再就是输出流是有缓冲区的,所以对于什么时候具体输出也形成了随机。
————————————————