第一部分:理論知識學習部分
第7章異常、日志、斷言和調試
概念:異常、異常類型、異常聲明、異常拋出、 異常捕獲
1.異常處理技術
2.斷言的概念及使用
3.基本的調試技巧
1)異常的概念
a.Java的異常處理機制可以控制程序從錯誤產生的 位置轉移到能夠進行錯誤處理的位置。
b.程序中出現的常見的錯誤和問題有:用戶輸入錯誤 ;設備錯誤 ;物理限制 ;代碼錯誤。
2)異常分類:
a.非致命異常:通過某種修正后程序還能繼續執行。 這類錯誤叫作異常。如:文件不存在、無效的數組 下標、空引用、網絡斷開、打印機脫機、磁盤滿等。 Java中提供了一種獨特的處理異常的機制,通過異 常來處理程序設計中出現的錯誤。
b.致命異常:程序遇到了非常嚴重的不正常狀態,不 能簡單恢復執行,是致命性錯誤。如:內存耗盡、 系統內部錯誤等。這種錯誤程序本身無法解決。
3) Java中所有的異常類都直接或間接地繼承于 Throwable類。除內置異常類外,程序員可自定義異 常類。
Java中的異常類可分為兩大類:
a.Error Error類層次結構描述了Java運行時系統的內部錯誤 和資源耗盡錯誤。應用程序不應該捕獲這類異常,也 不會拋出這種異常。
b.Exception Exception類:重點掌握的異常類。Exception層次結 構又分解為兩個分支:一個分支派生于 RuntimeException;另一個分支包含其他異常
第二部分:實驗部分?——異常、斷言與日志
1、實驗目的與要求
(1)?掌握java異常處理技術;
(2)?了解斷言的用法;
(3)?了解日志的用途;
(4)?掌握程序基礎調試技巧;
2、實驗內容和步驟
實驗1:用命令行與IDE兩種環境下編輯調試運行源程序ExceptionDemo1、ExceptionDemo2,結合程序運行結果理解程序,掌握未檢查異常和已檢查異常的區別。
1 //異常示例1 2 public class ExceptionDemo1 { 3 public static void main(String args[]) { 4 int a = 0; 5 System.out.println(5 / a); 6 } 7 }
1 //異常示例2 2 import java.io.*; 3 4 public class ExceptionDemo2 { 5 public static void main(String args[]) 6 { 7 FileInputStream fis=new FileInputStream("text.txt");//JVM自動生成異常對象 8 int b; 9 while((b=fis.read())!=-1) 10 { 11 System.out.print(b); 12 } 13 fis.close(); 14 } 15 }
檢查異常后:
1 package 異常; 2 3 //異常示例1 4 public class ExceptionDemo1 { 5 public static void main(String args[]) { 6 int a=0; 7 if(a==0) { 8 System.out.println("除數為零!"); 9 } 10 else { 11 System.out.println(5 / a); 12 13 } 14 } 15 }
1 package 異常; 2 3 //異常示例2 4 import java.io.*; 5 6 public class ExceptionDemo2 { 7 public static void main(String args[]) throws Exception 8 { 9 FileInputStream fis=new FileInputStream("text.txt");//JVM自動生成異常對象 10 int b; 11 while((b=fis.read())!=-1) 12 { 13 System.out.print(b); 14 } 15 fis.close(); 16 } 17 }
在項目文件夾中添加相應的TXT文件
實驗2:?導入以下示例程序,測試程序并進行代碼注釋。
測試程序1:
1.在elipse?IDE中編輯、編譯、調試運行教材281頁7-1,結合程序運行結果理解程序;
2.在程序中相關代碼處添加新知識的注釋;
3.掌握Throwable類的堆棧跟蹤方法;
?7-1代碼如下:
1 package stackTrace; 2 3 import java.util.*; 4 5 /** 6 * A program that displays a trace feature of a recursive method call. 7 * @version 1.01 2004-05-10 8 * @author Cay Horstmann 9 */ 10 public class StackTraceTest 11 { 12 /** 13 * Computes the factorial of a number 14 * @param n a non-negative integer 15 * @return n! = 1 * 2 * . . . * n 16 */ 17 public static int factorial(int n) 18 { 19 System.out.println("factorial(" + n + "):"); 20 Throwable t = new Throwable();//調用Throwable類的getStackTrace方法,得到StackTraceElement對象的一個數組 21 StackTraceElement[] frames = t.getStackTrace(); 22 for (StackTraceElement f : frames) 23 System.out.println(f); 24 int r; 25 if (n <= 1) r = 1; 26 else r = n * factorial(n - 1); 27 System.out.println("return " + r); 28 return r; 29 } 30 31 public static void main(String[] args) 32 { 33 Scanner in = new Scanner(System.in); 34 System.out.print("Enter n: "); 35 int n = in.nextInt(); 36 factorial(n); 37 } 38 }
?
?程序運行結果如下:
?
測試程序2:
1.Java語言的異常處理有積極處理方法和消極處理兩種方式;
2.下列兩個簡答程序范例給出了兩種異常處理的代碼格式。在elipse?IDE中編輯、調試運行源程序ExceptionalTest.java,將程序中的text文件更換為身份證號.txt,要求將文件內容讀入內容,并在控制臺顯示;
3.掌握兩種異常處理技術的特點。
1 //積極處理方式 2 import java.io.*; 3 4 class ExceptionTest { 5 public static void main (string args[]) 6 { 7 try{ 8 FileInputStream fis=new FileInputStream("text.txt"); 9 } 10 catch(FileNotFoundExcption e) 11 { …… } 12 …… 13 } 14 }
1 //消極處理方式 2 3 import java.io.*; 4 class ExceptionTest { 5 public static void main (string args[]) throws FileNotFoundExcption 6 { 7 FileInputStream fis=new FileInputStream("text.txt"); 8 } 9 }
讀入內容后:
1 package 異常; 2 3 //積極處理方式 4 import java.io.*; 5 import java.io.BufferedReader; 6 import java.io.FileReader; 7 8 class ExceptionTest { 9 public static void main (String args[]) 10 { 11 File fis=new File("身份證號.txt"); 12 try{ 13 14 15 FileReader fr = new FileReader(fis); 16 BufferedReader br = new BufferedReader(fr); 17 try { 18 String s, s2 = new String(); 19 while ((s = br.readLine()) != null) { 20 s2 += s + "\n "; 21 } 22 br.close(); 23 System.out.println(s2); 24 } catch (IOException e) { 25 // TODO Auto-generated catch block 26 e.printStackTrace(); 27 } 28 } catch (FileNotFoundException e) { 29 // TODO Auto-generated catch block 30 e.printStackTrace(); 31 } 32 33 } 34 }
?
1 package 異常; 2 3 //消極處理方式 4 5 import java.io.*; 6 class ExceptionTest { 7 public static void main (String args[]) throws IOException 8 { 9 File fis=new File("身份證號.txt"); 10 FileReader fr = new FileReader(fis); 11 BufferedReader br = new BufferedReader(fr); 12 String s, s2 = new String(); 13 14 while ((s = br.readLine()) != null) { 15 s2 += s + "\n "; 16 } 17 br.close(); 18 System.out.println(s2); 19 } 20 }
?
?
實驗3: 編程練習
練習1:
1.編制一個程序,將身份證號.txt 中的信息讀入到內存中;
2.按姓名字典序輸出人員信息;
3.查詢最大年齡的人員信息;
4.查詢最小年齡人員信息;
5.輸入你的年齡,查詢身份證號.txt中年齡與你最近人的姓名、身份證號、年齡、性別和出生地;
6.查詢人員中是否有你的同鄉;
在以上程序適當位置加入異常捕獲代碼。
?
?
1 package IDcard; 2 3 import java.io.BufferedReader; 4 import java.io.File; 5 import java.io.FileInputStream; 6 import java.io.FileNotFoundException; 7 import java.io.IOException; 8 import java.io.InputStreamReader; 9 import java.util.ArrayList; 10 import java.util.Scanner; 11 import java.util.Collections; 12 13 public class ID { 14 15 public static People findPeopleByname(String name) { 16 People flag = null; 17 for (People people : peoplelist) { 18 if(people.getName().equals(name)) { 19 flag = people; 20 } 21 } 22 return flag; 23 24 } 25 26 public static People findPeopleByid(String id) { 27 People flag = null; 28 for (People people : peoplelist) { 29 if(people.getnumber().equals(id)) { 30 flag = people; 31 } 32 } 33 return flag; 34 35 } 36 37 private static ArrayList<People> agenear(int yourage) { 38 // TODO Auto-generated method stub 39 int j=0,min=53,d_value=0,k = 0; 40 ArrayList<People> plist = new ArrayList<People>(); 41 for (int i = 0; i < peoplelist.size(); i++) { 42 d_value = peoplelist.get(i).getage() > yourage ? 43 peoplelist.get(i).getage() - yourage : yourage - peoplelist.get(i).getage() ; 44 k = d_value < min ? i : k; 45 min = d_value < min ? d_value : min; 46 } 47 for(People people : peoplelist) { 48 if(people.getage() == peoplelist.get(k).getage()) { 49 plist.add(people); 50 } 51 } 52 return plist; 53 } 54 55 private static ArrayList<People> peoplelist; 56 57 public static void main(String[] args) //throws IOException 58 { 59 peoplelist = new ArrayList<People>(); 60 Scanner scanner = new Scanner(System.in); 61 File file = new File("D:\\身份證號.txt"); 62 try { 63 FileInputStream files = new FileInputStream(file); 64 BufferedReader in = new BufferedReader(new InputStreamReader(files)); 65 String temp = null; 66 while ((temp = in.readLine()) != null) { 67 68 String[] information = temp.split("[ ]+"); 69 People people = new People(); 70 people.setName(information[0]); 71 people.setnumber(information[1]); 72 int A = Integer.parseInt(information[3]); 73 people.setage(A); 74 people.setsex(information[2]); 75 for(int j = 4; j<information.length;j++) { 76 people.setplace(information[j]); 77 } 78 peoplelist.add(people); 79 80 } 81 } catch (FileNotFoundException e) { 82 System.out.println("文件未找到"); 83 e.printStackTrace(); 84 } catch (IOException e) { 85 System.out.println("文件讀取錯誤"); 86 e.printStackTrace(); 87 } 88 boolean isTrue = true; 89 while (isTrue) { 90 91 System.out.println("******************************************"); 92 System.out.println(" 1.按姓名典序輸出人員信息"); 93 System.out.println(" 2.查詢最大年齡人員信息"); 94 System.out.println(" 3.查詢最小年齡人員信息"); 95 System.out.println(" 4.輸入你的年齡,查詢身份證號.txt中年齡與你最近的人"); 96 System.out.println(" 5.查詢人員中是否有你的同鄉"); 97 System.out.println(" 6.退出"); 98 System.out.println("******************************************"); 99 int nextInt = scanner.nextInt(); 100 switch (nextInt) { 101 case 1: 102 Collections.sort(peoplelist); 103 System.out.println(peoplelist.toString()); 104 break; 105 case 2: 106 int max=0; 107 int j,k1 = 0; 108 for(int i=1;i<peoplelist.size();i++) 109 { 110 j = peoplelist.get(i).getage(); 111 if(j>max) 112 { 113 max = j; 114 k1 = i; 115 } 116 117 } 118 System.out.println("年齡最大:"+peoplelist.get(k1)); 119 break; 120 case 3: 121 int min = 100; 122 int j1,k2 = 0; 123 for(int i=1;i<peoplelist.size();i++) 124 { 125 j1 = peoplelist.get(i).getage(); 126 if(j1<min) 127 { 128 min = j1; 129 k2 = i; 130 } 131 132 } 133 System.out.println("年齡最小:"+peoplelist.get(k2)); 134 break; 135 case 4: 136 System.out.println("年齡:"); 137 int input_age = scanner.nextInt(); 138 ArrayList<People> plist = new ArrayList<People>(); 139 plist = agenear(input_age); 140 for(People people : plist) { 141 System.out.println(people.toString()); 142 } 143 break; 144 case 5: 145 System.out.println("請輸入省份"); 146 String find = scanner.next(); 147 for (int i = 0; i <peoplelist.size(); i++) 148 { 149 String [] place = peoplelist.get(i).getplace().split("\t"); 150 for(String temp : place) { 151 if(find.equals(temp)) { 152 System.out.println("你的同鄉是 "+peoplelist.get(i)); 153 break; 154 } 155 } 156 157 } 158 break; 159 case 6: 160 isTrue = false; 161 System.out.println("byebye!"); 162 break; 163 default: 164 System.out.println("輸入有誤"); 165 } 166 } 167 } 168 169 }
?
練習2:
1.編寫一個計算器類,可以完成加、減、乘、除的操作;
2.利用計算機類,設計一個小學生100以內數的四則運算練習程序,由計算機隨機產生10道加減乘除練習題,學生輸入答案,由程序檢查答案是否正確,每道題正確計10分,錯誤不計分,10道題測試結束后給出測試總分;
3.將程序中測試練習題及學生答題結果輸出到文件,文件名為test.txt;
4.在以上程序適當位置加入異常捕獲代碼。
?
程序如下:
1 package 算術題; 2 3 import java.io.FileNotFoundException; 4 import java.io.PrintWriter; 5 import java.util.Scanner; 6 7 8 public class ss { 9 public static void main(String[] args) { 10 11 Scanner in = new Scanner(System.in); 12 sf sf=new sf(); 13 PrintWriter output = null; 14 try { 15 output = new PrintWriter("ss.txt"); 16 } catch (Exception e) { 17 //e.printStackTrace(); 18 } 19 int sum = 0; 20 21 for (int i = 1; i < 11; i++) { 22 int a = (int) Math.round(Math.random() * 100); 23 int b = (int) Math.round(Math.random() * 100); 24 int s = (int) Math.round(Math.random() * 4); 25 26 27 switch(s) 28 { 29 case 1: 30 System.out.println(i+": "+a+"/"+b+"="); 31 while(b==0){ 32 b = (int) Math.round(Math.random() * 100); 33 } 34 double c = in.nextDouble(); 35 output.println(a+"/"+b+"="+c); 36 if (c == sf.chu_fa(a, b)) { 37 sum += 10; 38 System.out.println("恭喜答案正確"); 39 } 40 else { 41 System.out.println("抱歉,答案錯誤"); 42 } break; 45 46 case 2: 47 System.out.println(i+": "+a+"*"+b+"="); 48 int c1 = in.nextInt(); 49 output.println(a+"*"+b+"="+c1); 50 if (c1 == sf.chen_fa(a, b)) { 51 sum += 10; 52 System.out.println("恭喜答案正確"); 53 } 54 else { 55 System.out.println("抱歉,答案錯誤"); 56 }break;
58 case 3: 59 System.out.println(i+": "+a+"+"+b+"="); 60 int c2 = in.nextInt(); 61 output.println(a+"+"+b+"="+c2); 62 if (c2 == sf.jia_fa(a, b)) { 63 sum += 10; 64 System.out.println("恭喜答案正確"); 65 } 66 else { 67 System.out.println("抱歉,答案錯誤"); 68 }break ;
71 case 4: 72 System.out.println(i+": "+a+"-"+b+"="); 73 int c3 = in.nextInt(); 74 output.println(a+"-"+b+"="+c3); 75 if (c3 == sf.jian_fa(a, b)) { 76 sum += 10; 77 System.out.println("恭喜答案正確"); 78 } 79 else { 80 System.out.println("抱歉,答案錯誤"); 81 }break ; 83 84 } 85 86 } 87 System.out.println("成績"+sum); 88 output.println("成績:"+sum); 89 output.close(); 90 91 } 92 }
package 算術題;public class sf {private int a;private int b;public int jia_fa(int a,int b){return a+b;}public int jian_fa(int a,int b){if((a-b)<0)return 0;elsereturn a-b;}public int chen_fa(int a,int b){return a*b;}public int chu_fa(int a,int b){if(b!=0)return a/b; elsereturn 0;}}
?
結果如下:
?
?
實驗4:斷言、日志、程序調試技巧驗證實驗。
實驗程序1:
1 //斷言程序示例 2 public class AssertDemo { 3 public static void main(String[] args) { 4 test1(-5); 5 test2(-3); 6 } 7 8 private static void test1(int a){ 9 assert a > 0; 10 System.out.println(a); 11 } 12 private static void test2(int a){ 13 assert a > 0 : "something goes wrong here, a cannot be less than 0"; 14 System.out.println(a); 15 } 16 }
1.在elipse下調試程序AssertDemo,結合程序運行結果理解程序;
2.注釋語句test1(-5);后重新運行程序,結合程序運行結果理解程序;
3.掌握斷言的使用特點及用法。
程序運行結果如下:
?
注釋后程序如下:
1 package stackTrace; 2 //斷言程序示例 3 public class AssertDemo { 4 public static void main(String[] args) { 5 // test1(-5); 6 test2(-3); 7 } 8 9 private static void test1(int a){ 10 assert a > 0; 11 System.out.println(a); 12 } 13 private static void test2(int a){ 14 assert a > 0 : "something goes wrong here, a cannot be less than 0"; 15 System.out.println(a); 16 } 17 } 18
結果如下:
?
實驗程序2:
1.用JDK命令調試運行教材298頁-300頁程序7-2,結合程序運行結果理解程序;
2.并掌握Java日志系統的用途及用法。
程序如下:
1 package logging; 2 3 import java.awt.*; 4 import java.awt.event.*; 5 import java.io.*; 6 import java.util.logging.*; 7 import javax.swing.*; 8 9 /** 10 * A modification of the image viewer program that logs various events. 11 * @version 1.03 2015-08-20 12 * @author Cay Horstmann 13 */ 14 public class LoggingImageViewer 15 { 16 public static void main(String[] args) 17 { 18 if (System.getProperty("java.util.logging.config.class") == null 19 && System.getProperty("java.util.logging.config.file") == null) 20 { 21 try 22 { 23 Logger.getLogger("com.horstmann.corejava").setLevel(Level.ALL); 24 final int LOG_ROTATION_COUNT = 10; 25 Handler handler = new FileHandler("%h/LoggingImageViewer.log", 0, LOG_ROTATION_COUNT); 26 Logger.getLogger("com.horstmann.corejava").addHandler(handler); 27 } 28 catch (IOException e) 29 { 30 Logger.getLogger("com.horstmann.corejava").log(Level.SEVERE, 31 "Can't create log file handler", e); 32 } 33 } 34 35 EventQueue.invokeLater(() -> 36 { 37 Handler windowHandler = new WindowHandler(); 38 windowHandler.setLevel(Level.ALL); 39 Logger.getLogger("com.horstmann.corejava").addHandler(windowHandler); 40 41 JFrame frame = new ImageViewerFrame(); 42 frame.setTitle("LoggingImageViewer"); 43 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 44 45 Logger.getLogger("com.horstmann.corejava").fine("Showing frame"); 46 frame.setVisible(true); 47 }); 48 } 49 } 50 51 /** 52 * The frame that shows the image. 53 */ 54 class ImageViewerFrame extends JFrame 55 { 56 private static final int DEFAULT_WIDTH = 300; 57 private static final int DEFAULT_HEIGHT = 400; 58 59 private JLabel label; 60 private static Logger logger = Logger.getLogger("com.horstmann.corejava"); 61 62 public ImageViewerFrame() 63 { 64 logger.entering("ImageViewerFrame", "<init>"); 65 setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); 66 67 // set up menu bar 68 JMenuBar menuBar = new JMenuBar(); 69 setJMenuBar(menuBar); 70 71 JMenu menu = new JMenu("File"); 72 menuBar.add(menu); 73 74 JMenuItem openItem = new JMenuItem("Open"); 75 menu.add(openItem); 76 openItem.addActionListener(new FileOpenListener()); 77 78 JMenuItem exitItem = new JMenuItem("Exit"); 79 menu.add(exitItem); 80 exitItem.addActionListener(new ActionListener() 81 { 82 public void actionPerformed(ActionEvent event) 83 { 84 logger.fine("Exiting."); 85 System.exit(0); 86 } 87 }); 88 89 // use a label to display the images 90 label = new JLabel(); 91 add(label); 92 logger.exiting("ImageViewerFrame", "<init>"); 93 } 94 95 private class FileOpenListener implements ActionListener 96 { 97 public void actionPerformed(ActionEvent event) 98 { 99 logger.entering("ImageViewerFrame.FileOpenListener", "actionPerformed", event); 100 101 // set up file chooser 102 JFileChooser chooser = new JFileChooser(); 103 chooser.setCurrentDirectory(new File(".")); 104 105 // accept all files ending with .gif 106 chooser.setFileFilter(new javax.swing.filechooser.FileFilter() 107 { 108 public boolean accept(File f) 109 { 110 return f.getName().toLowerCase().endsWith(".gif") || f.isDirectory(); 111 } 112 113 public String getDescription() 114 { 115 return "GIF Images"; 116 } 117 }); 118 119 // show file chooser dialog 120 int r = chooser.showOpenDialog(ImageViewerFrame.this); 121 122 // if image file accepted, set it as icon of the label 123 if (r == JFileChooser.APPROVE_OPTION) 124 { 125 String name = chooser.getSelectedFile().getPath(); 126 logger.log(Level.FINE, "Reading file {0}", name); 127 label.setIcon(new ImageIcon(name)); 128 } 129 else logger.fine("File open dialog canceled."); 130 logger.exiting("ImageViewerFrame.FileOpenListener", "actionPerformed"); 131 } 132 } 133 } 134 135 /** 136 * A handler for displaying log records in a window. 137 */ 138 class WindowHandler extends StreamHandler 139 { 140 private JFrame frame; 141 142 public WindowHandler() 143 { 144 frame = new JFrame(); 145 final JTextArea output = new JTextArea(); 146 output.setEditable(false); 147 frame.setSize(200, 200); 148 frame.add(new JScrollPane(output)); 149 frame.setFocusableWindowState(false); 150 frame.setVisible(true); 151 setOutputStream(new OutputStream() 152 { 153 public void write(int b) 154 { 155 } // not called 156 157 public void write(byte[] b, int off, int len) 158 { 159 output.append(new String(b, off, len)); 160 } 161 }); 162 } 163 164 public void publish(LogRecord record) 165 { 166 if (!frame.isVisible()) return; 167 super.publish(record); 168 flush(); 169 } 170 }
程序運行結果如下:
?
實驗程序3:
1.用JDK命令調試運行教材298頁-300頁程序7-2,結合程序運行結果理解程序;
2.按課件66-77內容練習并掌握Elipse的常用調試技術。
1)條件斷點?
添加斷點:
點擊Breakpoint Properties后:
2)變量斷點
斷點不僅能打在語句上,變量也可以接受斷點:
上圖就是一個變量的打的斷點,在變量的值初 始化,或是變量值改變時可以停止,當然變量 斷點上也是可以加條件的,和上面的介紹的條 件斷點的設置是一樣的。
3)方法斷點
方法斷點就是將斷點打在方法的入口處:
方法斷點的特別之處在于它可以打在JDK的源 碼里,由于JDK在編譯時去掉了調試信息,所 以普通斷點是不能打到里面的,但是方法斷點 卻可以,可以通過這種方法查看方法的調用棧。
4)異常斷點
經常遇見一些異常,然后程序就退出來了,要找到異常發生的地方就比較難了,還好可以打一個異常斷點。
上圖中我們增加了一個NullPointException的異常斷點,當異常發生時,代碼會停在異常發生處,定位問題時應該比較有幫助。
5)重新調試
6)單步執行程序?
7)檢查變量
8)改變變量值
第三部分:總結
通過本周的學習,我掌握了java異常處理的一些基礎技術;通過調試理解書上的示例程序,再加上老師助、教學長的演示講解,更好的使我理解這一章的知識。課后的自主編程也是在學長提供思路的基礎上理解之后,補充完整的,本周除了慣例的編程練習外,重點是學習Java異常處理技術,更好的運用eclipse這個工具為我們編程提供服務。