Skip to content

【OnJava-十五】异常

异常使得我们可以将每件事都当作一个事务来考虑,而异常可以看护着这些事务的底线 “… 事务的基本保障是我们所需的在分布式计算中的异常处理。事务是计算机中的合同法,如果出了什么问题,我们只需要放弃整个计算。” 我们还可以将异常看作是一种内建的恢复(undo)系统,因为(在细心使用的情况下)我们在程序中可以拥有各种不同的恢复点。如果程序的某部分失败了,异常将 “恢复” 到程序中某个已知的稳定点上。

自定义异常

不必拘泥于 Java 中已有的异常类型。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!");
        }
    }
}
java
class MyException extends Exception {
    MyException() {}
    MyException(String msg) { super(msg); }
}
class MyException extends Exception {
    MyException() {}
    MyException(String msg) { super(msg); }
}

栈轨迹

java
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();  
    }  
}
java
// 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是两个不同的输出流,那么在打印时自然就形成了交叉。再就是输出流是有缓冲区的,所以对于什么时候具体输出也形成了随机。
————————————————