项目

内容

这个作业属于哪个课程

https://www.cnblogs.com/nwnu-daizh/

这个作业的要求在哪里

https://www.cnblogs.com/nwnu-daizh/p/11778090.html

作业学习目标

(1) 掌握java异常处理技术;

(2) 了解断言的用法;

(3) 了解日志的用途;

(4) 掌握程序基础调试技巧;

 

第一部分:总结第七章关于异常处理相关理论知识(20分) 

一.  处理错误

1.  异常分类

      Java中,异常对象都是派生于Throwable类的一个实例。进而分为Error和Exception。Error描述了Java运行时系统的内部错误和资源耗尽错误,很少出现。主要关注Exception,分为RuntimeException和其他异常。由程序错误导致的异常属于RuntimeException,程序本身没有问题,由于像io错误等导致的属于其他异常。

     派生于RuntimeException的一场包涵下面几个情况:(1)错误的类型转换 (2)数组访问越界 (3)访问null指针

     不是派生于RuntimeException的异常包括:(1)试图在文件尾部后面读取数据  (2)试图打开一个不存在的文件   (3)试图根据给定的字符串查找Class对象,而这个字符串标是的类并不存在

      其他异常包含:试图在文件尾部后面读取数据、试图打开一个错误格式的URL、试图根据给定的字符串查找Class对象而类不存在。

1.2 声明已检查异常

  。如果遇到了无法处理的情况,那么java的方法可以抛出一个异常。这个道理很简单:一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发出什么错误。
  。方法应该在其首部声明所有可能抛出的异常。
  。在Java中,没有throws说明符的方法将不能抛出任何受查异常。
  。java throws在编译时执行,而不是在运行时执行 

     注意:   方法应该在其首部声明所有可能抛出的异常,如果抛出多个异常,每个异常类之间用逗号隔开。

        public FileInputStream(String name) throws FileNotFoundException{}

  。下面4中情况应抛出异常:

        1. 调用一个抛出已检查异常的方法,如FileInputStream的构造器。

        2. 程序运行过程中发现错误,且利用throw语句抛出一个已检查异常。

        3. 程序出现错误。

        4. Java虚拟机和运行时库出现的内部异常。

        也可以捕获异常,这样异常不被抛到方法之外,也不需要throws规范。

1.3 . 如何抛出异常

 当Java应用程序出现错误时,会根据错误类型产生一个异常对象,这个对象包含了异常的类型和错误出现时程序所处的状态信息。把异常对象递交给Java编译器的过程称为抛出。抛出异常要生成异常对象,异常对象可由某些类的实例生成,也可以由JVM生成。抛出异常对象通过throw语句来实现。

        1. 找到一个合适的异常类,2. 创建这个类的一个对象, 3. 将对象抛出

        抛出EOFException的语句:

         throw new EOFException();或者    EOFException e=new EOFException(); throw e;

     注意:一个方法抛出了异常后,他就不能返回调用者了。

1.4   创建异常类

      在程序中,可能会遇到任何标准类都没有能充分描述清楚的问题,在这种情况下,创建自己的异常类就很有必要了。我们需要做的只是定义一个派生于Exception的类,或者派生于Exception子类的类。例如:定义一个派生于IOException的类。习惯上,定义的类应该包含两个构造器,一个是默认的构造器,另一个是带有详细描述信息的构造器(超类Throwable的toString方法将会打印出这些详细信息,者在调试中非常有用。

 

    String getMessage()

       能获得Throwable对象详细描述信息,即构造时丢进去的String。

二 . 捕获异常

2.1 捕获异常     

如果某个异常发生时没有在任何地方进行捕获,那么程序将中止执行,并在控制台上打印出异常信息,包括异常的类型和堆栈的内容。对于图形界面程序(applet和应用程序),在捕获异常之后,也会打印出堆栈的信息,但是程序将返回到用户界面的处理循环中 

        捕获异常使用try/catch语句块。

      。如果在try语句块中抛出了一个在catch子句中说明的异常类,那么将跳过try语句块的其余代码,直接执行catch子句中的处理器代码。

      。如果抛出了一个catch子句中没有声明的异常类型,那么这个方法就会立刻退出。

        通常,应该捕获那些知道如何处理的异常,将那些不知道如何处理的异常 传递出去(在方法的首部添加throws说明符)。

注意:不允许子类覆盖超类的方法中throws说明符超过超类所列出的异常范围,如果有不属于的,不能throws掉,只能自己捕获处理

      -try语句括住可能抛出异常的代码段。  -catch语句指明要捕获的异常类及相应的处理代码。     -finally语句指明必须执行的程序块

     。try子句捕获异常的第一步是用try(···子句选定捕获异常的代码范围,由try所限定的代码块中的语句在执行过程中可能会自动生成异常对象并抛出。

      (1) catch块是对异常对象进行处理的代码;0每个try代码块可以伴随一个或多个catch语句,用于处理try代码块中所生成的各类异常事件;catch语句只需要一个形式参数指明它所能捕获的异常类对象,这个异常类必须是Throwable的子类,运行时系统通过参数值把被抛出的异常对象传递给catch块;

     (2)catch块可以通过异常对象调用类Throwable所提供的方法。

            -getMessage()用来得到有关异常事件的信息;      -printStackTrace()用来跟踪异常事件发生时执行堆栈的内容。

     (3) catch语句的顺序:-捕获异常的顺序和不同catch语句的顺序有关,当捕获到一个异常时。剩下的catch语句就不再进行匹配。因此在安排catch语句的顺序时,首先应该捕获最特殊的异常,然后在逐渐一般化,也就是一般先安排子类,再安排父类。

2.2 捕获多个异常

        对不同类型的异常做不同的处理,为每个异常类型使用一个单独的catch子句。

2.3 再次抛出异常与异常链

      。  在catch子句中可以抛出一个异常,这样做的目的是改变异常的类型。如果开发了一个供其他程序员使用的子系统,那么表示子系统故障的异常类型可能会产生多种解释。ServletException就是这样一个异常类型的例子。执行servlet的代码可能不想知道发生错误的细节原因,但希望明确的知道是否servlet是否有问题。 

      。就可以将原始异常设置为新异常的诱饵:catch(SQLException e){ Throwable t= new XXXException(); t.initCause(e);throw t;}    当捕获到异常时,可以使用Throwable e=t.getCause();重新得到原始异常。

      。 当捕获到异常时,就可以使用下面这条语句重新得到原始异常: Throwable e=se.getCause();

      。java编译器查看catch块中的throw语句,然后查看e的类型,会指出这个方法可以抛出任何Exception而不只是SQLException。(也就是说不可以这么做)
现在这个问题已经有所改进。编译器会跟踪到e来自try块。假设这个try块中仅有的已检查异常是SQLException实例,另外,假设e在catch中未改变,将外围方法声明为throws SQLException就是合法的 。


2.4 finally子句

      。当代码中抛出一个异常时,就会终止方法中的剩余代码的处理,并推出这个方法的执行。如果方法获得了一些本地资源,并且只有这个方法自己知道,有如果这些资源在退出方法之前必须被收回,那么就会产资源回收问题。一种解决方案是捕获并重新抛出所有的异常。但是这种解决方案比较乏味,这是因为需要在两个地方清除所分配的资源。一个在正常的代码中,另一个是在异常的代码中。 Java有一种更好的解决方案,这就是finally子句。

 

      。不管是否有异常被捕获,finally子句中的代码都被执行。可以只有try/finally,而没有catch,此时异常重新抛出。

        try{     code that might throw exceptions

               }

       catch(IOException e){      show error dialog

               }

       finally{      g.dispose();

        }

        1. try中没有抛出异常:try中代码全部执行,finally中代码全部执行,程序继续运行。执行顺序:1-2-5-6

        2. try抛出一个catch子句捕获的异常:try中代码中断执行,执行catch中的代码,最后执行finally中代码。

            如果catch没有抛出异常,则catch中代码全部执行,finally后的代码正常运行,执行顺序:1-3-4-5-6。

            如果catch抛出异常,则catch中断执行,finally后的代码也中断执行,执行顺序:1-3-5。

        3. try抛出一个catch没有捕获的异常:try中代码中断执行,catch的代码不执行,finally中代码执行完即终止:1-5。

   。无论在try语句块中是否遇到异常,finally子句中的in.close()语句都会被执行。当然,如果真的遇到一个异常,这个异常将被重新抛出,并且必须有另一个catch子句捕获。 

      当finally子句中包含return 语句时,将会出现一种意想不到的结果。假设利用return 语句从try语句中退出,在方法返回前,finally子句的内容将被执行。如果finally子句中也有一个return语句,这个返回值方会覆盖原始的返回值。

2.5带资源的try 语句

      如果try块抛出一个异常,而且close方法也抛出一个异常,这就会带来一个难题。带资源的try语句可以很好的处理这种情况。原来的异常会重新抛出,而close方法抛出的异常会被抑制。这些异常将自动捕获,并由addSupressed方法增加到原来的异常。

      如果对这些异常感兴趣,可以调用getSuppressed方法,他会得到从close方法抛出并被抑制的异常列表。  只要需要关闭资源,就要尽可能的使用带资源的try语句。
      带资源的try语句自身也可以有catch子句和一个finally子句,这些子句会在关闭资源之后执行,不过在实际中,一个try语句中加入这个多的内容可能不是一个好主意。 

2.6分析堆栈跟踪元素

   。  堆栈轨迹(stack trace)是一个方法调用过程的列表,它包含了程序执行过程中方法调用的特定位置 , 前面已经看到过这种列表,当java程序正常终止,而没有捕获异常时,这个列表就会显示出来。 可以调用Throwable类的printStackTrace方法访问堆栈轨迹的文本描述信息。

   。比较灵活的方式是使用getStackTrace()。它会得到StackTraceElement对象的一个数组。

   。 静态的Thread.getAllStackTrace方法,获得所有线程的堆栈跟踪。 

   。一种更灵活的方法是使用getStackTrace方法,他会得到StackTraceElement对象的一个数组,可以在你的程序中分析这个对象数组。

   。StackTraceElement类含有能够获得文件名和当前执行的代码行号的方法,同时,还含有能够获得类名和方法名的方法。toString方法将产生一个格式化的字符串,其中包含所获得的信息。

三 .使用异常机制的建议

        1. 异常处理不能代替简单的测试,只在异常情况下使用异常机制。

        2. 不要过分地细化异常,将整个任务包装在一个try中,转而使用多个catch。

        3. 利用异常层次结构:不要只抛出RuntimeException,应使用更合适的子类。

        4. 不要压制异常:不太明白这个的意思。

        5. 检测错误时,苛刻要不放任更好。

        6. 不要羞于传递异常。

四.  断言assert

        在一个具有自我保护能力的程序中,断言是一个常用的习语。假设确信某个属性符合要求,并且代码的执行依赖于这个属性。断言允许在测试期间向代码中插入一些检查语句,当代码发布时,这些插入的检测语句将会被自动地移走。

4.1断言的概念

   。java语言中引入了关键字assert。这个关键字有两种形式: assert 条件; 和   assert  条件:表达式;
   这两种形式都会对条件进行检测,如果结果为false,则抛出一个AssertionError异常。在第二种形式中,表达式将被传入AssertionError的构造器,并转换成一个消息字符串
   。 要想断言x是一个非负数值,只要简单的下列语句:
    assert x>=0;
    或者将x的实际值传递给AssertionError对象,从而可以在后面显示出来

4.2  启用和禁用断言

        在默认情况下,断言被禁用,可以在运行程序时用-enableassertions或者-ea选项启用:

        启动或者禁用断言不必重新编译程序。启动或者禁用断言是类加载器(Class loader)的功能。当断言被禁用时,类加载器将跳过断言代码,因此,不会降低程序的运行速度 
也可以在某个类或者整个包中使用断言。

        有些类不是由类加载器加载,而是直接由虚拟机加载。可以使用这些开噶UN有选择的启用或者禁用这些类中的断言。 

然而,启用和禁用所有断言的-ea 和-da开关不能应用到那么没有类加载器的系统类上。对于这些系统类来说,需要使用-enablesystemassertions 或者-esa来启用断言 。

4.3  使用断言完成参数检查

        断言失败是致命的、不可恢复的错误。

        断言检查只用于开发和测试阶段。断言只应该用于在测试阶段确定程序内部的错误位置。

        断言是一种测试和调试阶段所使用的战术性工具,而日志记录是一种在程序的整个生命周期都可以使用的策略工具。

4.3 为文档使用断言

五.记录日志

5.1 基本日志

   要生成简单的日志记录,可以使用全局日志记录器(global logger)并调用其info方法    Logger.getGlobal().info("hello");

  如果在适当的地方调用  Logger.getGlobal().setLevel(Level.OFF); 将会取消所有的日志

5.2 高级日志

    。可以调用getLogger方法来串讲或者获取记录器

      public static final Logger mylogger=Logger.getLogger("helo");

   。未被任何变量引用的日志记录其可能会被垃圾回收,所以要用一个静态变量存储日志记录器的一个引用
与包名类似,日志记录器名也有层次结构。事实上,与包名相比,日志记录器的层次性更强。对于包名来说,一个包的名字与其父包的名字之间没有语义关系,但是日志记录器的父与子之间将共享某些属性。

。有一下7个日志记录器级别

SEVERE   WARNING   INFO   CONFIG   FINE   FINER     FINEST

   在默认情况,只记录前三个级别,也可以设置其他级别。

5.3修改日志管理器配置

 。默认情况,配置文件存在于:e/lib/logging.properties

 。要想使用自己的配置文件 需要  java -Djava.util.logging.config.file=configFile MainClass

 。修改默认的日志记录级别   .level=INFO

 。还能修改自己日志记录级别    com.mycompany.myapp.level=FINE

 。控制台也有输出级别限制   java.util.logging.ConsoleHandler.level=FINE

 。日志属性由 java.util.logging.LogManager类处理。具体看API

5.4 日志本地化

本地化的应用程序包含资源包,例如,某个资源包可能将字符串“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);

5.5 处理器

。日志记录器先会将记录发送到父处理器中,最终的处理器有一个ConsoleHandle。

。对于一个要被记录的日志记录,它的日志记录级别必须高于日志记录器和处理器的阈值。

。要想记录FINE级别的日志,就必须修改配置文件中的默认日志记录级别和处理器级别。 另外,还可以绕过配置文件,安装自己的处理器。//控制台处理器

。在默认情况,日志记录器会将记录发送给自己的处理器和父处理器。父处理器就是一般的默认处理器,但是既然我们有了自己的处理器,可以把父处理器关了。免得控制台发送了两次记录

要想将日志发送到别的地方,就需要其他处理器。

5.6 过滤器

  • 每个记录器和处理器都可以有一个可选的过滤器来完成附加的过滤
  • 可以通过实现Filter接口并定义下列方法来自定义过滤器      boolean isLoggable(LogRecord record)

  • setFilter方法安装过滤器

5.7格式化器

。ConsoleHandler类和FileHandler可以生成文本或 XML格式的日志记录。但是也可以自定义格式。

。通过继承Formatter类,并覆盖一下方法。 String format(LogRecord record)

。可以根据自己意愿对记录的信息进行格式化,并返回结果字符串。然后用setFormatter方法将格式化器安装到处理器中。

六.调试技巧

(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的图形工具,使用jmap查看堆的转储

(11)使用-Xprof标志运行虚拟机可以运行一个剖析器跟踪代码中经常被调用的方法。输出结果中还会显示哪些方法是由即时编译器编译的

第二部分:实验部分

实验1:(5分)

用命令行与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[]) throws IOException
     {
          FileInputStream fis = new FileInputStream("text.txt");//JVM自动生成异常对象
          int b;
          while((b=fis.read())!=-1)
          {
              System.out.print(b);
          }
          fis.close();
      }
}

 实验运行结果: 

                                       

已检查异常,指的是一个函数的代码逻辑没有错误,但程序运行时会因为IO等错误导致异常,你在编写程序阶段是预料不到的。如果不处理这些异常,程序将来肯定会出错。所以编译器会提示你要去捕获并处理这种可能发生的异常,不处理就不能通过编译。
就比如所有try catch的异常都是已检查异常。因为已检查异常必须被处理。

未检查异常,也就是RunTimeException异常,指的是你的程序逻辑本身有问题,比如数组越界、访问null对象,NullPointException,这种错误你自己是可以避免的。编译器不会强制你检查这种异常。

 

实验2:测试程序1(5分)

测试程序1:在elipse IDE中编辑、编译、调试运行教材281页7-1,结合程序运行结果理解程序;

代码如下:

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)     //求n的阶乘
   {
      System.out.println("factorial(" + n + "):");
      StackWalker walker = StackWalker.getInstance();    //创建一个表示指定执行点的堆栈跟踪元素walker,调用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 (Scanner in = new Scanner(System.in))   //try子句
      {
         System.out.print("Enter n: ");
         int n = in.nextInt();
         factorial(n);
      }
   }
}

  实验运行结果:

实验2:测试程序2(10分)

测试程序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");
     }
}  

代码如下:

  //积极处理方式  
import java.io.*; 
  public class ExceptionTest {
     public static void main (String args[])
  {
         
      try{
        FileInputStream fis=new FileInputStream("D:\\身份证号.txt");
        BufferedReader in = new BufferedReader(new InputStreamReader(fis));
          try {
              String s, s2 = new String();
              while ((s = in.readLine()) != null) {
                s2 += s + "\n ";
            }
             in.close();              System.out.println(s2);
          } catch (IOException e) {
              System.out.println("学生信息文件读取错误");
              e.printStackTrace();
          }
      } catch (FileNotFoundException e) {
          System.out.println("学生信息文件找不到");
          e.printStackTrace();
      }
 
   }
 }

  

package hi;
  //消极处理方式
  
  import java.io.*;
  public class ExceptionTest {
      public static void main (String args[]) throws  IOException
        {
          FileInputStream fis=new FileInputStream("D:\\身份证号.txt");
          BufferedReader in = new BufferedReader(new InputStreamReader(fis));
         String s, s2 = new String();
 
             while ((s = in.readLine()) != null) {
                 s2 += s + "\n ";
             }
             in.close();
            System.out.println(s2);
       }
 }

积极处理和消极处理的实验运行结果如下:

实验3:编程练习(25分)

l 编写一个计算器类,可以完成加、减、乘、除的操作;

l 利用计算机类,设计一个小学生100以内数的四则运算练习程序,由计算机随机产生10道加减乘除练习题,学生输入答案,由程序检查答案是否正确,每道题正确计10分,错误不计分,10道题测试结束后给出测试总分;

将程序中测试练习题及学生答题结果输出到文件,文件名为test.txt;

代码如下:

package hi;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;


public class jisuan {
    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        jieguo student=new jieguo();
        PrintWriter out = null;
        try {
            out = new PrintWriter("text.txt");
        } catch (FileNotFoundException e) {
            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 c= (int) Math.round(Math.random() * 3);

            
           switch(c)
           {
           case 0:
               System.out.println(i+": "+a+"/"+b+"=");
               
               while(b==0)
               { 
                   b = (int) Math.round(Math.random() * 100);
            }
               
            int C = in.nextInt();
            out.println(a+"/"+b+"="+C);
            if (C == student.division(a, b)) {
                sum += 10;
                System.out.println("right");
            }
            else {
                System.out.println("false");
            }
            
            break;
            
           case 1:
               System.out.println(i+": "+a+"*"+b+"=");
               int D = in.nextInt();
               out.println(a+"*"+b+"="+D);
               if (D == student.multiplication(a, b)) {
                   sum += 10;
                   System.out.println("right");
               }
               else {
                   System.out.println("false");
               }
               break;
           case 2:
               System.out.println(i+": "+a+"+"+b+"=");
               int E = in.nextInt();
               out.println(a+"+"+b+"="+E);
               if (E == student.add(a, b)) {
                   sum += 10;
                   System.out.println("right");
               }
               else {
                   System.out.println("false");
               }
               
               break ;
           case 3:
               System.out.println(i+": "+a+"-"+b+"=");
               int F = in.nextInt();
               out.println(a+"-"+b+"="+F);
               if (F == student.reduce(a, b)) {
                   sum += 10;
                   System.out.println("right");
               }
               else {
                   System.out.println("false");
               }
               break ;
              } 
          }
       System.out.println("成绩"+sum);
        out.println("成绩:"+sum);
         out.close();        
   }
   }

   

package hi;
public class jieguo {
   private int a;
   private int b;
    public int  add(int a,int b)
    {
        return a+b;
    }
    public int   reduce(int a,int b)
    {
        return a-b;
    }
    public int   multiplication(int a,int b)
    {
        return a*b;
    }
    public int   division(int a,int b)
    {
        if(b!=0)
        return a/b;
        else return 0;
    }

}

 

实验运行结果:

 

 

实验4:测试程序1(5分)

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);
    }
}

 实验运行结果:

 

 注释后的结果:

 

常见的断言特性

前置条件断言:代码执行之前必须具备的特性
后置条件断言:代码执行之后必须具备的特性
前后不变断言:代码执行前后不能变化的特性

断言使用方式

断言可以有两种形式
1.assertExpression1
2.assertExpression1:Expression2
其中Expression1应该总是一个布尔值,Expression2是断言失败时输出的失败消息的字符串。如果Expression1为假,则抛出一个AssertionError,这是一个错误,而不是一个异常,也就是说是一个不可控制异常(uncheckedException),AssertionError由于是错误,所以可以不捕获,但不推荐这样做,因为那样会使你的系统进入不稳定状态。

实验4:测试程序2(5分)

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;
            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();
   }
}  

运行结果:

 

 

实验4:测试程序3(5分)

l 用JDK命令调试运行教材298-300页程序7-2,结合程序运行结果理解程序;

按课件66-77内容练习并掌握Elipse的常用调试技术。

程序代码同上;

调试如下:

(1)条件断点 ,添加断点,并点击Breakpoint Properties后:

 

(2)变量断点

 

 

(3)方法断点

 

 

实验总结:(15分)

           在学完了第四,五,六章的内容后,这周JAVA进入了异常,断言和日志的学习,记得老师以前说过那三章是JAVA的核心,是核心就会比较难,反正我学的时候就稀里糊涂的。当我学了异常,断言与日志之后,我对JAVA又重拾了信心。这周的学习内容自我感觉还可以,再加上老师又详细的讲解了一遍,我对异常和断言的语法点基本上掌握了,一些比较简单的程序我都可以加上异常或是断言处理代码,可是在实验报告单中给一些比较复杂的程序加异常和断言处理代码的时候,我就有点懵了,不知道要加什么样的异常类,也不知道应该在什么地方加异常代码,可是我觉得这应该也是正常的,因为初阶段的学习,我们对JAVA的框架都不是很熟悉,随着知识的增多,我会慢慢理解并对他加以熟练应用的。日志那一块进行了自学,我自己看了一遍,大概懂得了他的语法点,通过写那一道书上的程序,我看到那是关于图形用户界面的代码,原来JAVA 也有关于图形用户界面的语法点,总体来说,这周的JAVA学习我是有很大的收获的,遗留的问题我会通过自己的努力去解决的。

posted on 2019-11-04 19:56  201871010110-李华  阅读(180)  评论(1编辑  收藏  举报