<a target="_blank" href="http://www.javahelp.com.cn/">java幫幫-it資源分享網</a>
五、黑馬程式員—異常處理和常用類
第五篇
1、異常
異常:就是不正常,是指程式在運作時出現的不正常情況。其實就是程式中出現的問題。
這個問題按照面向對象思想進行描述,并封裝成了對象。因為問題的産生有産生的原因、有
問題的名稱、有問題的描述等多個屬性資訊存在。當出現多屬性資訊最友善的方式就是将這
些資訊進行封裝。異常就是 java 按照面向對象的思想将問題進行對象封裝。這樣就友善于
操作問題以及處理問題。
出現的問題有很多種,比如角标越界,空指針等都是。就對這些問題進行分類。而且這
些問題都有共性内容比如:每一個問題都有名稱,同時還有問題描述的資訊,問題出現的位
置,是以可以不斷的向上抽取。形成了異常體系。
異常的體系 throwable
error
通常指 jvm 出現重大問題如:運作的類不存在或者記憶體溢出等。
不需要編寫針對代碼對其處理,程式無法處理。
exception
在運作時運作出現的一些情況,可以通過 try,catch,finally 處理
異常處理兩種方式:
1、捕獲異常:try catch 直接處理可能出現的異常!
2、聲明異常:throws 聲明告訴調用者可能的異常,暴露問題,調用者自己
處理!
我的總結:
exception 和 error 的子類名大都是以父類名作為字尾。
java 異常其實是對不正常情況的一種描述,并将其封裝成對象;
java 在 設計異常體系時,将容易出現的異常情況都封裝成了對象。
2、異常處理格式
異常處理的 5 個關鍵字
try ,catch,
finally
throw, throws
捕獲異常:先捕獲小異常再捕獲大異常。
程式是調出來的,不是寫出來的;多測試是程式員的必修課。
異常處理後,程式不會因為出現異常而退出!
異常處理格式
try{
//可能出異常的代碼
} catch(異常類 對象){
//處理該異常類型的語句
}
[finally] {
//一定會執行的代碼
//catch 塊使用 system.exit(1);除外
備注:當 try 語句塊出現異常,程式會自動跳到 catch 語句塊去找比對的異常類型,并執行
異常處理語句,finally 語句塊是異常的統一出口。
3、多異常處理
聲明異常時盡可能聲明具體異常類型,友善更好的處理;
方法聲明幾個異常就對應有幾個 catch 塊;
若多個 catch 塊中的異常出現繼承關系,父類異常 catch 塊放在最後;
在 catch 語句塊使用 exception 類作為異常類型時:
所有子類執行個體都可以使用父類接收(向上轉型),即所有的異常對象都可以使用 exception 接
收;
注:在 java 處理多異常時捕獲小範圍的異常必須放在大範圍異常之前。
java7 - 同時捕獲多個異常類型
java7 之前:
try {
int a = integer.parseint("1");
int b = integer.parseint("0");
int c = a / b;
system.out.println(c);
} catch (numberformatexception e)
{
e.printstacktrace();
} catch(arithmeticexception e)
java7:将多個異常寫到了同一個 catch 代碼塊
integer a = integer.parseint("1");
integer b = integer.parseint("0");
integer c = a / b;
} catch (numberformatexception
| arithmeticexception e ) {
4、異常的分類
異常分類:
編譯時被檢查異常; ---> checked 異常
在程式中必須使用 try...catch 處理;
編譯時不被檢測的異常; ---> runtime 異常
可以不使用 try...catch 處理,但一旦出現異常就将由 jvm 處理。
異常的分類之 runtime 異常
runtimeexception(運作時異常)是指因設計或實作方式不當而導緻的問題.
說白了,就是程式員造成的,程式員小心謹慎是完全可以避免的異常.比如,事先判斷對象是否
為 null 就 可 以 避 免 nullpointerexception 異 常 , 事 先 檢 查 除 數 不 為 0 就 可 以 避 免
arithmeticexception 異常;
特點:
這種異常java編譯器不會檢查它,也就說程式中出現這類異常的時候,即使不處理也沒有
問題,但是一旦出現異常,程式将異常終止,若采用異常處理,則會被相應的程式執行處理.
異常的分類之 checked 異常
除了 runtimeexception 以及子類,其他的 exception 及其子類都是受檢查異常,我們也可
以稱為非 runtimeexception 異常.
java 編譯器會檢查它,也就說程式中一旦出現這類異常,要麼是沒有 try-catch 語句捕獲,
或 throws 語句沒有聲明抛出它,編譯就不會通過,也就說這種異常,程式要求必須處理.
5、聲明異常(throws)
在可能出現異常的方法上聲明抛出可能出現異常的類型:
聲明的時候盡可能聲明具體的異常,友善更好的處理.
目前方法不知道如何處理這種異常,可将該異常交給上一級調用者來處理(非
runtimeexception 類型的異常)。
方法一旦使用 throws 聲明抛出方法内可能出現的異常類型, 該方法就可以不再過問該
異常了;
一個方法調用另一個使用 throws 聲明抛出的方法,自己要麼 try...catch , 要麼也 throws;
格式:
public 傳回值類型 方法名(參數清單...)
throws 異常類 a,異常類 b... {
6、throw
自行抛出一個異常對象,抛出異常類的對象;
若 throw 抛出的是 runtime 異常:
程式可以顯示使用 try...catch 來捕獲并處理,也可以不管,直接交給方法調用者處理;
若 throw 抛出 checked 異常:
要麼放在 try 裡自己處理,要麼放在一個 throws 聲明的方法裡面,交給調用者處理。
eg:
public static void main(string[] args) {
fn1(1);
} catch (exception e) { e.printstacktrace(); }
fn2(2);
public static void fn1(int a) throws exception{
if(a >0) { throw new exception("fn1 -- a 值不合法"); }
public static void fn2(int a) {
if(a >0) { throw new runtimeexception("a 值不合法"); }
throws & throw
throws 用于在方法上聲明該方法不需要處理的異常類型。
throw 用于抛出具體異常類的對象。
throws 與 throw 的差別:
thorws 用在方法上,後面跟異常類名,可以是多個異常類。
throw 用在方法内,後面跟異常對象,隻能是一個。
7、finally
異常的統一出口:
不管 try 塊程式是否異常,也不管哪個 catch 執行,finally 塊總會執行。
try 語句塊或會執行的 catch 語句塊使用了 jvm 系統退出語句例外;//system.exit(1);
try 塊必須和 catch 塊或和 finally 同在,不能單獨存在,二者必須出現一個。
不要在 finally 中使用 return 或 throw 語句,否則将會導緻 try、catch 中的 return 或 throw 失
效。
我的總結:finally 代碼塊隻在一種情況下不執行:system.exit(0);
package reviewdemo;
public class demo19 {
system.out.println(17/0);
}catch(exception e){
//e.printstacktrace();
system.out.println("程式錯誤,請修正!");
}finally{
system.out.println("這是finally代碼塊!");
輸出:
程式錯誤,請修正!
這是finally代碼塊!
8、throw 和 catch 同時使用
當異常出現在目前方法中,程式隻對異常進行部分處理,還有一些處理需要在方法的調用
者中才能處理完成,此時還應該再次抛出異常,這樣就可以讓方法的調用者也能捕獲到異常;
public static void buy(string price) throws exception {
if(price != null)
double.parsedouble(price);
} catch (exception e) {
throw new exception("價格不能隻能是數字組成");
buy(null);
system.out.println(e.getmessage());
9、常用類
string
string 表示字元串,所謂字元串,就是一連串的字元;
string 是不可變類,一旦 string 對象被建立,包含在對象中的字元序列(内容)是不可變的,
直到對象被銷毀;
常量池:jvm 中一塊獨立的區域存放字元串常量和基本類型常量(public static final)。
string 使用 private final char value[]來實作字元串的存儲,也就是說 string 對象建立之後,
就不能再修改此對象中存儲的字元串内容,就是因為如此,才說 string 類型是不可變的.
string 對象比較:
單獨使用""引号建立的字元串都是常量,編譯期就已經确定存儲到常量池中;
使用 new string("")建立的對象會存儲到堆記憶體中,是運作期新建立的;
使用隻包含常量的字元串連接配接符如"aa" + "bb"建立的也是常量,編譯期就能确定,已經确
定存儲到常量池中;
使用包含變量的字元串連接配接符如"aa" + s1 建立的對象是運作期才建立的,存儲在堆中;
package string;
public class stringdemo {
/*
* "" 其實表示的是 string 的匿名對象
*/
string s = "";
/**
* string() 初始化一個新建立的 string 對象,使其表示一個空字元序列。
* "",不是表示 null
* string(string original)
* string s = new string("asd");// s 的值就是 asd
s = new string();//""
string s1 = new string("11");
string s2 = new string("11");
system.out.println(s1 == s2);//false
string s3 = "22";
string s4 = "22";
system.out.println(s3 == s4);//true
system.out.println(s3 == s2);//false
string s5 = "2" + "2";//這句話其實在編譯器編譯後的 class 檔案中 已經變成 "22"
//s5 建立了幾個對象?//回答:最多一個,如果常量池裡面沒有就是建立一個,如果
常量池裡本來就有就是建立零個!下面的 str 一樣的道理。
string str = "a" +"b"+ "c" +"d" +"e";//string str = "abcde";
system.out.println(s3 == s5);//true
* string 特點: 不可變的, 一個 string 對象的内容不能變,一旦内容變量該對象
就變成一個新的 string 對象了
* string str = "aaa";
* str = str+"12";
string str1 = "abcde";
system.out.println(str == str1);//true
string str2 = "abc" + "de";
system.out.println(str == str2);//true
string ss = "ab";
string str3 = ss + "cde";//這裡的 str3 在運作期才能确定内容值
system.out.println(str3 == str2);//false
string str4 = getstr() +"cde";//在運作期才能确定 str4 的值
system.out.println(str == str4);//false
system.out.println(str3 == str4);//false
* string s = "cd"; //一個 string 對象
s = s + "itcast"; //itcast 也是 string 對象, 最後的 s 的值 cditcast,也是一個
string 對象
system.out.print(s);
* */
public static string getstr(){
return "ab";
eg:
public class demo20 {
//s1,s2隻建立了一個對象
string s1 = "你好";
string s2 = "你好";
//s3,s4建立了兩個對象
string s3 = "你好";
string s4 = "你好";
10、string 方法
string():初始化一個新的 string 對象,使其表示一個空字元序列,并不是傳回空(不等于
null)。
string(stringbuffer buffer):根據 stringbuffer 對象來建立 string 對象;
string(stringbuilder builder):同上
char charat(int index):取字元串中指定位置的字元,index 從 0 開始計算。
string concat(string str):連接配接字元串,等同于 “+”;
boolean contentequals(stringbuffer buffer):若二者包含的字元序列相同時就傳回 true;
boolean equals(object obj):将該字元串與指定對象比較,若二者包含的字元序列相等傳回
true;
boolean equalsignorecase(string anotherstring) 将此 string 與另一個 string 比較,不考慮大
小寫;
byte[] getbytes():将該字元串轉換成 byte 數組;
int indexof(string str):找出 str 字元串在該字元串中第一次出現的位置;
int indexof(string str, int fromindex) 傳回指定子字元串在此字元串中第一次出現處的索引,
從指定的索引開始;
int lastindexof(string str) 傳回指定子字元串在此字元串中最後一次出現處的索引;
int length():傳回目前字元串長度;
string replace(char oldchar, char newchar) :傳回一個新的字元串,它是通過用 newchar 替換
此字元串中出現的所有 oldchar 得到的。
string replaceall(string regex, string replacement) 使用給定的 字元串 replacement 替換此字
符串所有的 regex 字元串;
boolean startswith(string prefix) 測試此字元串是否以指定的字首開始.
string[] split(string regex): 把字元串按指定的字元串分隔開。
string substring(int beginindex) 傳回一個新的字元串,從 beginindex 開始截取,它是此字元
串的一個子字元串;
string substring(int beginindex, int endindex) 傳回一個新字元串,它是此字元串的一個子字元
串;[begin,end)
char[] tochararray() 将此字元串轉換為一個新的字元數組。
string tolowercase() 将此 string 中的所有字元都轉換為小寫;
string touppercase()轉成大寫;
static string valueof(基本類型 obj):把基本類型值轉成字元串;
string trim() :忽略字元串前導空白和尾部空白。
string 小練習
判斷字元串是否由數字組成:
string s1 = "123456789";
string s2 = "12345 6789";
system.out.print(isnum(s1));
system.out.print(isnum(s2));
public static boolean isnum(string s){
char []ch = s.tochararray();
for (char c : ch) {
if(!(c > '0' && c <= '9')){
return false;
return true;
true
false
判斷字元串是否為空:
分析:
字元串的空有兩種情況:1、null;2、"";
public class demo21 {
string s1 = "";
system.out.println(isimpty(s1));
public static string isimpty(string s){
if(s != null & !"".equals(s)){
return "不為空";
return "為空!";
11、stringbuffer 與 stringbuilder
string 是不可變類,一旦 string 對象被建立,包含在對象中的字元序列是不可變的,直到對
象被銷毀;
stringbuffer 與 stringbuilder 對象則是可變的!
舉例說明這兩個的好處:(不用每次建立對象,效率高!)
public class demo22 {
long begintime = system.currenttimemillis();
for(int i = 1;i <= 100000;i++){
s += i;
long endtime = system.currenttimemillis();
long time = endtime - begintime;
system.out.println("運作時間為:"+time);
stringbuffer s1 = new stringbuffer();
s = "";
begintime = system.currenttimemillis();
s = ""+i;
s1 = new stringbuffer(s);
endtime = system.currenttimemillis();
time = endtime - begintime;
運作時間為:82922
運作時間為:15
可以看得出:stringbuffer 這兩個效率相當高!
stringbuffer: 是線程安全的;
stringbuilder: 是線程不安全的,性能高點,推薦使 stringbuilder;(jdk1.5 出現)
stringbuffer 的字元序列是可變的(通過 append 等方法操作)
stringbuffer 和 string 之間的轉換;
string tostring() 傳回此序列中資料的字元串表示形式。
stringbuffer(string str):以指定的字元串建立 stringbuffer 對象。
stringbuffer 方法
public stringbuilder()構造一個不帶任何字元的 stringbuilder 對象。
stringbuffer(string str) :構造一個字元串緩沖區,并将其内容初始化為指定的字元串内容。
stringbuffer append(object o) :将指定的任意類型對象追加到此 stringbuffer 對象。
stringbuffer insert(int offset, object o) :将任意類型參數的字元串表示形式插入此序列中。
stringbuffer delete(int start, int end) :移除此序列的子字元串中的字元。
stringbuffer deletecharat(int index): 移除此序列指定位置的 char。
* 用stringbuilder 或stringbuffer:
把字元串“abcde”;
轉變成字元串“a,b,c,d”
public class demo23 {
//第一種方法:往裡面插入;
stringbuilder sb = new stringbuilder("abcde");
sb.deletecharat(sb.length()-1);
system.out.println(sb);
for (int i = 0; i < sb.length(); i+=2) {
sb.insert(i, ",");
sb.deletecharat(0);
//第二種方法:往裡面追加,要追加必須周遊,必須換為數組!
sb = new stringbuilder("abcde");
char []cs = sb.tostring().tochararray();
stringbuilder sb1 = new stringbuilder();
for (char c : cs) {
sb1.append(c).append(",");
sb1.deletecharat(sb1.length()-1);
system.out.println(sb1);
編寫一個程式,這個程式把一個整數數組中的每個元素用逗号連接配接成一個字元串,例如,
根據内容為{1,2,3}的數組形成内容為"1,2,3"的字元串。
* 編寫一個程式,
* 這個程式把一個整數數組中的每個元素用逗号連接配接成一個字元串,
* 例如,根據内容為{1,2,3}的數組形成内容為"1,2,3"的字元串。
public class demo24 {
int []i = {1,2,3,4,5};
stringbuilder sb = new stringbuilder();
for (int j : i) {
sb.append(j).append(",");
12、math 和 random 和 uuid
math 類
public final class math extends object
以下 x 表示 double,float,int, long
abs(x x):求絕對值
max(x x1,x x2):求最大值
min(x x1,x x2):求最小值
public static double random():傳回帶正号的 double 值,該值大于等于 0.0 且小于 1.0。
和使用 new java.util.random 一樣
math.pi;
random 類
負責生成僞随機數;
random() 建立一個新的随機數生成器。
int nextint() 傳回下一個僞随機數,它是此随機數生成器的序列中均勻分布的 int 值。
int nextint(int n) 傳回一個僞随機數,它是取自此随機數生成器序列的、在 0(包括)
和指定值 n(不包括)之間均勻分布的 int 值。
public class demo26 {
system.out.println(math.e);//2.718281828459045
int a = 12;
int b = 25;
system.out.println(math.max(a,b));//這裡可以使用靜态導入(導入
math類中的方法,這樣的話前面就不用寫上math.)
system.out.println(math.min(a,b));
import java.util.uuid;
public class demo27 {
uuid u = uuid.randomuuid();
string s = u.tostring();
system.out.println(s);//此時是随機生成的,肯定每次都不一樣,全網唯
一!
u = new uuid(1222222222, 12);//根據構造方法來
s = u.tostring();
system.out.println(s);//這一個的uuid是固定的。
我的總結:uuid(用來标示檔案名等(免得檔案上傳因為名字可能一樣而被覆寫),可以
保證全網唯一!)
uuid 類:用唯一辨別符 (uuid) 的類。 uuid 表示一個 128 位的值。
uuid(universally unique identifier)全局唯一辨別符,是指在一台機器上生成的數字,它保證
對在同一時空中的所有機器都是唯一的。按照開放軟體基金會(osf)制定的标準計算,用到
了以太網卡位址、納秒級時間、晶片 id 碼和許多可能的數字。由以下幾部分的組合:目前
日期和時間(uuid 的第一個部分與時間有關,如果你在生成一個 uuid 之後,過幾秒又生
成一個 uuid,則第一個部分不同,其餘相同),時鐘序列,全局唯一的 ieee 機器識别号(如
果有網卡,從網卡獲得,沒有網卡以其他方式獲得),uuid 的唯一缺陷在于生成的結果串
會比較長。
标準的 uuid 格式為:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx (8-4-4-4-12),其中每個 x 是 0-9
或 a-f 範圍内的一個十六進制的數字;
uuid uuid = uuid.randomuuid();
string uid = uuid.tostring();
13、date 和 calendar
處理日期,時間;
大部分的方法已過時,不推薦使用,但是你使用過時的方法也不會報錯。
date() 配置設定 date 對象并初始化此對象,以表示配置設定它的時間(精确到毫秒)。
date(long date) 配置設定 date 對象并初始化此對象,以表示自從标準基準時間(稱為“曆元
(epoch)”,即 1970 年 1 月 1 日 00:00:00 gmt)以來的指定毫秒數。
simpledateformat
java.text.simpledateformat
simpledateformat 是一個與語言環境有關的方式來格式化和解析日期的具體類。它允許進
行格式化(日期 -> 文本)、解析(文本 -> 日期)和規範化。
simpledateformat(string pattern) 用給定的模式和預設語言環境的日期格式符号構造
simpledateformat。
public final string format(date date)将一個 date 格式化為日期/時間字元串。
public date parse(string source) throws parseexception:把字元串 source 表示的時間按 source
的格式轉成 date 對象。
練習:string 與 date 的互相轉化
按某種時間格式來輸出指定的 string 類型時間
date2string
format
把某種時間格式的 string 時間轉成 date 類型時間
string2date
parse
import java.text.simpledateformat;
import java.util.date;
public class demo28 {
public static void main(string[] args) throws exception {
date d = new date();
system.out.println(d);//擷取目前時間
//格式化
simpledateformat sd = new simpledateformat("yyyy-m-d
hh:mm:ss e");
string s = sd.format(d);//這個方法繼承于simpledateformat的父類
dateformat類!
system.out.println(s);
//反格式化
d = sd.parse(s);
system.out.println(d);
calendar
推薦使用處理日期和時間的類 calendar;
是抽象類,不能執行個體化,通過
static calendar getinstance() 獲得一個 calendar 對象。
int get(int field):傳回指定月曆字段值
靜态常量:
year 表示年的字段數字。
month 表示月份字段數字,月份範圍是[0,11]。
date 表示一個月中的某天。
day_of_month 表示一個月中的某天。
day_of_week 表示一個星期中的某天。
hour_of_day / hour 表示第幾小時
minute 表示第幾分鐘
second 表示第幾秒
date gettime() 傳回一個表示此 calendar 時間值的 date 對象。
void set(int year, int month, int date, int hour, int minute, int second) 設定字段 year、
month、day_of_month、hour、minute 和 second 的值。
abstract void add(int field, int amount) 根據月曆的規則,為給定的月曆字段添加或減去指定的
時間量。
若 amount 為負數,則減去一天,
若 amount 為正數 ,則加上一天
例子
import java.util.calendar;
public class demo29 {
calendar c = calendar.getinstance();
date d = c.gettime();
* void set(int year, int month, int date, int hour, int minute,
int second)
* 設定字段 year、month、day_of_month、hour、minute 和 second 的
值。
c.set(2015, 07, 15, 12, 24, 55);
d = c.gettime();
c.add(calendar.day_of_month, 3);
我的總結:注意常檢視 api!
eg:“查詢距今最近三天内的記錄”,這裡的‘三天内’是什麼時間段?
将目前日期時間轉換為 隻擷取當天的 00:00:00
如: 2011-08-08 12:12:12 轉化為 2011-08-08 00:00:00、
public class demo30 {
simpledateformat sd = new simpledateformat("yyyy-m-d hh:mm:ss
e");
string s = sd.format(d);
c.set(2015, 8, 23, 13, 24, 15);
system.out.println(sd.format(d));
c.add(calendar.day_of_month, -3);
thu jul 04 08:56:51 cst 2013
2013-7-4 08:56:51 星期四
2015-9-23 13:24:15 星期三
2015-9-20 13:24:15 星期日
14、system
system 類包含一些與系統相關的類字段和方法。它不能被執行個體化,類中所有屬性和方法都
是 static,可直接被 system 調用。
常用方法:
static void exit(int status) 終止虛拟機的運作.對于發生了異常情況而想終止虛拟機的運作,傳
遞一個非 0 數值,對于正常情況下退出系統傳遞 0 值;
該方法實際調用的是 runtime.getruntime().exit(int status);
static void arraycopy(object src, int srcpos, object dest, int destpos, int length) 數組拷貝
static long currenttimemillis() 傳回以毫秒為機關的目前時間。
string getenv(string name) 獲得指定的環境變量;
static void gc() 運作垃圾回收器。
實際上調用了 runtime 中的 gc()方法;
runtime.getruntime().exec("notepad ");
static properties getproperties() 取得目前的系統屬性。
static string getproperty(string key) 取得指定鍵訓示的系統屬性。
static string getproperty(string key, string def) 擷取用指定鍵描述的系統屬性,def 表示預設
資訊。
eg:package reviewdemo627;
import java.util.properties;
public class demo32 {
properties p = system.getproperties();
system.out.println(p);
system.out.println(system.getenv());