201871010116-祁英红《面向对象程序设计(java)》第十周学习总结
博文正文开头格式:(2分)
项目 |
内容 |
《面向对象程序设计(java)》 |
https://www.cnblogs.com/nwnu-daizh/ |
这个作业的要求在哪里 |
https://www.cnblogs.com/nwnu-daizh/p/11778090.html |
作业学习目标 |
1.掌握java异常处理技术; 2.了解断言的用法; 3.了解日志的用途; 4.掌握程序基础调试技巧。 |
随笔博文正文内容包括:
第一部分:总结第七章关于异常处理相关理论知识(20分)
一、异常
1、异常:程序执行过程中所发生的异常事件,它中断指令的正常执行。
Java的异常处理机制可以控制程序从错误产生的位置转移到能够进行错误处理的位置
程序中出现的常见错误和问题有:
(1)用户输入错误
(2)设备错误
(3)物理限制
(4)代码错误
2、java把程序运行时可能遇到的错误分为两类:
(1)非致命异常:通过某种修正后程序还能继续执行(异常)。如:文件不存在、无效的数组下标、空引用网络断开、打印机脱机、磁盘满等。Java中提供了种独特的异常处理机制处理这类错误
(2)致命异常:程序遇到了非常严重的不正常状态,不能简单恢复执行,是致命性错误。如:内存耗尽系统内部错误等。这种错误程序本身无法解决
3、Java的异常类直接或间接地继承于Throwable类。除内置异常类外,程序员可自定义异常类
Java的异常类可分为两大类
(1)error:Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该捕获这类异常,也不会抛出这种异常
(2)Exception:类是需重点掌握的异常类。层次结构又分解为两个分支分支派生于另一个分支包含其他异常。
RuntimeException为运行时异常类,一般是程序错误产生
派生于的异常包含下面几种情况
(1)错误的类型转换
(2)数组访问越界
(3)访问空指针
Java将派生于类或类的所有异常称为未检查异常,编译器允许不对它们异常处理。
注意:“如果出现异常,就一定是程序员的问题!!!”
非运行时异常中程序本身没有问题,但由于某种情况的变化,程序不能正常运行,导致异常出现
除运行时异常外,其它继承自Exception类的异常类包括:
(1)试图在文件尾部后面读取数据
(2)试图打开一个错误格式的URL
(3)编译器要求程序必须对这类异常进行处理称为已检查异常
4、IOException输入输出异常类
(1)IOException:申请I/0操作没有正常完成。
(2)EOFException:在输入操作正常结束前遇见了文件结束符。
(3)FileNotFountException:在文件系统中,没有找到由文件名字符串指定的文件。
声明抛出(已检查)异常:声明抛出异常:如果一个方法可能会生成一些异常,但是该方法并不确切知道如何对这些异常事件进行处理,此时,这个方法就需声明抛出这些异常。
一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器可能发生什么异常。
声明抛出异常在方法声明中用throws子句中来指明。
throws子句可以同时指明多个异常,说明该方法将不对这些异常进行处理,而是声明抛出它们。
以下几种情况需要方法用throws子句声明抛出异常。
(1)方法调用了一个抛出已检查异常的方法,程序运行过程中可能会发生错误,并且利用throw语句抛出一个已检查异常对象,程序出现错误。
(2)Java虚拟机和运行时库出现的内部异常。一个方法必须声明该方法所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么应该避免发生(RuntimeException)
如果方法没有声明所有可能发生的已检查异常,编译器会给出一个错误消息。
5、抛出异常:
(1)当Java应用程序出现错误时,会根据错误类型产生一个异常对象,这个对象包含了异常的类型和错误出现时程序所处的状态信息。把异常对象递交给Java编译器的过程称为抛出。
(2)抛出异常要生成异常对象,异常对象可由某些类的实例生成,也可以由JW生成。
(3)抛出异常对象通过throw语句来实现。
对于已存在的异常类,抛出该类的异常对象非常容易,步骤是:
(1)找到一个合适的异常类;
(2)创建这个类的一个对象
(3)将该对象抛出
(4)一个方法抛出了异常后,它就不能返回调用者了。
6、创建异常类:
自定义异常类:定义一个派生于Exception的直接或间接子类。如一个派生于IOException的类。
自定义异常类应该包括两个构造器:
默认构造器
带有详细描述信息的构造器(超类Throwabe的方法会打印出这些详细信息,有利于代码调试)
7、捕获异常:
程序运行期间,异常发生时,Java运行系统从异常生成的代码块开始,寻找相应的异常处理代码,并将异常交给该方法处理,这一过程叫作捕获
某个异常发生时,若程序没有在任何地方进行该异常的捕获,则程序就会终止执行,并在控制台上输出异常信息
若要捕获一个异常,需要在程序中设置一个try/catch/finally
(1)try语句括住可能抛出异常的代码段
(2)catch语句指明要捕获的异常类及相应的处理代码。
(3)finally语句指明必须执行的程序块。
1)try子句:
捕获异常的第一步是用try{…}子句选定捕获异常的代码范围,由try所限定的代码块中的语句,在执行过程中可能会自动生成异常对象并抛出。
对于异常处理可以捕获,也可以只声明抛出不做任何处理。
2)catch子句:
catch块是对异常对象进行处理的代码,每个try代码块可以伴随一个或多个catch语句,用于处理try代码块中所生成的各类异常事件。
catch语句只需要一个形式参数指明它所能捕获的异常类对象,这个异常类必须是Throwable的子类,运行时系统通过参数值把被抛出的异常对象传递给catch块,catch块可以通过异常对象调用类Throwable所提供的方法。
getMessage()用来得到有关异常事件的信息。
printStackTrace()用来跟踪异常事件发生时执行堆栈的内容。
再次抛出异常与异常链:子句中也可以抛出一个异常,这样做的目的是改变异常的类型。
3)finally子句:
捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得控制流程在转到程序其它部分以前,能够对程序状态做统一的管理。
不论在try代码块中是否发生了异常事件,finally块中的语句都会被执行。
二、断言
使用断言:在一个具有自我保护能力的程序中,断言很常用。
1、断言的概念:断言机制允许在测试期间向代码插入一些检查语句。当代码发布时,这些插入的检测语句将会被自动地移走。
Java语言引入了关键字assert。有两种形式:
(1)assert 条件;
(2)assert 条件:表达式;
两种形式都会对条件进行检测,如果结果为false,则抛出一个AssertionError异常。在第二种形式中,表达式将被传入AssertionError的构造器,并转换成一个消息字符串。
2、启用和禁用断言:
默认情况下,断言被禁用。
可以在程序中用-enableassertions或-ea(开启默认包中的所有类断言)选项启用:
java -enableassertions MyApp
用-disableassertions或-da禁用断言
3、 使用断言完成参数检查
在Java中,给出了3种处理系统错误的机制:
(1)抛出一个异常
(2)日志
(3)使用断言
什么时候使用断言:
(1)断言失败是致命的、不可恢复的错误
(2)断言检查只用于开发和测试阶段
断言只应该用于在测试阶段确定程序内部的错误位置。
4、 为文档假设使用断言:
断言是一种测试和调试阶段所使用的战术性工具;而日志记录是一种在程序的整个生命周期都可以使用的策略性工具。
三、日志
1、记录日志
记录日志API用来帮助观察程序运行的操作过程:
*可以很容易地取消全部日志记录,或者仅仅取消某个级别的日志,而且打开和关闭这个操作也很容易
*可以很简单地禁止日志记录的输出,因此,这些日志代码留在程序中的开销很小
*日志记录可以被定向到不同的处理器,用于在控制台中显示,用于存储在文件中等
*日志记录器和处理器都可以对记录进行过滤。过滤器可以根据过滤实现器指定的标准丢弃那些无用的记录项
*日志记录可以采用不同的方式格式化,例如,纯文本或XML
*应用程序可以使用多个日志记录器,它们使用类似包名的这种具有层次结构的名字,例如,com.mycompany.myapp
*在默认情况下,日志系统的配置由配置文件提供。如果需要的话,应用程序可以替换这个配置
2、 基本日志
“虚拟日志”
要生成简单的日志记录,可以使用全局日志记录器并调用其info方法:Logger.getGlobal().info("File->Open menu item selected");
在适当的地方调用:Logger.getGlobal().setLevel(Level.OFF);将会取消所有日志
3、高级日志
“企业级日志”
在一个专业的应用程序中,不要将所有的日志都记录到一个全局日志记录器中,而是可以自定义日志记录器,可以调用getLogger方法创建或获取记录器:private static final Logger myLogger=Logger.getLogger("com.mycompany.myapp");
未被任何变量引用的日志记录器可能会被垃圾回收,为了防止这种情况发生,要用一个静态变量存储日志记录器的一个引用
通常,有以下7个日志记录器级别:
*SEVERE
*WARNING
*INFO
*CONFIG
*FINE
*FINER
*FINEST
默认情况下,只记录前三个级别
logger.setLevel(Level.FINE);
现在,FINE和更高级别的记录都可以记录下来
Level.ALL开启所有级别的记录,Level.OFF关闭所有级别的记录
对于所有的级别有下面几种记录方法:
(1)logger.warning(message);
(2)logger.fine(message);
(3)logger.log(Level.FINE,message);
默认的日志记录将显示包含日志调用的类名和方法名,如果虚拟机对执行过程进行了优化,可以使用logp方法获得调用类和方法的确切位置:
void logp(Level l,String className,String methodName,String message)
跟踪执行流的方法(将生成FINER级别和以字符串ENTRY和RETURN开始的日志记录):
void entering(String className,String methodName,Object[] params)
void exiting(String className,String methodName,Object result)
记录日志的常见用途是记录那些不可预料的异常:
void throwing(String className,String methodName,Throwable t)——FINER级别的记录和一条以THROW开始的信息
void log(Level l,String message,Throwable t)
4、修改日志管理器配置
可以通过编辑配置文件来修改日志系统的各种属性。在默认情况下,配置文件存在于:jre/lib/logging.properties
要想用另一个配置文件:
(1)将java.util.logging.config.file特性设置为配置文件的存放位置并使用命令java -Djava.util.logging.config.file=configFile MainClass
(2)在main中调用System.setProperty("java.util.logging.config.file",file),也会调用LogManager.readConfiguration()来重新初始化日志管理器。
可以通过com.mycompany.myapp.level=FINE来指定自己的日志记录级别
可以通过java.util.logging.ConsoleHandler.level=FINE设置处理器级别
5、 本地化
我们可能希望将日志消息本地化,以便让全球的用户都可以阅读它。
本地化的应用程序包含资源包,例如,某个资源包可能将字符串“readingFile”映射成英文“Reading file”.
每个资源包都有一个名字(如com.mycompany.logmessages)
在请求日志记录器时,可以指定一个资源包:Logger logger=Logger.getLogger(loggerName,"com.mycompany.logmessages")
然后,为日志消息指定资源包的关键字,而不是实际的日志消息字符串:logger.info("readingFile")
消息应该包含占位符{0}、{1},如:Reading file {0}
然后调用下面的一个方法向占位符传递具体的值:logger.log(Level.INFO,"readingFile",fileName);
6、处理器
在默认情况下,日志记录器将记录发送到ConsoleHandler中,并由它输出到System.err流中。特别是,日志记录器还会将记录发送到父处理器中。
与日志记录器一样,处理器也有日志记录级别。对于一个要被记录的日志记录,它的日志记录级别必须高于日志记录器和处理器的阈值。
日志管理器配置文件设置的默认控制台处理器的日志记录级别为:java.util.logging.ConsoleHandler.level=INFO
要想记录FINE级别的日志,就必须修改配置文件中的默认日志记录级别和处理器级别。或者可以绕过配置文件,安装自己的处理器。
在默认情况下,日志记录器将记录发送到自己的处理器和父处理器,所以设置useParentHandlers属性为false就不会两次看到这些记录。
要想将日志记录发送到其他地方,就要添加其他的处理器。日志API提供了两个很有用的处理器,一个是FileHandler,另一个是SockerHandler。
SockerHandler将记录发送到特定的主机和端口。FileHandler可以收集文件中的记录。
可以通过设置日志管理器配置文件中的不同参数来修改文件处理器的默认行为。
7、 过滤器
在默认情况下,过滤器根据日志记录的级别进行过滤。
可以通过实现Filter接口并定义下列方法来自定义过滤器:boolean isLoggable(LogRecord record)
要想将一个过滤器安装到一个日志记录器或处理器中,只需要调用setFilter方法。
注意,同一时刻最多只能有一个过滤器。
8、 格式化器
ConsoleHandler类和FileHandler类可以生成文本和XML格式的日志记录。但是也可以自定义格式,这里需要扩展Formatter类并覆盖下面方法:String format(LogRecord record)
最后,调用setFormatter方法将格式化器安装到处理器中。
9、 日志记录说明
日志记录常用操作:
(1)为一个简单的应用程序,选择一个日志记录器,并把日志记录器命名为与主应用程序包一样的名字(com.mycompany.myprog)
调用下列方法得到日志记录器:private static final Logger logger=Logger.getLogger("com.mycompany.myprog");
(2)默认的日志配置将级别等于或高于INFO级别的所有消息记录到控制台,可以通过修改默认的配置文件或者安装一个新的默认配置
(3)级别为INFO、WARNING和SEVERE的消息都将显示在控制台上,因此,最好只将对程序用户有意义的消息设置为这几个级别。将程序员想要的日志记录设置为FINE级别。
四、调试技巧
(1)可以打印或记录任意变量的值:System.out.println("x="+x)或Logger.getGlobal().info("x="+x)
(2)在每一个类中放置一个main方法,这样就可以对每一个类进行单元测试。
(3)JUnit是一个非常常见的单元测试框架,学习并使用它
(4)日志代理是一个子类的对象,它可以截获方法调用,并进行日志记录,然后调用超类中的方法。
(5)利用Throwable类提供的printStackTrace方法,可以从任何一个异常对象中获得堆栈情况。
不一定要通过捕获异常来生成堆栈轨迹。只要在代码的任意位置插入下面这条语句就可以获得堆栈轨迹:Thread.dumpStack();
(6)一般来说,堆栈轨迹显示在System.err上,也可以利用printStackTrace(PrintWriter s)方法将它发送到一个文件中。
(7)将非捕获异常记录到一个文件中:Thread.setDefaultUncaughtExceptionHanler()
(8)要想查看类的加载过程,可以使用-verbose标志启动Java虚拟机
(9)-Xlint选项告诉编译器对一些普遍容易出现的代码问题进行检查
(10)使用jconsole的图形工具
(11)使用jmap查看堆的转储
(12)使用-Xprof标志运行虚拟机可以运行一个剖析器跟踪代码中经常被调用的方法。输出结果中还会显示哪些方法是由即时编译器编译的。
第二部分:实验部分
实验1:用命令行与IDE两种环境下编辑调试运行源程序ExceptionDemo1、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(); } }
检查异常后:
package 异常; //异常示例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); } } }
package 异常; //异常示例2 import java.io.*; public class ExceptionDemo2 { public static void main(String args[]) throws Exception { FileInputStream fis=new FileInputStream("text.txt");//JVM自动生成异常对象 int b; while((b=fis.read())!=-1) { System.out.print(b); } fis.close(); } }
已检查异常:指的是一个函数的代码逻辑没有错误,但程序运行时会因为IO等错误导致异常,你在编写程序阶段是预料不到的。如果不处理这些异常,程序将来肯定会出错。所以编译器会提示你要去捕获并处理这种可能发生的异常,不处理就不能通过编译。
未检查异常:指的是你的程序逻辑本身有问题,比如数组越界、访问null对象,这种错误你自己是可以避免的。编译器不会强制你检查这种异常。也检查不过来,太多了。
实验2: 导入以下示例程序,测试程序并进行代码注释。
测试程序1:
在elipse IDE中编辑、编译、调试运行教材281页7-1,结合程序运行结果理解程序;
在程序中相关代码处添加新知识的注释;
掌握Throwable类的堆栈跟踪方法;
程序代码如下:
package stackTrace; import java.util.*; /** * A program that displays a trace feature of a recursive method call. * @version 1.10 2017-12-14 * @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 + "):"); var walker = StackWalker.getInstance(); walker.forEach(System.out::println); 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) { try (var in = new Scanner(System.in)) { System.out.print("Enter n: "); int n = in.nextInt(); factorial(n); } } }
程序运行结果如下:
堆栈跟踪是一个方法调用过程的立标,它包含了程序执行过程中方法的调用的特定位置。可以使用Throwable类和Thread类提供的接口获取堆栈信息,进行分析调用情况。
测试程序2:
Java语言的异常处理有积极处理方法和消极处理两种方式;
下列两个简单程序范例给出了两种异常处理的代码格式。在elipse IDE中编辑、调试运行源程序ExceptionTest.java,将程序中的text文件更换为身份证号.txt,要求将文件内容读入内容,并在控制台显示;
掌握两种异常处理技术的特点。
程序代码如下:
//积极处理方式 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"); } }
读入内容后:
package 异常; //积极处理方式 import java.io.*; import java.io.BufferedReader; import java.io.FileReader; class ExceptionTest { 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(); } } }
package 异常; //消极处理方式 import java.io.*; class ExceptionTest { 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); } }
java中的异常类有Error和Exception:
Exception也就是我们经常见到的一些异常情况,比如NullPointerException、IndexOutOfBoundsException,这些异常是我们可以处理的异常。
实验3: 编程练习
编写一个计算器类,可以完成加、减、乘、除的操作;
利用计算机类,设计一个小学生100以内数的四则运算练习程序,由计算机随机产生10道加减乘除练习题,学生输入答案,由程序检查答案是否正确,每道题正确计10分,错误不计分,10道题测试结束后给出测试总分;
将程序中测试练习题及学生答题结果输出到文件,文件名为test.txt;
在以上程序适当位置加入异常捕获代码。
程序代码如下:
package 计算器; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.util.Scanner; public class ss { public static void main(String[] args) { Scanner in = new Scanner(System.in); sf sf=new sf(); PrintWriter output = null; try { output = new PrintWriter("ss.txt"); } catch (Exception e) { //e.printStackTrace(); } int sum = 0; for (int i = 1; i < 11; i++) { int a = (int) Math.round(Math.random() * 100); int b = (int) Math.round(Math.random() * 100); int s = (int) Math.round(Math.random() * 4); switch(s) { case 1: System.out.println(i+": "+a+"/"+b+"="); while(b==0){ b = (int) Math.round(Math.random() * 100); } double c = in.nextDouble(); output.println(a+"/"+b+"="+c); if (c == sf.chu_fa(a, b)) { sum += 10; System.out.println("恭喜答案正确"); } else { System.out.println("抱歉,答案错误"); } break; case 2: System.out.println(i+": "+a+"*"+b+"="); int c1 = in.nextInt(); output.println(a+"*"+b+"="+c1); if (c1 == sf.chen_fa(a, b)) { sum += 10; System.out.println("恭喜答案正确"); } else { System.out.println("抱歉,答案错误"); }break; case 3: System.out.println(i+": "+a+"+"+b+"="); int c2 = in.nextInt(); output.println(a+"+"+b+"="+c2); if (c2 == sf.jia_fa(a, b)) { sum += 10; System.out.println("恭喜答案正确"); } else { System.out.println("抱歉,答案错误"); }break ; case 4: System.out.println(i+": "+a+"-"+b+"="); int c3 = in.nextInt(); output.println(a+"-"+b+"="+c3); if (c3 == sf.jian_fa(a, b)) { sum += 10; System.out.println("恭喜答案正确"); } else { System.out.println("抱歉,答案错误"); }break ; } } System.out.println("成绩"+sum); output.println("成绩:"+sum); output.close(); } }
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; else return 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; else return 0; } }
程序运行结果如下:
实验4:断言、日志、程序调试技巧验证实验。
在elipse下调试程序AssertDemo,结合程序运行结果理解程序;
注释语句test1(-5);后重新运行程序,结合程序运行结果理解程序;
掌握断言的使用特点及用法。
程序代码如下:
//断言程序示例 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); } }
程序运行结果如下:
注释
注释语句test1(-5)后程序代码如下:
//断言程序示例 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:
用JDK命令调试运行教材298页-300页程序7-2,结合程序运行结果理解程序;
并掌握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; var 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(() -> { var windowHandler = new WindowHandler(); windowHandler.setLevel(Level.ALL); Logger.getLogger("com.horstmann.corejava").addHandler(windowHandler); var 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 var menuBar = new JMenuBar(); setJMenuBar(menuBar); var menu = new JMenu("File"); menuBar.add(menu); var openItem = new JMenuItem("Open"); menu.add(openItem); openItem.addActionListener(new FileOpenListener()); var 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 var 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(); var 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:
用JDK命令调试运行教材298页-300页程序7-2,结合程序运行结果理解程序;
按课件66-77内容练习并掌握Elipse的常用调试技术。
1)条件断点
添加断点:
点击Breakpoint Properties后:
2)变量断点
断点不仅能打在语句上,变量也可以接受断点:
上图就是一个变量的打的断点,在变量的值初 始化,或是变量值改变时可以停止,当然变量 断点上也是可以加条件的,和上面的介绍的条 件断点的设置是一样的。
3)方法断点
方法断点就是将断点打在方法的入口处:
方法断点的特别之处在于它可以打在JDK的源 码里,由于JDK在编译时去掉了调试信息,所 以普通断点是不能打到里面的,但是方法断点 却可以,可以通过这种方法查看方法的调用栈。
4)异常断点
经常遇见一些异常,然后程序就退出来了,要找到异常发生的地方就比较难了,还好可以打一个异常断点。
上图中我们增加了一个NullPointException的异常断点,当异常发生时,代码会停在异常发生处,定位问题时应该比较有帮助。
5)重新调试
6)单步执行程序
7)检查变量
8)改变变量值
第三部分:总结
通过本周的学习,我掌握了java异常处理的一些基础技术,了解了断言和日志的一些知识;本周除了惯例的编程练习外,重点是学习Java异常处理技术,更好的运用eclipse这个工具为我们编程提供服务。通过这周的学习,对之前做作业程序中出现的异常有了一点理解,以后作业中出现的异常不再是毫无头绪,不懂是程序哪里出现的问题。