day10 10、異常的一些注意點

10、異常的一些注意點

10.1 Java.util.logging(JDK自帶的記錄日誌類)

10.1.1 簡介

日誌用來記錄程序的運行軌跡,方便查找關鍵信息,也方便快速定位解決問題。下面介紹 Java 自帶的日誌工具類 java.util.logging 的使用。

如果要生成簡單的日誌記錄,可以使用全局日誌記錄器並調用其 info 方法,代碼如下:

Logger.getGlobal().info("打印信息");

JDK Logging 把日誌分爲如下表 7 個級別,等級依次降低。

級別 SEVERE WARNING INFO CONFIG FINE FINER FINEST
調用方法 severe() warning() info() config() fine() finer() finest()
含義 嚴重 警告 信息 配置 良好 較好 最好

Logger 的默認級別是 INFO,比 INFO 級別低的日誌將不顯示。Logger 的默認級別定義在 jre 安裝目錄的 lib 下面。

Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO

所以在默認情況下,日誌只顯示前三個級別,對於所有的級別有下面幾種記錄方法:

logger.warning(message);
logger.fine(message);

同時,還可以使用 log 方法指定級別,例如:

logger.log(Level.FINE, message);

例 1

package exception_use;

import java.util.logging.Logger;

public class TestLog {

        private static Logger log = Logger.getLogger(TestLog.class.toString());
        public static void main(String[] args) {
            // 級別依次升高,後面的日誌級別會屏蔽之前的級別
            log.finest("finest");
            log.finer("finer");
            log.fine("fine");
            log.config("config");
            log.info("info");
            log.warning("warning");
            log.severe("server");
        }
    }


輸出結果爲:
在這裏插入圖片描述

可以使用 setLevel 方法設置級別,例如logger.setLevel(Level.FINE);可以將 FINE 和更高級別的都記錄下來。另外,還可以使用 Level.ALL 開啓所有級別的記錄,或者使用 Level.OFF 關閉所有級別的記錄。

注意:如果將記錄級別設計爲 INFO 或者更低,則需要修改日誌處理器的配置。默認的日誌處理器不會處理低於 INFO 級別的信息。

10.1.2 修改日誌管理器配置

在這裏插入圖片描述
可以通過編輯配置文件來修改日誌系統的各種屬性。在默認情況下,配置文件存在於 jre 安裝目錄下“jre/lib/logging.properties”。要想使用另一個配置文件,就要將 java.util.logging.config.file 特性設置爲配置文件的存儲位置,並用下列命令啓動應用程序。

java -D java.util.logging.config.file = configFile MainClass

日誌管理器在 JVM 啓動過程中初始化,這在 main 執行之前完成。如果在 main 中調用System.setProperty("java.util.logging.config.file",file),也會調用LogManager.readConfiguration()來重新初始化日誌管理器。

要想修改默認的日誌記錄級別,就需要編輯配置文件,並修改以下命令行。

.level=INFO

可以通過添加以下內容來指定自己的日誌記錄級別

Test.Test.level=FINE

也就是說,在日誌記錄器名後面添加後綴 .level。

在稍後可以看到,日誌記錄並不將消息發送到控制檯上,這是處理器的任務。另外,處理器也有級別。要想在控制檯上看到 FINE 級別的消息,就需要進行下列設置。

java.util.logging.ConsoleHandler.level=FINE

注意:在日誌管理器配置的屬性設置不是系統屬性,因此,用-Dcom.mycompany.myapp.level=FINE啓動應用程序不會對日誌記錄器產生任何影響

10.2 自動資源管理(java7後加,java9增強)

10.2.1 介紹

public static void main(String[] args) {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream("a.txt");
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } finally {
        // 關閉磁盤文件,回收資源
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Java 7 以前,上面程序中的 finally 代碼塊是不得不寫的“臃腫代碼”,爲了解決這種問題,Java 7 增加了一個新特性,該特性提供了另外一種管理資源的方式,這種方式能自動關閉文件,被稱爲自動資源管理(Automatic Resource Management)。該特性是在 try 語句上的擴展,主要釋放不再需要的文件或其他資源。

自動資源管理替代了 finally 代碼塊,並優化了代碼結構和提高程序可讀性。語法如下:

try (聲明或初始化資源語句) {//加()來聲明!
    // 可能會生成異常語句
} catch(Throwable e1){
    // 處理異常e1
} catch(Throwable e2){
    // 處理異常e1
} catch(Throwable eN){
    // 處理異常eN
}

當 try 代碼塊結束時,自動釋放資源。不再需要顯式的調用 close() 方法,

該形式也稱爲“帶資源的 try 語句”。

注意:

  1. try 語句中聲明的資源被隱式聲明爲 final,資源的作用侷限於帶資源的 try 語句。
  2. 可以在一條 try 語句中聲明或初始化多個資源,每個資源以;隔開即可。
  3. 需要關閉的資源必須實現了 AutoCloseable 或 Closeable 接口。
  4. Closeable 是 AutoCloseable 的子接口,Closeable 接口裏的 close() 方法聲明拋出了 IOException,因此它的實現類在實現 close() 方法時只能聲明拋出 IOException 或其子類;AutoCloseable 接口裏的 close() 方法聲明拋出了 Exception,因此它的實現類在實現 close() 方法時可以聲明拋出任何異常。

下面示範如何使用自動關閉資源的 try 語句。

public class AutoCloseTest {
    public static void main(String[] args) throws IOException {
        try (
                // 聲明、初始化兩個可關閉的資源
                // try語句會自動關閉這兩個資源
                BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));
                PrintStream ps = new PrintStream(new FileOutputStream("a.txt"))) {
            // 使用兩個資源
            System.out.println(br.readLine());
            ps.println("使用帶資源的try");
        }
    }
}

上面程序中分別聲明、初始化了兩個 IO 流,BufferedReader 和 PrintStream 都實現了 Closeable 接口,並在 try 語句中進行了聲明和初始化,所以 try 語句會自動關閉它們。

自動關閉資源的 try 語句相當於包含了隱式的 finally 塊(這個 finally 塊用於關閉資源),因此這個 try 語句可以既沒有 catch 塊,也沒有 finally 塊。

Java 7 幾乎把所有的“資源類”(包括文件 IO 的各種類、JDBC 編程的 Connection 和 Statement 等接口)進行了改寫,改寫後的資源類都實現了 AutoCloseable 或 Closeable 接口。

如果程序需要,自動關閉資源的 try 語句後也可以帶多個 catch 塊和一個 finally 塊。

10.2.2 java9的增強自動資源管理(不用寫()只要聲明瞭final或有效final)

Java 9 再次增強了這種 try 語句。Java 9 不要求在 try 後的圓括號內聲明並創建資源,只需要自動關閉的資源有 final 修飾或者是有效的 final (effectively final),Java 9 允許將資源變量放在 try 後的圓括號內。上面程序在 Java 9 中可改寫爲如下形式。

public class AutoCloseTest {
    public static void main(String[] args) throws IOException {
        // 有final修飾的資源
        final BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));
        // 沒有顯式使用final修飾,但只要不對該變量重新賦值,該變量就是有效的
        final PrintStream ps = new PrintStream(new FileOutputStream("a. txt"));
        // 只要將兩個資源放在try後的圓括號內即可
        try (br; ps) {
            // 使用兩個資源
            System.out.println(br.readLine());
            ps.println("使用帶資源的try");
        }
    }
}

10.3 final and return執行順序

在 finally 代碼塊中改變返回值並不會改變最後返回的內容。且它一定會被執行!

總結爲以下幾條:

  • 當 try 代碼塊和 catch 代碼塊中有 return 語句時,finally 仍然會被執行。
  • 執行 try 代碼塊或 catch 代碼塊中的 return 語句之前,都會先執行 finally 語句。
  • 無論在 finally 代碼塊中是否修改返回值,返回值都不會改變,仍然是執行 finally 代碼塊之前的值。finally 代碼塊中的 return 語句一定會執行。

10.4 異常規範

10.4.1 C++異常規範(拋棄)

概念
C++ 規定,異常規範在函數聲明和函數定義中必須同時指明,並且要嚴格保持一致,不能更加嚴格或者更加寬鬆。

注意
C++裏邊我們知道異常規範是拋棄的,異常規範是 C++98 新增的一項功能,但是後來的 C++11 已經將它拋棄了,不再建議使用。
java裏邊的異常規範不同!

10.4.2 java的異常規範

參考大佬的博客,作記錄:Java 異常處理基本規則,Java異常處理的基本規範

1)不要捕獲運行時異常
不要捕獲 Java 類庫中定義的繼承自 RuntimeException 的運行時異常類,如:IndexOutOfBoundsException / NullPointerException ,這類異常由程序員預檢查來規避,保證程序健壯性。

2) try-catch 作用域(現有代碼出現率較高)
對大段代碼進行try-catch ,這是不負責任的表現。catch 時請細分各種類型進行捕獲!分清穩定代碼和非穩定代碼,穩定代碼指的是無論如何不會出錯的代碼。對於非穩定代碼的 catch 儘可能進行區分異常類型,再做對應的異常處理。
3)異常的捕捉 & 異常的處理(現有代碼出現率較高)
捕獲異常是爲了處理它,不要捕獲了卻什麼都不處理而拋棄之,如果不想處理它,請將該異常拋給它的調用者。最外層的業務使用者,必須處理異常,將其轉化爲用戶可以理解的內容。
4)異常 & finally
如果有對IO 流和資源做操作,必須逐一關閉IO 流和資源對象(從裏層到外層),有異常也要做處理。

JDK 7 以上可以使用try-with-resources 方式。 (java7的自動資源管理,java9的增強自動資源管理)
5)finally & return
不能在 finally 塊中使用 return ,finally 塊中的 return 返回後方法結束執行,不會再執行 try 塊中的 return 語句。
6)異常需要精確
捕獲異常與拋異常,必須是完全匹配,或者捕獲異常是拋異常的父類。如果預期對方拋的是繡球,實際接到的是鉛球,就會產生意外情況。

7)程序員的基本修養 & NPE

  1. 方法(接口)的返回值可以爲 null ,但不推薦返回空集合,或者空對象等,必須添加註釋充分說明什麼情況下會返回 null 值。調用方需要進行 null 判斷防止 NPE 問題。

  2. 防止 NPE ,是程序員的基本修養,注意 NPE 產生的場景。

    a.查詢數據庫返回null ,包括null 對象和null 集合。

    b.集合內元素有null 對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章