1、理論知識部分java
異常:在程序的執行過程當中所發生的異常事件,它中斷指令的正常執行。程序員
Java的異常處理機制能夠控制程序從錯誤產生的位置轉移到可以進行錯誤處理的位置。編程
程序中出現的常見的錯誤和問題有:用戶輸入錯誤;設備錯誤;物理限制;代碼錯誤。數組
Java把程序運行時可能遇到的錯誤分爲兩類:非致命異常:經過某種修正後程序還能繼續執行。這類錯誤叫做異常。如:文件不存在、無效的數組下標、空引用、網絡斷開、打印機脫機、磁盤滿等。 Java中提供了一種獨特的處理異常的機制,經過異常來處理程序設計中出現的錯誤。致命異常:程序遇到了很是嚴重的不正常狀態,不能簡單恢復執行,是致命性錯誤。如:內存耗盡、系統內部錯誤等。這種錯誤程序自己沒法解決。安全
Java中全部的異常類都直接或間接地繼承於Throwable類。除內置異常類外,程序員可自定義異常類。網絡
Java中的異常類可分爲兩大類: Error :Error類層次結構描述了Java 運行時系統的內部錯誤和資源耗盡錯誤。應用程序不該該捕獲這類異常,也不會拋出這種異常 。 Exception類: Exception層次結構又分解爲兩個分支:一個分支派生於 RuntimeException;另外一個分支包含其餘異常。app
RuntimeException爲運行時異常類,通常是程序錯誤產生。派生於RuntimeException的異常包含下面幾種狀況:錯誤的類型轉換;數組訪問越界;訪問空指針。less
Java將派生於Error類或RuntimeException類的全部異常稱爲未檢查異常,編譯器容許不對它們作出異常處理。 注意:「若是出現RuntimeException異常,就必定是程序員的問題!!!」dom
非運行時異常,程序自己沒有問題,但因爲某種狀況的變化,程序不能正常運行,致使異常出現。除了運行時異常以外的其它繼承自Exception類的異常類包括:試圖在文件尾部後面讀取數據;試圖打開一個錯誤格式的URL。 編譯器要求程序必須對這類異常進行處理 (checked),稱爲已檢查異常。測試
RuntimeException運行時異常類:ArithmeticException: 算術異常類;ArrayStoreException: 數組存儲異常類;ClassCastException: 類型強制轉換異常類;IndexOutOfBoundsException: 下標越界異常類;NullPointerException: 空指針異常類;SecurityException: 違背安全原則異常類。
IOException:輸入輸出異常類:IOException:申請I/O操做沒有正常完成。EOFException:在輸入操做正常結束前碰見了文件結束符。FileNotFountException:在文件系統中,沒有找到由文件名字符串指定的文件。
聲明拋出異常:若是一個方法可能會生成一些異常,可是該方法並不確切知道如何對這些異常事件進行處理,此時,這個方法就需聲明拋出這些異常。「一個方法不只須要告訴編譯器將要返回什麼值,還要告訴編譯器可能發生什麼異常。」
聲明拋出異常在方法聲明中用throws子句中來指明。例如:public FileInputStream(String name ) throws FileNotFoundException
throws子句能夠同時指明多個異常,說明該方法將不對這些異常進行處理,而是聲明拋出它們。public static void main(String args[]) throws IOException,IndexOutOfBoundsException
如下4種狀況須要方法用throws子句聲明拋出異常:一、方法調用了一個拋出已檢查異常的方法。二、程序運行過程當中可能會發生錯誤,而且利用throw語句拋出一個已檢查異常對象。 三、程序出現錯誤。例如,a[-1] = 0/四、Java虛擬機和運行時庫出現的內部異常。
一個方法必須聲明該方法全部可能拋出的已檢查異常,而未檢查異常要麼不可控制(Error),要麼應該避免發生(RuntimeException)。若是方法沒有聲明全部可能發生的已檢查異常,編譯器會給出一個錯誤消息。
當Java應用程序出現錯誤時,會根據錯誤類型產生一個異常對象,這個對象包含了異常的類型和錯誤出現時程序所處的狀態信息。把異常對象遞交給Java編譯器的過程稱爲拋出。拋出異常要生成異常對象,異常對象可由某些類的實例生成,也能夠由JVM生成。拋出異常對象經過throw語句來實現。
如何拋出異常:首先決定拋出異常類型。例如:當從一個長爲 1024的文件中讀取數據時,但讀到733時遇到了文件結束標記,此時應拋出一個異常,EOFException比較合適。代碼爲:throw new EOFException(); 或者: EOFException e= new EOFException(); throw e;
對於已存在的異常類,拋出該類的異常對象很是容易,步驟是:找到一個合適的異常類;建立這個類的一個對象;將該對象拋出。一個方法拋出了異常後,它就不能返回調用者了。
建立異常類:自定義異常類:定義一個派生於Exception的直接或間接子類。如一個派生於IOException的類。自定義的異常類應該包括兩個構造器:默認構造器;帶有詳細描述信息的構造器(超類Throwable的toString方法會打印出這些詳細信息,有利於代碼調試)
程序運行期間,異常發生時,Java運行系統從異常生成的代碼塊開始,尋找相應的異常處理代碼,並將異常交給該方法處理,這一過程叫做捕獲。某個異常發生時,若程序沒有在任何地方進行該異常的捕獲,則程序就會終止執行,並在控制檯上輸出異常信息。若要捕獲一個異常,須要在程序中設置一個try/catch/ finally塊: try語句括住可能拋出異常的代碼段。catch語句指明要捕獲的異常及相應的處理代碼。finally語句指明必須執行的程序塊。
try子句:捕獲異常的第一步是用try{…}子句選定捕獲異常的代碼範圍,由try所限定的代碼塊中的語句在執行過程當中可能會自動生成異常對象並拋出。對於異常處理,能夠捕獲,也能夠只聲明拋出不做任何處理。
catch子句:catch塊是對異常對象進行處理的代碼;每一個try代碼塊能夠伴隨一個或多個catch語句,用於處理 try代碼塊中所生成的各種異常事件;catch語句只須要一個形式參數指明它所能捕獲的異常類對象,這個異常類必須是Throwable的子類,運行時系統經過參數值把被拋出的異常對象傳遞給catch塊;catch塊能夠經過異常對象調用類Throwable所提供的方法。getMessage()用來獲得有關異常事件的信息;printStackTrace()用來跟蹤異常事件發生時執行堆棧的內容。
能夠在一個try塊中捕獲多個異常類型,每一個異常類型須要個單獨的catch子句。
try{ 拋出異常代碼}
catch(ExceptionType1 e1){ 拋出exceptionType1時要執行的代碼 }
catch(ExceptionType2 e2){ 拋出exceptionType2時要執行的代碼 }
catch(ExceptionType3 e3){ 拋出exceptionType3時要執行的代碼 }
catch語句的順序:捕獲異常的順序和不一樣catch語句的順序有關,當捕獲到一個異常時。剩下的catch語句就再也不進行匹配。所以在安排catch語句的順序時,首先應該捕獲最特殊的異常,而後在逐漸通常化,也就是通常先安排子類,再安排父類。
再次拋出異常與異常鏈catch子句中也能夠拋出一個異常,這樣作的目的是改變異常的類型。
finally子句:捕獲異常的最後一步是經過finally語句爲異常處理提供一個統一的出口,使得控制流程在轉到程序其它部分之前,可以對程序的狀態作統一的管理。不論在 try代碼塊中是否發生了異常事件,finally塊中的語句都會被執行。
Java異常捕獲處理代碼的通常形式是: try {//括號內爲被監視程序塊 }
catch(異常類1 e1){//括號內爲處理異常類1的程序塊}
catch(異常類2 e2){//括號內爲處理異常類2的程序塊}
… …
catch (異常類n en){//括號內爲處理異常類n的程序塊}
finally {//括號內爲必需要執行的程序塊 }
程序編碼時異常處理的兩種方式:積極處理方式:確切知道如何處理的異常應該捕獲;消極處理方式:不知道如何去處理的異常聲明拋出。
異常處理的原則:(1) 異常處理不能代替簡單的條件檢測,只在異常狀況下使用異常機制。(2) 程序代碼不要過度細化異常,儘可能將有可能產生異常的語句放在一個try語句塊中。(3) 拋出的異常類型儘量明確。(4) 不要壓制異常,對於不多發生的異常,應該將其關閉。(5) 早拋出,晚捕獲,儘可能讓高層次的方法通告用戶發生了錯誤。
2、實驗部分
1、實驗目的與要求
(1) 掌握java異常處理技術;
(2) 瞭解斷言的用法;
(3) 瞭解日誌的用途;
(4) 掌握程序基礎調試技巧;
2、實驗內容和步驟
實驗1:用命令行與IDE兩種環境下編輯調試運行源程序ExceptionDemo一、ExceptionDemo2,結合程序運行結果理解程序,掌握未檢查異常和已檢查異常的區別。
//異常示例1 public class ExceptionDemo1 { public static void main(String args[]) { int a = 0; System.out.println(5 / a); } } |
//異常示例2 import java.io.*;
public class ExceptionDemo2 { public static void main(String args[]) { FileInputStream fis=new FileInputStream("text.txt");//JVM自動生成異常對象 int b; while((b=fis.read())!=-1) { System.out.print(b); } fis.close(); } } |
//異常示例1 public class ExceptionDemo1 { public static void main(String args[]) { int a = 0; if(a==0) { System.out.println("除數爲零"); } else { System.out.println(5 / a); } } }
//異常示例2 import java.io.*; public class ExceptionDemo1 { public static void main(String args[]) throws IOException { FileInputStream fis=new FileInputStream("text.txt");//JVM自動生成異常對象 int b; while((b=fis.read())!=-1) { System.out.print(b); } fis.close(); } }
實驗2: 導入如下示例程序,測試程序並進行代碼註釋。
測試程序1:
l 在elipse IDE中編輯、編譯、調試運行教材281頁7-1,結合程序運行結果理解程序;
l 在程序中相關代碼處添加新知識的註釋;
l 掌握Throwable類的堆棧跟蹤方法;
package stackTrace; import java.util.*; /** * A program that displays a trace feature of a recursive method call. * @version 1.01 2004-05-10 * @author Cay Horstmann */ public class StackTraceTest { /** * Computes the factorial of a number * @param n a non-negative integer * @return n! = 1 * 2 * . . . * n */ public static int factorial(int n) { System.out.println("factorial(" + n + "):"); Throwable t = new Throwable(); StackTraceElement[] frames = t.getStackTrace(); for (StackTraceElement f : frames) System.out.println(f); int r; if (n <= 1) r = 1; else r = n * factorial(n - 1); System.out.println("return " + r); return r; } public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.print("Enter n: "); int n = in.nextInt(); factorial(n); } }
測試程序2:
l Java語言的異常處理有積極處理方法和消極處理兩種方式;
l 下列兩個簡答程序範例給出了兩種異常處理的代碼格式。在elipse IDE中編輯、調試運行源程序ExceptionalTest.java,將程序中的text文件更換爲身份證號.txt,要求將文件內容讀入內容,並在控制檯顯示;
l 掌握兩種異常處理技術的特色。
//積極處理方式 import java.io.*;
class ExceptionTest { public static void main (string args[]) { try{ FileInputStream fis=new FileInputStream("text.txt"); } catch(FileNotFoundExcption e) { …… } …… } } |
//消極處理方式
import java.io.*; class ExceptionTest { public static void main (string args[]) throws FileNotFoundExcption { FileInputStream fis=new FileInputStream("text.txt"); } } |
//積極處理 import java.io.*; class ExceptionDemo1 { public static void main (String args[]) { File fis=new File("身份證號.txt"); try{ FileReader fr = new FileReader(fis); BufferedReader br = new BufferedReader(fr); try { String s, s2 = new String(); while ((s = br.readLine()) != null) { s2 += s + "\n "; } br.close(); System.out.println(s2); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
//消極處理方式 import java.io.*; class ExceptionDemo1 { public static void main (String args[]) throws IOException { File fis=new File("身份證號.txt"); FileReader fr = new FileReader(fis); BufferedReader br = new BufferedReader(fr); String s, s2 = new String(); while ((s = br.readLine()) != null) { s2 += s + "\n "; } br.close(); System.out.println(s2); } }
實驗3: 編程練習
練習1:
l 編制一個程序,將身份證號.txt 中的信息讀入到內存中;
l 按姓名字典序輸出人員信息;
l 查詢最大年齡的人員信息;
l 查詢最小年齡人員信息;
l 輸入你的年齡,查詢身份證號.txt中年齡與你最近人的姓名、身份證號、年齡、性別和出生地;
l 查詢人員中是否有你的同鄉;
l 在以上程序適當位置加入異常捕獲代碼。
package ID; public class Person implements Comparable<Person> { private String name; private String ID; private int age; private String sex; private String birthplace; public String getname() { return name; } public void setname(String name) { this.name = name; } public String getID() { return ID; } public void setID(String ID) { this.ID= ID; } public int getage() { return age; } public void setage(int age) { this.age= age; } public String getsex() { return sex; } public void setsex(String sex) { this.sex= sex; } public String getbirthplace() { return birthplace; } public void setbirthplace(String birthplace) { this.birthplace= birthplace; } public int compareTo(Person o) { return this.name.compareTo(o.getname()); } public String toString() { return name+"\t"+sex+"\t"+age+"\t"+ID+"\t"+birthplace+"\n"; } } package ID; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Scanner; public class Main{ private static ArrayList<Person> Personlist; public static void main(String[] args) { Personlist = new ArrayList<>(); Scanner scanner = new Scanner(System.in); File file = new File("C:\\mydirectory\\身份證號.txt"); try { FileInputStream fis = new FileInputStream(file); BufferedReader in = new BufferedReader(new InputStreamReader(fis)); String temp = null; while ((temp = in.readLine()) != null) { Scanner linescanner = new Scanner(temp); linescanner.useDelimiter(" "); String name = linescanner.next(); String ID = linescanner.next(); String sex = linescanner.next(); String age = linescanner.next(); String place =linescanner.nextLine(); Person Person = new Person(); Person.setname(name); Person.setID(ID); Person.setsex(sex); int a = Integer.parseInt(age); Person.setage(a); Person.setbirthplace(place); Personlist.add(Person); } } catch (FileNotFoundException e) { System.out.println("查找不到信息"); e.printStackTrace(); } catch (IOException e) { System.out.println("信息讀取有誤"); e.printStackTrace(); } boolean isTrue = true; while (isTrue) { System.out.println("1:按姓名字典序輸出人員信息"); System.out.println("2:查詢最大年齡與最小年齡人員信息"); System.out.println("3:按省份找同鄉"); System.out.println("4:輸入你的年齡,查詢年齡與你最近人的信息"); System.out.println("5:退出"); int nextInt = scanner.nextInt(); switch (nextInt) { case 1: Collections.sort(Personlist); System.out.println(Personlist.toString()); break; case 2: int max=0,min=100;int j,k1 = 0,k2=0; for(int i=1;i<Personlist.size();i++) { j=Personlist.get(i).getage(); if(j>max) { max=j; k1=i; } if(j<min) { min=j; k2=i; } } System.out.println("年齡最大:"+Personlist.get(k1)); System.out.println("年齡最小:"+Personlist.get(k2)); break; case 3: System.out.println("省份?"); String find = scanner.next(); String place=find.substring(0,3); String place2=find.substring(0,3); for (int i = 0; i <Personlist.size(); i++) { if(Personlist.get(i).getbirthplace().substring(1,4).equals(place)) System.out.println("同鄉 "+Personlist.get(i)); } break; case 4: System.out.println("年齡:"); int yourage = scanner.nextInt(); int near=agenear(yourage); int d_value=yourage-Personlist.get(near).getage(); System.out.println(""+Personlist.get(near)); break; case 5: isTrue = false; System.out.println("歡迎使用!"); break; default: System.out.println("輸入有誤"); } } } public static int agenear(int age) { int j=0,min=53,d_value=0,k=0; for (int i = 0; i < Personlist.size(); i++) { d_value=Personlist.get(i).getage()-age; if(d_value<0) d_value=-d_value; if (d_value<min) { min=d_value; k=i; } } return k; } }
注:如下實驗課後完成
練習2:
l 編寫一個計算器類,能夠完成加、減、乘、除的操做;
l 利用計算機類,設計一個小學生100之內數的四則運算練習程序,由計算機隨機產生10道加減乘除練習題,學生輸入答案,由程序檢查答案是否正確,每道題正確計10分,錯誤不計分,10道題測試結束後給出測試總分;
l 將程序中測試練習題及學生答題結果輸出到文件,文件名爲test.txt;
l 在以上程序適當位置加入異常捕獲代碼。
public class math { private int a; private int b; public static int add(int a,int b) { return a+b; } public static int reduce(int a,int b) { return a-b; } public static int multiplication(int a,int b) { return a*b; } public static int division(int a,int b) { if(b!=0) return a/b; else return 0; } }
import java.io.*; import java.io.PrintWriter; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); PrintWriter out = null; try { out = new PrintWriter("text.txt"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } int sum = 0; for (int i = 1; i <=10; i++) { int a = (int) Math.round(Math.random() * 100); int b = (int) Math.round(Math.random() * 100); int m = (int) Math.round(Math.random()*4); switch(m) { case 1: System.out.println(i+": "+a+"/"+b+"="); while(b==0){ b = (int) Math.round(Math.random() * 100); } int c1 = in.nextInt(); if (c1 == a / b) { System.out.println("恭喜答案正確"); sum += 10; } else { System.out.println("抱歉,答案錯誤"); } break; case 2: System.out.println(i+": "+a+"*"+b+"="); int c2 = in.nextInt(); if (c2 == a * b) { System.out.println("恭喜答案正確"); sum += 10; } else { System.out.println("抱歉,答案錯誤"); } break; case 3: System.out.println(i+": "+a+"+"+b+"="); int c3 = in.nextInt(); out.println(a+"+"+b+"="+c3); if (c3 == a + b) { System.out.println("恭喜答案正確"); sum += 10; } else { System.out.println("抱歉,答案錯誤"); } break ; case 4: System.out.println(i+": "+a+"-"+b+"="); int c4 = in.nextInt(); if (c4 == a - b) { System.out.println("恭喜答案正確"); sum += 10; } else { System.out.println("抱歉,答案錯誤"); } break ; } } System.out.println("成績"+sum); } }
實驗4:斷言、日誌、程序調試技巧驗證明驗。
實驗程序1:
//斷言程序示例 public class AssertDemo { public static void main(String[] args) { test1(-5); test2(-3); }
private static void test1(int a){ assert a > 0; System.out.println(a); } private static void test2(int a){ assert a > 0 : "something goes wrong here, a cannot be less than 0"; System.out.println(a); } } |
l 在elipse下調試程序AssertDemo,結合程序運行結果理解程序;
l 註釋語句test1(-5);後從新運行程序,結合程序運行結果理解程序;
l 掌握斷言的使用特色及用法。
//斷言程序示例 public class AssertDemo { public static void main(String[] args) { test1(-5); test2(-3); } private static void test1(int a){ assert a > 0; System.out.println(a); } private static void test2(int a){ assert a > 0 : "something goes wrong here, a cannot be less than 0"; System.out.println(a); } }
實驗程序2:
l 用JDK命令調試運行教材298頁-300頁程序7-2,結合程序運行結果理解程序;
l 並掌握Java日誌系統的用途及用法。
package logging; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.logging.*; import javax.swing.*; /** * A modification of the image viewer program that logs various events. * @version 1.03 2015-08-20 * @author Cay Horstmann */ public class LoggingImageViewer { public static void main(String[] args) { if (System.getProperty("java.util.logging.config.class") == null && System.getProperty("java.util.logging.config.file") == null) { try { Logger.getLogger("com.horstmann.corejava").setLevel(Level.ALL); final int LOG_ROTATION_COUNT = 10; Handler handler = new FileHandler("%h/LoggingImageViewer.log", 0, LOG_ROTATION_COUNT); Logger.getLogger("com.horstmann.corejava").addHandler(handler); } catch (IOException e) { Logger.getLogger("com.horstmann.corejava").log(Level.SEVERE, "Can't create log file handler", e); } } EventQueue.invokeLater(() -> { Handler windowHandler = new WindowHandler(); windowHandler.setLevel(Level.ALL); Logger.getLogger("com.horstmann.corejava").addHandler(windowHandler); JFrame frame = new ImageViewerFrame(); frame.setTitle("LoggingImageViewer"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Logger.getLogger("com.horstmann.corejava").fine("Showing frame"); frame.setVisible(true); }); } } /** * The frame that shows the image. */ class ImageViewerFrame extends JFrame { private static final int DEFAULT_WIDTH = 300; private static final int DEFAULT_HEIGHT = 400; private JLabel label; private static Logger logger = Logger.getLogger("com.horstmann.corejava"); public ImageViewerFrame() { logger.entering("ImageViewerFrame", "<init>"); setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); // set up menu bar JMenuBar menuBar = new JMenuBar(); setJMenuBar(menuBar); JMenu menu = new JMenu("File"); menuBar.add(menu); JMenuItem openItem = new JMenuItem("Open"); menu.add(openItem); openItem.addActionListener(new FileOpenListener()); JMenuItem exitItem = new JMenuItem("Exit"); menu.add(exitItem); exitItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { logger.fine("Exiting."); System.exit(0); } }); // use a label to display the images label = new JLabel(); add(label); logger.exiting("ImageViewerFrame", "<init>"); } private class FileOpenListener implements ActionListener { public void actionPerformed(ActionEvent event) { logger.entering("ImageViewerFrame.FileOpenListener", "actionPerformed", event); // set up file chooser JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(new File(".")); // accept all files ending with .gif chooser.setFileFilter(new javax.swing.filechooser.FileFilter() { public boolean accept(File f) { return f.getName().toLowerCase().endsWith(".gif") || f.isDirectory(); } public String getDescription() { return "GIF Images"; } }); // show file chooser dialog int r = chooser.showOpenDialog(ImageViewerFrame.this); // if image file accepted, set it as icon of the label if (r == JFileChooser.APPROVE_OPTION) { String name = chooser.getSelectedFile().getPath(); logger.log(Level.FINE, "Reading file {0}", name); label.setIcon(new ImageIcon(name)); } else logger.fine("File open dialog canceled."); logger.exiting("ImageViewerFrame.FileOpenListener", "actionPerformed"); } } } /** * A handler for displaying log records in a window. */ class WindowHandler extends StreamHandler { private JFrame frame; public WindowHandler() { frame = new JFrame(); final JTextArea output = new JTextArea(); output.setEditable(false); frame.setSize(200, 200); frame.add(new JScrollPane(output)); frame.setFocusableWindowState(false); frame.setVisible(true); setOutputStream(new OutputStream() { public void write(int b) { } // not called public void write(byte[] b, int off, int len) { output.append(new String(b, off, len)); } }); } public void publish(LogRecord record) { if (!frame.isVisible()) return; super.publish(record); flush(); } }
實驗程序3:
l 用JDK命令調試運行教材298頁-300頁程序7-2,結合程序運行結果理解程序;
l 按課件66-77內容練習並掌握Elipse的經常使用調試技術。
3、實驗總結:經過此次實驗我瞭解了異常,對於積極處理和消極處理方法還不是很會,對於JDK命令調試和Elipse的經常使用調試技術並非很熟悉。編程須要多加練習,對於以前所學的知識須要多加回顧,查漏補缺·。