Java04異常、斷言、日志和調試

11 異常、斷言、日志和調試

異常處理(exception handing

使用斷言來啟動檢測

Java日志框架

調試技巧

11.1 處理錯誤

如果一個方法不能夠采用正常的途徑完成任務,就通過另外一個路徑退出方法。

在這種情況下,方法不返回任何值,而是拋出一個封裝了錯誤信息的對象。此外,調用這個方法的代碼也將無法繼續執行。

異常處理機制開始搜索能夠處理這種異常情況的異常處理器(exception handler)。

異常處理的任務就是將控制權從錯誤產生的地方轉移給能夠處理這種情況的錯誤處理器。

?

異常對象是派生于Throwable類的一個實例。

可以創建自己的異常類。

?

異常的分類:

Throwable

Exception

RuntimeException

?

ArrayIndexOutOfBoundsException

NullPointerException

IOException

?

?

Error

?

?

?

Error類層次描述的是Java運行時系統的內部錯誤和資源耗盡。

應用程序不應拋出此類錯誤。

除了通告給用戶并盡力使程序安全地中止之外,再也無能為力。

此種情況很少出現。

?

派生于Error類或RuntimeException類的所有異常稱為未檢查(unchecked)異常;

所有其他的異常稱為已檢查(checked)異常。

編譯器將檢查是否為所有已檢查異常提供了異常處理器。

?

聲明已檢查異常:

public FileInputStream(String name) throws?FileNotFoundException

?

一個方法要么返回其返回值,要么拋出一個異常。

一個方法必須聲明所有可能拋出的已檢查異常,而未檢查異常要么不可控(Error),要么應避免(RuntimeException)。

如果子類中覆蓋了超類的一個方法,子類方法中聲明的已檢查異常不能比超類方法中聲明的異常更通用。

?

如何拋出異常:

1、找到一個合適的異常類;

2、創建其類對象;

3、將對象拋出。

如:throw new EOFException();

throw new EOFException(String);

?

一旦方法拋出異常,這個方法就不能返回到調用者。

C++中可以拋出任何類型的值,Java中只能拋出Throwable子類的對象。

?

創建異常類:

定義一個派生于Exception的類,或者派生于Exception子類的類。

包含兩個構造器:默認構造器;帶有詳細描述信息的構造器。

class FileFormatException extends IOException
{public FileFormatException(){}public FileFormatException(String message){super(massage);}
}

11.2 捕獲異常

如果某個異常發生的時候沒有在任何地方進行捕獲,那程序就會終止執行,并在控制臺上打印出異常信息,其中包括異常的類型和堆棧信息。

捕獲異常:

try
{code that might throw exception
}
catch(FileNotFoundException | UnknownHostException e) //捕獲多個異常時,e隱含為final變量。
{emergency action for missing files and unknown hosts
}
catch(IOException e)
{emergency action for all other I/O problems
}

如果try語句塊中的任何代碼拋出了一個在catch子句中說明的異常類,則跳過try語句塊的其余代碼,執行catch子句中的處理器代碼;

如果try語句塊中拋出的異常沒有在catch子句中說明,則立即退出這個方法;

如果try語句塊沒有拋出異常,則跳過catch子句。

?

通常,異常處理的最好選擇是什么都不做,而是將異常傳遞給調用者。

如果調用了一個拋出已檢查異常的方法,要么處理,要么傳遞。

通常,捕獲那些知道如何處理的異常,傳遞那些不知怎樣處理的異常。

?

catch子句中還可以拋出一個異常,這樣做目的是改變異常的類型。

如:

try
{access the database
}
catch (SQLException e)
{Throwable se = new ServletException(“database error”);se.initCause(e);throw se;
}
finally
{close resource;
}

Throwable e = se.getCause();

//可以得到原始異常,使用這種包裝技術,可以讓用戶拋出子系統中的高級異常,而不會丟失原始異常的細節。


如果在一個方法中發生了一個已檢查異常,而方法不允許拋出它,那么包裝技術可以將這個已檢查異常包裝成一個運行時異常。

?

強烈建議使用try/catchtry/finally子句

finally子句一定會被執行。

?

帶資源的try語句

try(Resource res = ...)
{work with res;
}
//try塊退出時,自動調用res.close()方法。
//此時,try塊拋出的異常被拋出,close方法拋出的異常被抑制。

帶資源的try語句自身也可以有catch子句和一個finally子句。這些子句會在關閉資源后執行。

在實際中,一個try語句中加入這么多內容可能不是一個好主意。

?

堆棧跟蹤(stack trace):

是一個方法調用過程的列表,包含了程序執行過程中方法調用的特定位置。

 
Throwable t = new Throwable();
StackTraceElement[] frames = t.getStackTrace();
for (StackTraceElement frame : frames)analyze frame;
//多線程堆棧跟蹤
Map<Thread, StackTraceElement[]> map = Thread.getAllStackTraces();
for (Thread t : map.keySet())
{StachTraceElement[] frames = map.get(t);analyze frames
}


11.3 使用異常的技巧

1、異常處理不能代替簡單的測試;

2、不要過分細化異常;

3、利用異常層次結構;

4、不要壓制異常;對于不常發生的異常,catch語句塊的內容可以先空著,待日后感覺需要處理時再填上。

5、不要羞于傳遞異常。

?

11.4 使用斷言

斷言機制允許在測試期間向代碼中插入一些檢查語句。

當代碼發布時,這些插入的檢測語句將會被自動移走。

?

assert 條件;

assert 條件:表達式;

?

這兩種形式都會對條件進行檢測,如果結果為false,則拋出一個AssertionError異常。

在第二種形式中,表達式將被傳入AssertionError的構造器,并轉換成一個消息字符串。

表達式的唯一目的就是產生一個消息字符串。

?

assert x >= 0;

assert x >=0 : x;

assert x >=0 “x >= 0”;

?

默認情況下,斷言被禁用。

在運行時,用-enableassertions -ea 選項啟用它。

java -enableassertions MyApp

在啟用或禁用斷言時不必重新編譯程序。啟用或禁用斷言時類加載器(class loader)的功能。

當斷言被禁用時,類加載器將跳過斷言代碼,因此不會降低程序運行的速度。

也可選用-disableassertions-da禁用某個特定類或包的斷言。

?

Java中,給出了三種處理系統錯誤的機制:

異常;

日志;

斷言。

?

斷言是致命的,不可恢復的錯誤。只用于開發和測試階段。

斷言是一種測試和調試階段所使用的戰術性工具;

日志記錄是一種在程序的整個生命都可以使用的策略性工具。


11.5 記錄日志

優點:

·可以取消全部日志記錄,或僅取消某個級別的日志,而且打開和關閉這個操作也很容易;

·可以很簡單的禁止日志記錄的輸出,因此,這些日志代碼留在程序中的開銷很小;

·日志記錄可以在控制臺中顯示,也可以在文件中存儲;

·可以對日志記錄進行過濾,只保留重要日志;

·可以采用不同格式:純文本或XML

·可使用多個日志記錄;

·默認情況下,日志系統的配置由配置文件控制;如果需要的話,應用程序可以替換這個配置。

?

基本日志:

日志系統管理著一個名為Logger.global的默認日志記錄器,可通過info方法記錄日志信息

Logger.getGlobal().info(“File->Open menu item selected”); //記錄日志

Logger.getGlobal().setLevel(Level.OFF); //取消所有日志

?

高級日志:

在一個應用程序中,不要將所有的日志都記錄到一個全局日志記錄器中,而是自定義日志記錄器。

調用getLogger方法可以創建或檢索記錄器:

private static final Logger myLogger = Logger.getLogger(“com.mycompany.myapp”);

日志記錄具有層次結構,上下層之間將共享某些屬性,例如對com.mycompany日志記錄器設置了日志級別,它的子記錄器也會繼承這個級別。

SERVER ?WARNING ?INFO ?CONFIG ?FINE ?FINER ?FINEST

默認記錄前三個級別。

?

級別設置:

logger.setLevel(Level.FINE); //Level.ALL開啟所有級別 Level.OFF關閉所有級別

?

記錄方法:

logger.waring(message);

logger.fine(message);

logger.log(level.FINE, message);

?

默認的日志配置記錄了INFO或更高級別的所有記錄。

應該使用CONFIGFINEFINEST級別來記錄那些有助于診斷,但對于程序員又沒有太大意義的調試信息。

?

默認的日志記錄將顯示包含日志調用的類名和方法名,如同堆棧所顯示的那樣。

但是,如果虛擬機對執行過程進行了優化,就得不到準確的調用信息。

此時可用logp方法獲得調用類和方法的確切位置:

void logp(Level l, String className, String methodName, String Message)

?

?

跟蹤執行流的方法:

void entering(String className, String methodName)

void entering(String className, String methodName, Object param)

void entering(String className, String methodName, Object[] params)

void exiting(String className, String methodName)

void exiting(String className, String methodName, Object result)

如:

int read(String file, String pattern)
{logger.entering(“com.mycompany.mylib.Reader”,”read”,new Object[]{file, pattern};...logger.exiting(“com.mycompany.mylib.Reader”,”read”,count);return count;
}


這些調用將產生FINER級別和以字符串ENTRYRETURN開始的日志記錄。

?

日志記錄的常見用途是記錄那些不可預料的異常。

兩種方法:

void throwing(String className, String methodName, Throwable t)

void log(Level l, String message, Throwable t)

典型用法:

if(...)
{IOException exception = new IOException(“...”);logger.throwing(“com.mucompany.mylib.Reader”,”read”,exception);throw exception;
}
//調用throwing可以記錄一條FINER級別的記錄和一條以THROW開始的信息。try
{...
}
catch(IOException)
{Logger.getLogger(“com.mycompany.myapp”).log(Level.WARNING, “Reading image”, e);
}

修改日志管理器配置文件jre/lib/logging.properties

日志管理器在VM啟動過程中被初始化,在main之前執行。

.level=INFO //修改默認的日志記錄級別

com.mycompany.myapp.level=FINE 指定自己的日志記錄級別

?

本地化:

本地化的應用程序包含資源包(resource bundle)中的本地特定信息。

資源包由各個地區的映射集合組成。如某個資源包可以將redingFile映射成英文的Reading file或者德文的Achtung! Datei wired eingelesen

一個程序可以包含多個資源包,一個用于菜單;其他用于日志消息。

每個資源包都有一個名字,如com.mycompany.logmessages

要想將映射添加到一個資源包中,需要為每個地區創建一個文件。

英文消息映射位于com/mycompany/logmessages_en.properties文件中;

德文消息映射位于com/mycompany/logmessages_de.properties文件中。

可以將這些文件與應用程序的類文件放在一起,以便ResourceBundle類自動對它們進行定位。

這些文件都是純文本文件,內容如下:

readigFile=Achtung! Datei wird eingelesen

renamingFile=Datei wird umbenannt

?

在請求日志記錄器時,可以指定一個資源包:

Logger logger= Logger.getLogger(loggerName, “com.mycompany.logmessages”);

然后,為日志消息指定資源包的關鍵字,而不是實際的日志消息字符串:

logger.info(“readingFile”);

?

通常需要在本地化的消息中增加一些參數,因此,消息應該包括占位符{0}{1}等。

例如,在日志消息中包含文件名,需要使用下列方式包含占位符:

readingFile=Reading file {0}

renamingFile=Change name file {0} to {1}

?

logger.log(Level.INFO, “readingFile”, fileName);

logger.log(Level.INFO, “renamingFile”, new Object[]{oldName, newName};

?

處理器:

默認情況下,日志記錄器將記錄發送到ConsoleHandler中,并由它輸出到System.err流中。

日志記錄器還會將記錄發送到父處理中,最終處理器(命名為””)有一個ConsoleHandler

處理器也有一個日志記錄級別。

?

安裝自己的處理器:

Logger logger = Logger.getLogger(“com.mycompany.myapp”);

logger.setLevel(Level.FINE);

logger.setUseParentHandlers(false);

Handler handler = new ConsoleHandler();

handler.setLevel(Level.FINE);

logger.addHandler(handler);

?

其他處理器:

FileHandler 將記錄發送到用戶主目錄的javan.log文件中,n是文件的唯一編號,默認XML格式。

SocketHandler 將記錄發到特定的主機和端口。

?

?

過濾器:

默認情況下,過濾器根據日志記錄的級別進行過濾。

每個日志記錄器和處理器都可以有一個可選的過濾器來完成附加的過濾。

另外,可通過實現Filter接口的boolean isLoggable(LogRecord record)方法來自定義過濾器。

調用setFilter方法安裝過濾器。

一個時刻最多只能有一個過濾器。

?

日志記錄說明:日志記錄器最好與主應用程序包名相同;



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/387302.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/387302.shtml
英文地址,請注明出處:http://en.pswp.cn/news/387302.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

全雙工與半雙工的區別

1、全雙工傳輸 (英文Full&#xff0d;Duplex &#xff09; 是指交換機在發送數據的同時也能夠接收數據&#xff0c;兩者同步進行&#xff0c;這好像我們平時打電話一樣&#xff0c;說話的同時也能夠聽到對方的聲音。目前的交換機都支持全雙工。全雙工的好處在于遲延小&#xff…

人臉識別經典算法一:特征臉方法(Eigenface)

這篇文章是擼主要介紹人臉識別經典方法的第一篇&#xff0c;后續會有其他方法更新。特征臉方法基本是將人臉識別推向真正可用的第一種方法&#xff0c;了解一下還是很有必要的。特征臉用到的理論基礎PCA在另一篇博客里&#xff1a;特征臉(Eigenface)理論基礎-PCA(主成分分析法)…

Java05泛型

12 泛型 12.1 為什么使用泛型 泛型程序設計&#xff08;Generic programming&#xff09;&#xff1a;意味著編寫的代碼可以被很多不同類型的對象所重用。 類型參數&#xff08;type parameters&#xff09; 通配符類型&#xff08;wildcard type&#xff09; 可以將Manage…

bitmap轉換為drawable

Bitmap bitmap MediaStore.Images.Media.getBitmap(this, Uri.parse(string)); Drawable drawable new BitmapDrawable(bitmap);// 這樣就轉換成drawable格式&#xff0c;可以設置背景圖片了轉載于:https://www.cnblogs.com/Nigeria/p/10471028.html

numpy的下載與安裝教程——(解決No module named numpy問題)

NumPy函數庫是Python開發環境的一個獨立模塊&#xff0c;而且大多數Python發行版沒有默認安裝NumPy數據庫&#xff0c;因此在安裝Python之后必須單獨安裝NumPy數據庫。 進入Python shell開發環境后輸入 [python] view plaincopy from numpy import* 如果出現No module named …

Xception

The First ColumnThe Second Columnpadding 方式&#xff1a;same and valid The First ColumnThe Second ColumnSame 就是 增加一列相同的數 &#xff08;一般是0&#xff09;valid只保留有效的轉載于:https://www.cnblogs.com/hugeng007/p/10477430.html

1.蒼穹外賣-day01

蒼穹外賣-day01 課程內容 軟件開發整體介紹 蒼穹外賣項目介紹 開發環境搭建 導入接口文檔 Swagger 項目整體效果展示&#xff1a; 管理端-外賣商家使用 用戶端-點餐用戶使用 當我們完成該項目的學習&#xff0c;可以培養以下能力&#xff1a; 1. 軟件開發整體介紹 作為一名…

7 用戶和用戶組

7.1 用戶配置文件 7.1.1 用戶信息文件 /etc/passwd man 5 passwd 查看配置文件功能 第1字段&#xff1a; 用戶名稱 第2字段&#xff1a; 密碼標志 X代表有密碼 如果用戶沒有密碼&#xff0c;則只允許本地登錄 第3字段&#xff1a; UID&#xff08;用戶ID&#xff09; 0…

C#調用Python模塊

編程&#xff1a;C#調用Python模塊 當下&#xff0c;C#與Python都是比較熱門的計算機編程語言&#xff0c;他們各有優缺點&#xff0c;如果能讓他們互相配合工作&#xff0c;那是多么美好的事情&#xff0c;今天我來講解一下如何利用C#來調用Python。 如果讓C#支持調用Python模…

面試簡單整理之克隆

61.為什么要使用克隆&#xff1f; 克隆獲取對象的副本&#xff0c;直接用復制還是一個引用。 62.如何實現對象克隆&#xff1f; 1.被clone的類實現cloneable接口&#xff0c;重寫object類的clone&#xff08;&#xff09;方法 2.如果深克隆則克隆對象的引用對象也要實現接口、重…

8 權限管理

8.1 ACL權限 8.1.1 簡介與開啟 用于解決身份不夠用的問題 ACL(access control list) 訪問控制表 ACL是存在于計算機中的一張表&#xff0c;它使操作系統明白每個用戶對特定系統對象&#xff0c;例如文件目錄或單個文件的存取權限。 這張表對于每個系統用戶有擁有一個訪問…

windows下GitHub的SSH Key 配置

https://www.jianshu.com/p/9317a927e844轉載于:https://www.cnblogs.com/lishidefengchen/p/10481889.html

PyCharm調試錯誤

JetBrains PyCharm 2017.3.2 這就說明python.exe的環境沒有配&#xff0c;點擊藍色的configure Python Interpreter&#xff0c;然后選擇對應的路徑就可以了

Java06集合

13 集合 實現方法時&#xff0c;不同的數據結構會導致性能有很大差異。 13.1 集合接口 Java集合類庫將接口&#xff08;interface&#xff09;與實現&#xff08;implementation&#xff09;分離。 可以使用接口類型存放集合的應用&#xff0c;一旦改變了想法&#xff0c;可…

Tensorflow驗證碼識別應用

簡單的Tensorflow驗證碼識別應用&#xff0c;供大家參考&#xff0c;具體內容如下 1.Tensorflow的安裝方式簡單,在此就不贅述了. 2.訓練集訓練集以及測試及如下(純手工打造,所以數量不多): 3.實現代碼部分(參考了網上的一些實現來完成的) main.py(主要的神經網絡代碼) ?123456…

9 文件系統管理

9.1 回顧分區和文件系統 分區類型 主分區&#xff1a;總共最多只能分四個 擴展分區&#xff1a;只能有一個&#xff0c;主分區加擴展分區最多有四個&#xff0c;必須再劃分成邏輯分區才能使用。 邏輯分區&#xff1a;在擴展分區中劃分的 IDE硬盤最多支持59個邏輯分區 SCSI…

Linux 桌面玩家指南:09. X Window 的奧秘

Linux 桌面玩家指南&#xff1a;09. X Window 的奧秘 原文:Linux 桌面玩家指南&#xff1a;09. X Window 的奧秘特別說明&#xff1a;要在我的隨筆后寫評論的小伙伴們請注意了&#xff0c;我的博客開啟了 MathJax 數學公式支持&#xff0c;MathJax 使用$標記數學公式的開始和結…

Storm教程1理論介紹

流式計算的歷史: 早在7、8年前諸如UC伯克利、斯坦福等大學就開始了對流式數據處理的研究&#xff0c;但是由于更多的關注于金融行業的業務場景或者互聯網流量監控的業務場景&#xff0c;以及當時互聯網數據場景的限制&#xff0c;造成了研究多是基于對傳統數據庫處理的流式化&…

梯度下降原理及Python實現

梯度下降算法是一個很基本的算法&#xff0c;在機器學習和優化中有著非常重要的作用&#xff0c;本文首先介紹了梯度下降的基本概念&#xff0c;然后使用python實現了一個基本的梯度下降算法。梯度下降有很多的變種&#xff0c;本文只介紹最基礎的梯度下降&#xff0c;也就是批…

dagger2的初次使用

一、使用前準備 1、打開app的build.gradle文件&#xff1a; 頂部停用apt插件&#xff1a; //添加如下代碼&#xff0c;應用apt插件 apply plugin: com.neenbedankt.android-apt dependencies中添加依賴&#xff1a; //Dagger2compile com.google.dagger:dagger:2.4apt com.goog…