摘要
通過本章的學習,讀者應能夠了解Java語言中復雜的事件處理與錯誤處理。理解它們的概念,知道它們的工作流程,為今後學習打下基礎。
--------------------------------------------------------------------------------
本章目標:
通過本章的學習,讀者應能夠了解Java語言中復雜的事件處理與錯誤處理。理解它們的概念,知道它們的工作流程,為今後學習打下基礎。
12.1事件處理
傳授新知
消息驅動、事件處理是面向對象編程技術的主要特點,它一改過程語言的順序執行,整個程序以程序代碼為主線地思想,而是變成了由用戶,使用程序的用戶為主線的思想。
通俗地說,以前的程序設計思想中,整個程序的運行流程是以程序本身為主的,整個運行流程是在程序中預定義的。而在面向對象的程序設計思想中,則是讓用戶來把握主動權,整個運行流程是由用戶來決定的。應用程序一旦構建完GUI後,它就不再工作,而是等待,等待用戶通過鼠標、鍵盤給它通知(消息驅動),它再根據這個通知的內容進行相應的處理(事件處理)。
我們往返顧一下,在我們講解使用“按鈕”時,曾經在程序中使用過這樣的一段程序:
button1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
Toolkit.getDefaultToolkit().beep();
}
});
當時,我們已經對它的功能做了描述:首先為按鈕buuton1增加了一個事件監測器,這個事件監測器用來監測按鈕是否按下(ActionEvent)。另外,我們還編寫了一個事件處理的程序段:
public void actionPerformed(ActionEvent evt)
{
Toolkit.getDefaultToolkit().beep();
}
當按鈕按下時,就會執行這個程序段,也就執行了Toolkit.getDefault.Toolkit().beep()方法,即響了一聲鈴。
在程序中要編寫“事件處理”程序段時,通常可以分為以下幾個步驟來做:
1.確定事件類型
幾乎用戶使用鼠標、鍵盤做的每一個動作都會引起一個消息,也就是會引發一個事件,但我們並不是要對這些所有的事件都做出反應,有些事件並不是我們所關心的。對於不同的部件,我們需要關心的事件往往不同。下表中列出了最常用到的幾個事件。
部件 事件類型 事件描述
JButton ActionEvent 按下了按鈕
CheckBox ActionEvent 選擇或取消選擇復選框
JTextField ActionEvent 用戶輸入文本輸入回車鍵
表12-1 常用部件-事件一覽表
2.為部件增加一個該事件的監測器
每一種事件類型都有一個相應的接口,通常名為XXXListener,其中XXX代表它所處理的事件類型。這些接口包含在java.awt.event和javax.swing.event包中。例如:
button1.addActionListener(new ActionListener()
{
……
});
3.增加事件處理程序
最後,我們就要往裡面增加血肉,實際的事件處理程序。
正如你所看到的一樣,編寫事件處理程序並不是一件簡單的事,要寫好事件處理程序更不是那麼簡單。由於本書是一本Java的入門性書籍,所以並沒有把每個部件的全部事件都列舉出來,做一個一一講解。在此,只求大家能夠通過學習對事件處理過程有一個粗略地了解,以便大家能夠學習、研究各種與事件處理相關的知識。
實例說明
我們曾經在第10章中使用過Frame來構建小應用程序,當時我們可以看到程序執行時是新彈出了一個窗口,也就是一個Frame,這個Frame有最大化、最小化、關閉按鈕。不知各位讀者是否注重到,在這個Frame中呢,關閉按鈕並沒有生效,這是因為在程序中並未定義對這個事件的處理。下面我們來看一段程序,看一下它是如何使這個關閉按鈕生效的。根據慣例,我們首先創建一個源程序:
源程序:closeTest.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class closeTest
{
public static void main(String args[])
{
Frame frame1=new Frame("This is a Frame");
frame1.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
frame1.setSize(200,200);
frame1.show();
}
}
這是一個Java的應用程序,我們首先使用javac編譯,然後執行:
java closeTest
來執行這個程序,程序的輸出極為簡單:
圖12-1 程序closeTest.java的輸出
一些提示:
這個程序也從側面說明了,我們在Java的應用程序中也可以使用GUI界面,雖然我們一直使用Java小應用程序(Applet)來舉例。
程序的輸出是一個空白的Frame,大家現在按下關閉按鈕,你會發現,這個Frame馬上被關閉了。我們實現了我們的目標。
傳授新知
下面,我們一起來看一下這個程序:
1)
public static void main(String args[])
大家應該還記得,一個Java應用程序(Application)是從main方法開始執行的吧!
2)
Frame frame1=new Frame("This is a Frame");
在這時,我們定義了一個Frame,這個我們學習過了,不會多說。
3)
frame1.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
這段程序是本節最重要的內容。它為容器frame1增加了一個有關window(窗口)的事件監測器。監測的事件是什麼?是windowClosing,也就是按下關閉按鈕。
假如監測到這個按鈕被按下時,就執行System.exit(0)退出程序。
4)
frame1.setSize(200,200);
frame1.show();
這兩句語句,大家應該也不會生疏,我們先將Frame設置為200*200大,然後調用show方法將其顯示出來。
自測練習
1) 當一個部件有一個事件發生,但並沒有為這個部件的這個事件指定事件監測器,將會發生什麼?________________。
a.編譯時就不會通過 b.引起Java程序發生致命錯誤
c.忽略這個事件 d.引發默認的事件處理
2) 通常我們使用____________方法來為一個部件增加事件監視器。
a.addXXXListener b.XXXListener
3) 事件監視器包含在_____________包中。
a.java.awt.happen b.java.until c.java.awt.event
4) 按鈕按下事件名是__________。
a.PressedEvent b.ActionEvent
5) 在Java應用程序(Application)中不能夠使用JButton對象?_______。
a.對 b.錯
6) 僅有GUI部件可以產生事件?___________。
a.對 b.錯
請說明理由:
____________________________________________________________________
練習答案
1)c 這個事件將被忽略,因為Java中並不存在默認的事件處理。當然也不會使Java程序異常退出,Java還不至於如此脆弱吧!
2)a 當你碰到這種形式的語句,就是增加事件監測器。
3)c 在java.awt.event和javax.swing.event中。
4)b ActionEven。
5)b 雖然我們一直都在以Applet為例,但這不證實,Application中不能夠使用這些GUI部件。我們完全可以使用這個GUI部件組成一個Application程序。
6)b 這是一種錯覺,最簡單的例子就是Frame,它是容器呀,其實還有許多東西可以發生事件。
12.2錯誤處理
傳授新知
“世界上並不存在完全無錯的程序”,我們不討論它是不是一條真理。但它的確是一條警語,它告誡我們在編寫程序時一定要注重盡可能地避免錯誤。
程序運行出錯時會超出程序員的控制,使得程序“南轅北轍”,不僅無法正常完成功能,而且還會出現一些可怕的事情。
注重:
由於程序設計的錯誤而引起的事故數不勝數,損失最巨大的是美國的一次火箭發射,在那次悲劇中,在程序中由於錯把“,”寫成了“;”,卻使得火箭在天上爆炸,所以為防止程序設計錯誤花再大的人力、物力也是應該的。
最有效的解決方法是在程序設計是,有意識地加入一些機制,使其能夠在運行時檢測自己,在錯誤失控之前,報告出來。
最常見的一種錯誤處理是為每一個方法(其它語言,就是每一個函數)返回一個狀態值,用來指示該方法是否成功、正確地完成了任務。當調用這個方法的程序收到了一個錯誤的狀態值,就能夠得知程序出錯了,再采取有效的措施避免這個錯誤引起的問題(最簡單的方法就是退出程序,或給出提示提醒操作者)。
下面我們來考察一下簡單的例子:
public int getIndex(String emailaddr)
{
for(int x=0;x
這個方法用來在emailaddr字符串中找到“@”符所在的位置,然後返回位置值。但細心的讀者應該能夠很快地提出一個問題:假如emailaddr中沒有“@”符,那麼這個程序將返回什麼呢?
對,這就是潛在的錯誤可能。當emailaddr中沒有“@”符時,不管返回什麼值,可以確定的一點就是返回的值一定不正確!
然後,調用這個方法的程序並不知道它得到了一個錯誤的返回呀!它會當作一個正確的值繼續運行下去。糟了,“多米諾骨牌”啟動了!一個錯誤引發了。
所以,我們應該在這種時候,給調用這個方法的程序一個提示,那就是返回一個明確的錯誤值,比如在這裡我們可以使用-1來表示沒找到。使用這種思想,我們將程序改寫一下,形成:
public int getIndex(String emailaddr)
{
for(int x=0;x
我們在原來的程序中加上了一句:return(-1),這時程序的邏輯發生了變化,當找到時“@”符時,將返回它所在的位置。而假如找不到,那麼就會執行:return(-1)。
然後我們在調用這個方法的程序收到的返回值是-1時,就能夠意識到錯誤發生了。
自測練習
1) 請創建一個方法,在整數數組intArray查找是否有一個成員為5,有就返回它的位置。並且請注重加上一些錯誤處理機制。
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
____________________________________________________________________
在這個程序中,你使用了什麼錯誤處理機制。
____________________________________________________________________
____________________________________________________________________
假如整型數組intArray的值是{2,5,6,9,10}那麼,返回什麼值?
____________________________________________________________________
假如值是{4,6,2,90,8},則返回什麼值?
____________________________________________________________________
練習答案
1) 以下一個實例:
public int searchfive(int intArray[])
{
for(int x=0;x
在這個程序中,我們采用了通用的錯誤標識機制,也就是說,找到數字5,返回它的位置,而找不到數字5時,就返回-1。這樣可以讓調用這個方法的程序知道這個方法的執行效果。
假如整型數組intArray的值是{2,5,6,9,10}那麼將返回1。
而假如值是{4,6,2,90,8},那麼將找不到5,因而返回-1。
12.3異常處理
傳授新知
然而在有些情況下,合法的返回值和標識一個錯誤情形的返回值之間不能明確區分。這種情況下錯誤出現的地方,稱為異常情形。這個異常錯誤是致命錯誤,經常使得程序異常退出。
在Java語言中,提供了一些處理這些異常情況的工具,能夠較好的處理這些情況,使得Java程序更加健壯。由於這方面的內容相對比較高級,很難使用較短的篇幅來說明,所以本書(一本入門的書)僅以只言片語,與大家做一個簡單的介紹。
1.異常處理的流程
在Java中,異常是由Exception類定義的對象,一旦產生異常,方法的正常控制流會立即停止,Java虛擬機(JVM)將試圖找出能夠捕捉的處理程序並處理這個特定的異常。假如找不到處理程序,Exception對象將向上層傳遞,一層一層地上傳,直至程序的main方法。假如還是找不到處理程序,程序將退出運行。
也就是說,Java已經預先定義了許多異常情況(使用Exception類定義),當程序發生異常時,Java虛擬機就會想辦法尋找排除異常的辦法(也就是尋找相應的處理程序),假如在當前方法中找不到,就會將這個異常情況報告給調用這個方法的程序段,然後繼續尋找相應的程序。假如還找不到就再向上一層傳遞,直到程序的main方法。假如都找不到,程序就會異常退出。
2.構建異常處理的程序
那麼如何來構建這個異常處理程序呢?我們可以通過try/catch程序結構來設置:
try
{
……
}
catch(Exception ex)
{
……
}
當try塊內的代碼產生了catch塊中指定的異常就跳過try塊內的後面的代碼,而執行catch塊內的程序。
而假如try塊內的代碼未產生catch塊中指定的異常,則跳過catch塊內的程序。
更多的內容可以參考專門的書籍。