201871010111-劉佳華《面向對象程序設計(java)》第十週學習總結java
實驗八 異常、斷言與日誌編程
實驗時間 2019-11-1數組
一、實驗目的與要求網絡
(1) 掌握java異常處理技術;app
(2) 瞭解斷言的用法;less
(3) 瞭解日誌的用途;dom
(4) 掌握程序基礎調試技巧;ide
一:理論部分。函數
錯誤類型:1)用戶輸入錯誤;2)設備錯誤;3)物理限制;4)代碼錯誤工具
1.異常:在程序的執行過程當中所發生的異常事件,它中斷指令的正常執行。異常對象都是派生於Throwable類的一個實例。
全部異常類都是由Throwable繼承而來,在下一層分解爲兩個支:Error(致命錯誤)和Exception(非致命錯誤)。
設計java程序時,關注Exception層次結構。Exception層次結構又分解爲兩個分支:一個分支派生於RuntimeException;另外一個分支包含其餘異常。RuntimeException爲運行時異常類,通常是程序錯誤產生。
派生於RuntimeException的異常包含下面幾種狀況:
1)錯誤的類型轉換
2)數組訪問越界
3)訪問空指針
Java將派生於Error類或RuntimeException類的全部異常稱爲未檢查異常,編譯器容許不對它們作出異常處理。
2.拋出異常:聲明拋出異常在方法聲明中用throws子句中來指明。
1)throws子句能夠同時指明多個異常,說明該方法將不對這些異常進行處理,而是聲明拋出它們。
2)一個方法必須聲明該方法全部可能拋出的已檢查異常,而未檢查異常要麼不可控制(Error),要麼應該避免發生(RuntimeException)。若是方法沒有聲明全部可能發生的已檢查異常,編譯器會給出一個錯誤消息。
3)拋出異常對象經過throw語句來實現。
3.建立異常類。
自定義異常類:定義一個派生於Exception的直接或間接子類。如一個派生於IOException的類。
4.捕獲異常:
1)捕獲異常的第一步是用try{}子句選定捕獲異常的代碼範圍,由try所限定的代碼塊中的語句在執行過程當中可能會自動生成異常對象並拋出。
2)catch子句:catch塊是對異常對象進行處理的代碼;
a.每一個try代碼塊能夠伴隨一個或多個catch語句,用於處理try代碼塊中所生成的各種異常事件;
b.catch語句只須要一個形式參數指明它所能捕獲的異常類對象,這個異常類必須是Throwable的子類,運行時系統經過參數值把被拋出的異常對象傳遞給catch塊;
c.catch塊能夠經過異常對象調用類Throwable。
getMessage:用來獲得有關異常事件的信息;
printStackTrace:用來跟蹤異常事件發生時執行堆棧的內容。
5.堆棧跟蹤:程序執行中一個方法調用過程的列表,它包含了程序執行過程當中方法調用的特定位置。
6.程序編碼時異常處理的兩種方式:
1)積極處理方式:確切知道如何處理的異常應該捕獲;
2)消極處理方式:不知道如何去處理的異常聲明拋出。
5.斷言:
是程序的開發和測試階段用於插入一些代碼錯誤檢測語句的工具。
斷言(assert)語法以下:
一、assert 條件
或者
二、assert 條件:表達式
這兩個形式都會對布爾「條件」進行判斷,若是判斷結果爲假(false),說明程序已經處於不正確的狀態下,系統則拋出AssertionError,給出警告而且退出。在第二種形式中,「表達式」會傳入AssertionError的構造函數中並轉成一個消息字符
2、實驗內容和步驟
實驗1:用命令行與IDE兩種環境下編輯調試運行源程序ExceptionDemo一、ExceptionDemo2,結合程序運行結果理解程序,掌握未檢查異常和已檢查異常的區別
//異常示例1 public class ExceptionDemo1 { public static void main(String args[]) { int a = 0; System.out.println(5 / a); } }
運行截圖以下:
因分母爲零,程序在運行過程當中出現異常。修改後程序以下:
修改後代碼:
1 package TEST01; 2 3 import java.util.Scanner; 4 5 public class ExceptionDemo1 { 6 public static void main(String args[]) { 7 Scanner in = new Scanner(System.in); 8 int a =in.nextInt(); 9 if (a==0) { 10 System.out.println("input error!"); 11 } 12 else 13 System.out.println(5 / a); 14 in.close(); 15 } 16 }
運行截圖:
//異常示例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.用拋出異常方法修改後程序以下:
1 package TEST01; 2 //異常示例2 3 import java.io.*; 4 5 public class ExceptionDemo2 { 6 public static void main(String args[]) throws IOException 7 { 8 FileInputStream fis=new FileInputStream("text.txt");//JVM自動生成異常對象 9 int b; 10 while((b=fis.read())!=-1) 11 { 12 System.out.print(b); 13 } 14 fis.close(); 15 } 16 }
2.將可能出錯代碼放入try子句中程序修改後以下:
1 package TEST01; 2 import java.io.*; 3 4 public class ExceptionDemo2 { 5 public static void main(String args[]) 6 { 7 FileInputStream fis = null; 8 try { 9 fis = new FileInputStream("text.txt"); 10 } catch (FileNotFoundException e) { 11 // TODO Auto-generated catch block 12 e.printStackTrace(); 13 }//JVM自動生成異常對象 14 int b; 15 try { 16 while((b=fis.read())!=-1) 17 { 18 System.out.print(b); 19 } 20 } catch (IOException e) { 21 // TODO Auto-generated catch block 22 e.printStackTrace(); 23 } 24 try { 25 fis.close(); 26 } catch (IOException e) { 27 // TODO Auto-generated catch block 28 e.printStackTrace(); 29 } 30 } 31 }
實驗2: 導入如下示例程序,測試程序並進行代碼註釋。
測試程序1:
l 在elipse IDE中編輯、編譯、調試運行教材281頁7-1,結合程序運行結果理解程序;
l 在程序中相關代碼處添加新知識的註釋;
l 掌握Throwable類的堆棧跟蹤方法;
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.10 2017-12-14 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 + "):");//調用factorial函數 20 var walker = StackWalker.getInstance();//建立一個表示指定執行點的堆棧跟蹤元素 21 walker.forEach(System.out::println); 22 int r; 23 if (n <= 1) r = 1; 24 else r = n * factorial(n - 1);//計算n個數的階乘須要調用以前n-1個數的階乘 25 System.out.println("return " + r); 26 return r; 27 } 28 29 public static void main(String[] args) 30 { 31 try (var in = new Scanner(System.in)) 32 { 33 System.out.print("Enter n: "); 34 int n = in.nextInt(); 35 factorial(n); 36 } 37 } 38 }
運行結果:
測試程序2:
l Java語言的異常處理有積極處理方法和消極處理兩種方式;
l 下列兩個簡單程序範例給出了兩種異常處理的代碼格式。在elipse IDE中編輯、調試運行源程序ExceptionTest.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"); } } |
積極的處理方式:
1 package TEST01; 2 3 import java.io.*; 4 5 public class ExceptionTest { 6 public static void main (String args[]) 7 { 8 try{ 9 10 FileInputStream fis=new FileInputStream("身份證號.txt"); 11 BufferedReader in =new BufferedReader(new InputStreamReader(fis)); 12 String m=new String(); 13 String n=new String(); 14 while((m=in.readLine())!=null) { 15 n+=m+"\n"; 16 } 17 in.close(); 18 System.out.println(n); 19 20 } 21 catch(FileNotFoundException e) { 22 System.out.println("文件未找到"); 23 e.printStackTrace(); 24 }catch(IOException e) { 25 System.out.println("學生信息錯誤"); 26 e.printStackTrace(); 27 } 28 29 } 30 }
消極的處理方式:
1 import java.io.*; 2 public class ExceptionTest { 3 public static void main (String args[]) throws IOException 4 { 5 FileInputStream fis=new FileInputStream("身份證號.txt"); 6 BufferedReader in = new BufferedReader(new InputStreamReader(fis)); 7 String m, n = new String(); 8 while ((m = in.readLine()) != null) { 9 n += m + "\n "; 10 } 11 in.close(); 12 System.out.println(n); 13 } 14 }
運行截圖:
實驗3: 編程練習
l 編寫一個計算器類,能夠完成加、減、乘、除的操做;
l 利用計算機類,設計一個小學生100之內數的四則運算練習程序,由計算機隨機產生10道加減乘除練習題,學生輸入答案,由程序檢查答案是否正確,每道題正確計10分,錯誤不計分,10道題測試結束後給出測試總分;
l 將程序中測試練習題及學生答題結果輸出到文件,文件名爲test.txt;
l 在以上程序適當位置加入異常捕獲代碼。
分析:
代碼以下:
1 import java.io.FileNotFoundException; 2 import java.io.PrintWriter; 3 import java.util.Scanner; 4 5 public class Jisuanqi { 6 7 public static void main(String[] args) { 8 9 Scanner in=new Scanner(System.in); 10 JsQ jsq=new JsQ(); 11 PrintWriter output = null; 12 try { 13 output = new PrintWriter("題目.txt"); 14 } catch (FileNotFoundException e) { 15 e.printStackTrace(); 16 } 17 int sum = 0; 18 19 for(int i=0;i<10;i++) { 20 int s = (int) Math.round(Math.random() * 3); 21 int a = (int) Math.round(Math.random() * 100); 22 int b = (int) Math.round(Math.random() * 100); 23 switch(s) 24 { 25 case 0: 26 System.out.println( a + "/" + b + "="); 27 while (b == 0) { 28 b = (int) Math.round(Math.random() * 100); 29 } 30 double c3 = in.nextDouble(); 31 output.println(a + "/" + b + "=" + c3); 32 if (c3 ==jsq.CHUF(a, b) ) { 33 sum += 10; 34 System.out.println("恭喜你,答對了!"); 35 } else { 36 System.out.println("抱歉,答錯了!"); 37 } 38 break; 39 case 1: 40 System.out.println( a + "-" + b + "="); 41 double c1 = in.nextDouble(); 42 output.println(a + "-" + b + "=" + c1); 43 if (c1 ==jsq.GF(a, b) ) { 44 sum += 10; 45 System.out.println("恭喜你,答對了!"); 46 } else { 47 System.out.println("抱歉,答錯了!"); 48 } 49 break; 50 case 2: 51 System.out.println( a + "*" + b + "="); 52 double c2 = in.nextDouble(); 53 output.println(a + "*" + b + "=" + c2); 54 if (c2 ==jsq.CHEF(a, b) ) { 55 sum += 10; 56 System.out.println("恭喜你,答對了!"); 57 } else { 58 System.out.println("抱歉,答錯了!"); 59 } 60 break; 61 case 3: 62 System.out.println( a + "+" + b + "="); 63 double c0 = in.nextDouble(); 64 output.println(a + "+" + b + "=" + c0); 65 if (c0 ==jsq.JF (a, b)) { 66 sum += 10; 67 System.out.println("恭喜你,答對了!"); 68 } else { 69 System.out.println("抱歉,答錯了!"); 70 } 71 break; 72 } 73 74 } 75 System.out.println("你的得分爲:"+sum); 76 output.println("你的得分爲:"+sum); 77 output.close(); 78 in.close(); 79 } 80 81 }
1 class JsQ{ 2 private int a; 3 private int b; 4 5 /*public JsQ(int a,int b ){ 6 this.a=a; 7 this.b=b; 8 9 }*/ 10 public double JF(int a,int b) { 11 12 return (a+b); 13 } 14 public double GF(int a,int b) { 15 return (a-b); 16 } 17 18 public double CHEF(int a,int b) { 19 return (a*b); 20 } 21 public double CHUF(int a,int b) { 22 return (a/b); 23 } 24 }
運行結果以下:
存入文件:
實驗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 掌握斷言的使用特色及用法。
小結:
一、assert 條件
或者
二、assert 條件:表達式
這兩個形式都會對布爾「條件」進行判斷,若是判斷結果爲假(false),說明程序已經處於不正確的狀態下,系統則拋出AssertionError,給出警告而且退出。在第二種形式中,「表達式」會傳入AssertionError的構造函數中並轉成一個消息字符
實驗程序2:
l 用JDK命令調試運行教材298頁-300頁程序7-2,結合程序運行結果理解程序;
l 並掌握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 var 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 var windowHandler = new WindowHandler(); 38 windowHandler.setLevel(Level.ALL); 39 Logger.getLogger("com.horstmann.corejava").addHandler(windowHandler); 40 41 var 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 var menuBar = new JMenuBar(); 69 setJMenuBar(menuBar); 70 71 var menu = new JMenu("File"); 72 menuBar.add(menu); 73 74 var openItem = new JMenuItem("Open"); 75 menu.add(openItem); 76 openItem.addActionListener(new FileOpenListener()); 77 78 var 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 var 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 var 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:
l 用JDK命令調試運行教材298頁-300頁程序7-2,結合程序運行結果理解程序;
按課件66-77內容練習並掌握Elipse的經常使用調試技術
1)條件斷點(有必定條件的斷點):在Eclipse Java 編輯區的行頭雙擊就會獲得一個斷點,代碼會運行到此處時中止。
在斷點處點擊鼠標右鍵,選擇最後一個「Breakpoint Properties」。
2)變量斷點:在變量的值初始化,或是變量值改變時能夠中止。
3)方法斷點:方法斷點就是將斷點打在方法的入口處。
4)異常斷點:當異常發生時,代碼會停在異常發生處。
5)從新調試:回退時,請在須要回退的線程方法上點右鍵,選擇「Drop to Frame」。
6)單步執行程序
7)檢查變量
8)改變變量值
實驗總結:
經過本週的學習,對理論知識異常、日誌、斷言和調試的理論知識有了進一步的掌握,對理論知識的學習以下:
異常:程序的執行過程當中所發生的異常事件,它中斷指令的正常執行。
Java把程序運行時可能遇到的錯誤分爲兩類:非致命異常:經過某種修正後程序還能繼續執行。這類錯誤叫做異常。如:文件不存在、無效的數組下標、空引用、網絡斷開、打印機
脫機、磁盤滿等。Java中提供了一種獨特的處理異常的機制,經過異常來處理程序設計中出現的錯誤。致命異常:程序遇到了很是嚴重的不正常狀態,不能簡單恢復執行,是致命性
錯誤。如:內存耗盡、系統內部錯誤等。這種錯誤程序自己沒法解決。並且其中還有異常的兩種方式,好比說消極處理和積極處理兩種方式。
斷言:是程序的開發和測試階段用於插入一些代碼錯誤檢測語句的工具。
並且使用斷言必須注意兩點: