Java复习笔记---异常,断言,日志和调试

来源:互联网 发布:json key 数字 编辑:程序博客网 时间:2024/06/06 03:54

温故而知新

一. 异常

  1. 对于异常情况,Java使用一种异常处理(exeception Handling)的错误捕捉机制处理
  2. 用户期望出现错误时程序能够采用一些理智的行为,如果由于出现错误而使得某些操作没有完成,程序应该:
    • 返回到一种安全的状态并能够让用户执行一些其他的命令
    • 允许用户保存所有操作的结果,并以适当的方式结束程序
  3. 在Java中,日过某个方法不能够采用正常的途径完成它的任务,就可以通过另外一个路径退出方法。在这种情况下,方法并不返回任何值,而是抛出一个封装了错误信息的对象
  4. 在Java程序设计语言中,异常类都派生于Throwable类,Java异常层次结构如下:Java异常和错误处理机制
  5. Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误,应该程序不应该改抛出这种类型的对象,这些错误将由JVM虚拟机处理
  6. 在设计Java程序时,需要关注Exception层次结构,这个层次结构有两个分支:一个分支派生于运行时异常RuntimeException,另一个分支派生于非运行时异常,划分这两个分支的规则是,由程序运行错误所导致的异常属于RuntimeException,而程序本身没问题,但由于像I/O错误,SQL错误这类问题所导致的异常属于非运行时异常
  7. 派生于RuntimeException的异常包含以下集中情况:
    • 错误的类型转换
    • 数据访问越界
    • 访问空指针
  8. 不是派生于RuntimeException的异常包括:
    • 试图在文件尾部后面读取数据
    • 试图打开一个不存在的文件
    • 试图根据给定的字符串查看Class对象,而这个字符串表示的类不存在
  9. “如果出现RuntimeException异常,那么一定就是你的问题”
  10. Java语言规范将派生于Error类和RuntimeException类的所有异常称为未检查异常(UncheckedException),将非运行时异常称为检查型异常
  11. 在遇到下面4中情况时应该跑出异常:
    • 调用一个抛出已检查异常的方法
    • 程序运行过程中发现错误,并且利用throw语句抛出一个已检查异常
    • 程序出现错误
    • Java虚拟机和运行库出现的内部错误
  12. 对于那些可能被他人使用的Java方法,应该根据异常规范在方法的首部声明这个方法可能抛出的所有异常
class myAnnotation {    public annotation generateAnnotation(String[] s) throwa IOException,FileNotFoundException {        ...    }}

13.不需要声明Java的内部错误, 即从Error继承的错误。任何程序代码都有抛出那些异常代码的潜能,而我们对其没有任何控制能力。
14. 一个方法必须声明所有可能抛出的所有已检查遗产,并处理所有UncheckedException,让程序能够继续运行
15. 如果在子类中覆盖了一个超类的方法,子类方法中声明的异常不能比父类中声明的异常范围更广
16. 如果父类方法没有抛出任何异常,则子类方法不能抛出异常
17. 使用throw关键字抛出异常:throw new EOFException();
18. 在程序中可能会遇到标准异常类不能够充分描述的问题,需要创建自定义异常类,创建的异常必须派生于非运行时异常(CheckedException)
19. 定义的异常类应该包含2个构造器,一个是默认的构造器,另一个是带有详细描述信息的构造器
20. 要想捕获一个异常,必须设置try/catch语句块
21. 如果try语句块抛出了一个在catch字句中说明的异常类,那么:
- 程序将跳过try语句块的其余代码
- 程序将执行catch字句中的处理器代码
22. 编译器将严格执行throws说明符,如果调用了一个抛出异常的方法,就必须对它进行捕获处理,或者进行传递
23. 捕获那些知道应该如何处理的异常,而将那些不知道如何处理的异常继续向上传递
24. throws说明符不能抛出超过父类方法所列出的异常
25. 在一个try语句块中可以捕获多个异常,并分别作出处理,在Java 7中可以一个catch语句处理多个异常对象
26. 可以通过e.getMessage()或者e.getClass().getName()获得异常对象的实际类型
27. 可以在catch语句中再抛出一个异常,这样做可以改变异常的类型
28. 可以用”包装”技术在原异常的基础上抛出子系统中的高级异常

try {    access database} catch(SQLException e) {    //将SQLEXception包装成ServletException    Throwable se = new ServletException("database error");    se.initCause(e);    throw se;}

30.try_catch_finally语句中,catch语句可以不写,finally语句肯定会执行
31. 在finally语句中最好不要加return语句,这样不会出现finally语句执行覆盖try语句的问题
32. 如果finally语句块中的代码抛出了异常,这将会覆盖原始的异常,如果要抛出原来的异常

Exception ex = null;try {    try {        code that moght throw exceptions;    }catch(Exception e) {        ex = e;        throw e;    }}finally {    try {        in.close();    }catch(Exception e) {        if(ex == null)             throw e;    }}

33.对于实现了AutoCloseable接口的资源类,可以使用Java 7中带有资源的try语句:try(Resource res = ...) { work with res; }
34. 调用Throwable类中的printStackTrace()方法可以查看堆栈跟踪的文本描述信息:

Throwable t = new Throwable();ByteArrayOutputStream bos = new ByteArrayOutputStream();t.printStackTrace(bos);String description = bos.toString();

35.一种更灵活的方法是使用getStackTrace()方法,它会得到StackTraceElement对象数组,可用于分析:

Throwable t = new Throwable();StackTraceElement[] elements = t.getStackeTrace();for(StackTraceElement e:elements) {    analyse e;}

36.异常信息分析常用方法:
- java.lang.Throwable
- Throwable(Throwable cause)
- Throwable(String message, Throwable cause)
- Throwable initCause(Throwable cause)
- Throwable getCause()
- StackTraceElement[] getStackeTrace()
- void addSuppressed(Throwable t)
- Throwable[] getSuppressed()
- java.lang.Exception
- Exception(Throwable cause)
- Exception(String message, Throwable cause)
- java.lang.RuntimeException
- RuntimeException(Throwable cause)
- RuntimeException(String message, Throwable cause)
- java.lang.StackTraceElement
- String getFileName()
- String getLineNumber()
- String getClassName()
- String getMethodName()
- boolean isNativeMethod()
- String toString()
37.使用异常机制的技巧:
- 异常处理不能代替简单的测试,只在异常情况下使用异常
- 不过分细化异常
- 利用好异常层次结构
- 不要压制异常,要对异常进行处理
- 在检查异常严格比放任更好
- 不要羞于传递异常,早抛出,晚捕获

二. 断言

  1. 断言机制允许在测试期间向代码中插入一些检查语句,当代码打不,这些语句会被自动移走
  2. 使用assert关键字断言,格式如下:assert <条件> 或 assert <条件> <表达式>,如果判断结果为false,则抛出一个AssertionError,在第二种表达式中,表达式将被传入AssertionError的构造器,转换成一个消息字符串
  3. 默认情况下,断言被禁用,需要通过运行时用-enableassertions 或 -ea选项启用: java -enableassertions MyApp
  4. 也可以在各个类或者某个包中使用断言:java -ea:MyClass -ea:com.mycompany.mylib... MyApp
  5. 使用-disableassertions或-da选项禁用断言
  6. 使用断言的时机:

    • 断言失败是致命的,不可恢复的错误
    • 断言检查只用于开发和测试阶段

7.常用方法:

  • void setDefaultAssertionStatus(boolean b) 对于通过类加载器加载的所有类来说,如果没有显式说明类或包的断言状态,就启用或者禁用断言
  • void setClassAssertionStatus(String className, boolean b)对于给定的类或者它的内部类,启用或者禁用断言
  • void setPackageAssertionStatus(String packageName, boolean b)对于给定包及其子包中的所有类,启用或者禁用断言
  • void clearAsserionStatus()移除所有类和包的显式断言设置

三. 日志

  1. 日志记录API的优点:

    • 可以很容易地取消全部日志记录,或者仅仅取消某个级别的日志,而且打开和关闭这个操作也很容易
    • 可以简单地禁止日志记录的输出,因此,将这些日志代码留在程序中的开销很小
    • 日志记录可以被定向到不同的处理器,用于在控制台显示或者存储在文件中
    • 日志记录器和处理器都可以对记录进行过滤,过滤器可以跟库过滤标准求其无用的记录项
    • 日志记录以采用不同的方式格式化,例如存文本或者XML
    • 应用程序可以使用多个日志记录器,它们使用类似包名这种具有层次结构的名字,例如:com.mycompany.myapp
    • 在默认情况下,日志系统的配置由配置文件控制,如果需要,应用程序可以替换这个配置

2.日志系统管理着一个名为Logger.global的默认日志记录器,可以用System.out来替换它,并通过info方法记录日志信息:Logger.getGlobal().info("File->open menu item selected")
3. 在专业的应用程序中,不要将所有的日志记录到一个全局日志记录器中,应该自定义日志记录器:private static final Logger myLogger = Logger.getLogger("com.mycompany.myapp")
4. 7个日志记录级别:

  • SEVERE
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST
    默认情况下,只记录前三个级别的记录,也可以设置日志记录级别:logger.setLevel(Level.FINE);
    5.跟踪执行流的方法:

  • void entering(String className, String methodName);

  • void entering(String className, String methodName, Object param);
  • void entering(String className, String methodName, Object[] params);
  • void exiting(String className, String methodName);
  • void exiting(String className, String methodName, Object result);
    调用将生成FINER级别和以字符串”ENTRY”,”RETURN”开始的日志记录
    6.提供日志记录中包含的异常描述的方法:

  • void throwing(String className, String methodName, Throwable t)

  • void log(Level l, String message, Throwable t)
    7.可以通过编辑配置文件来修改日志系统的各种属性,在默认情况下,配置文件存在于e/lib/logging.properties,要想使用另一个配置文件,就要将java.util.logging.config.file特性设置为配置文件的存储日志,并采用下面的命令启动应用程序:java -Djava.util.config.file = configFile MainClass
    8.编辑配置文件中.level = INFO来修改默认的日志级别,可以通过添加以下内容来指定自己的日志记录级别:com.mycompany.myapp.level = FINE;
    9.要想在控制台看到FINE级别的消息,就需要进行下列设置:java.util.logging.ConsoleHandler.level = FINE;
    10.在请求日志记录器时,可以指定一个资源包:
    Logger logger = Logger.getLogger(loggerName,"com.mycompany.logmessages");
    11.在默认情况下,日志记录器将记录发送到ConsoleHandler中,并由它输出到System.err流中,日志记录器还会降记录发送到父处理器中
    12.与日志记录器一样,处理器也有日志记录级别,对于一个包记录的日志记录,它的日志记录级别必须高于日志记录器和处理器的阈值,日志管理器配置文件的默认控制台处理器的日志记录级别java.util.logging.ConsoleHandler.level = INFO
    13.可以绕过配置文件,安装自己的处理器:
    Logger logger = Logger.getLogger("com.mycompany.myapp");    logger.setLevel(Level.FINE);    logger.setUserParentHandler(false);    Handler handler = new ConsoleHandler();    handler.setLevel(Levle.FINE);    logger.addHandler(handler);

14.日志API提供了两个很有用的处理器,一个是FileHandler;另一个是SocketHandler,可以将日志记录发送到文件及指定的主机端口
15.直接将日志记录发送到默认的文件处理器:
FileHandler fd = new FileJHandler();
logger.addHandler(fd);

16.如果多个应用程序使用同一个日志文件,就应该开启append标志,另外,应该在文件名模式中使用%u,让每个应用程序创建日志的唯一副本
17.开启文件循环功能是一个不错的主意,日志记录文件以myapp.log.0, myapp.log.1, myapp.log.2这种循环的形式出现。只要文件大小超出限制,最久的文件就会被删除,其他文件将会被重新命名,同时创建一个新文件,其编号为0
18.文件处理器配置参数:
文件处理器配置参数
19.日志文件模式变量:
日志文件模式变量
20.可以通过扩展Handler类或者StreamHandler类来自定义处理器
21.在默认情况下,过滤器根据日志记录的级别进行过滤,每个日志记录器和处理器都可以有一个可选的过滤器来完成附加的过滤,另外,可以通过实现Filter接口并定义下列方法来自定义过滤器:
boolean isLoggable(logRecord record);
22.使用setFilter()方法讲一个过滤器安装到日志记录器或处理器中
23.ConsoleHandler和FileHandler类可以生成文本和XML格式的日志记录,但也可以扩展Formatter类自定义格式:String format(LogRecord record)
24.日志记录基本操作

  • 为一个简单的应用程序选择一日志记录器,并把日志记录器命名为与主应用程序包一样的名字,例如:com.mycompany.myprog,这是一个很好的编程习惯,可通过以下方法得到日志记录器:Logger logger = Logger.getLogger("com.mycompany.myprog"),可能希望利用一些日志操作将静态域添加到类中:private static final Logger logger = logger.getLogger("com.myconpany.myprog");
  • 默认的日志配置将级别等于或高于INFO级别的所有记录到控制台,用户可以覆盖默认的配置文件,但最好在应用程序中安装一个更加适宜的默认配置
  • 所有级别为INFO,WARNING,SEVERE的消息都将显示到控制台上,因此,最好只将对程序用户有意义的消息设置为这几个级别,将程序员想要的日志级别设定为FINE是一个很好的选择
    25.常用方法:
java.util.logging.Logger//记录一个包含方法名和给定消息显示级别的日志记录    Logger getLogger(String loggerName)    Logger getLogger(String loggerName, String bundleName)    void severe(String message)    void warning(String message)    void info(String message)    void config(String message)    void fine(String message)    void finer(String message)    void finest(String message)//记录一个描述进入/退出方法的日志记录,其中应该包含给定阐述的返回值    void entering(String className, String methodName)    void entering(String className, String methodName, Object param)    void entering(String className, String methodName, Object[] params)    void exiting(String className, String methodName)    void exiting(String className, String methodName, Object result)//记录一个描述抛出给定异常对象的日志记录    void throwing(String className, String method methodName, Throwable t)//记录一个给定级别消息的日志记录,其中可以包括对象或者可抛出对象,要想包括对象,消息中必须包括格式化的占位符{0},{1}等    void log(Level level, String message)    void log(Level level, String message, Object obj)    void log(Level level, String message, Object[] objs)    void log(Level level, String message, Throwable t)//记录一个给定级别,准确的调用者信息和消息的日志记录,其中包括对象或可抛出对象    void logp(Level level, String className, String methodName, String message)    void logp(Level level, String className, String methodName, String message, Object obj)    void logp(Level level, String className, String methodName, String message, Object[] objs)    void logp(Level level, String className, String methodName, Throwable t)//记录一个给定级别,准确的调用者信息,资源包名和消息的日志记录,其中可以包括对象或可抛出对象    void logrb(Level level, String className, String methodName, String bundleName, String message)    void logrb(Level level, String className, String methodName, String bundleName, String message, Object obj)    void logrb(Level level, String className, String methodName, String bundleName, String message,Object[] objs)    void logrb(Level level, String className, String methodName, String bundleName, String message, Throwable t)    //获得和设置这个日志记录器的级别    Level getLevel();    void setLevel(Level level)//获得和设置这个日志记录器的父类日志记录器    Logger.getParent()    void setParentLogger()//获取这个日志记录器的所有处理器    Handler[] getHandlers()//增加或者删除这个日志记录器中的一个处理器    void addHandler(Handler handler)    void removeHandler(Handler handler)//获得和设置"use parent handler"属性,如果这个属性为true,则日志记录器会将全部的日志记录到它的父类处理器    boolean getUseParentHandlers()    void setUseParentHandlersI(boolean b)//获得和设置这个日志记录器的过滤器    Filter getFilter()    Filter setFilter()java.util.logging.Handler    //将日志记录发送到希望的目的地    abstract void publish(LogRecord record)    //刷新所有已缓冲的数据    abstract void flush()    //刷新所有已缓冲的所有数据并释放相关的资源    abstract void close()    //获得和设置这个处理器的过滤器    Filter getFilter()    void setFilter()    //获得和设置这个处理器的格式化器    Formatter getFormatter()    void setFormatter(Formatter f)    //获得和设置这个处理器的级别    Level getLevel()    void setLevel(Level level)java.lang.ConsoleHandler    //构造一个新的控制台处理器    ConsoleHandler()java.util.logging.FileHandler    /**    * 构造一个文件处理器    * @pattern 构造日志文件名的模式    * @limit 日志文件可以包含的近似最大字节数    * @count 循环序列的文件数量    * @append 新构造的文件处理器对象应该追加在一个已存在的日志文件尾部,则为true    */    FileHandler(String pattern)    FileHandler(String pattern, boolean append)    FileHandler(String pattern, int limit, int count)    FileHandler(String pattern, int limit, int count, boolean append)java.util.logging.LogRecord    //获得这个日志记录的记录级别     Level getLevel()    //获得正在记录这个日志记录的记录器的名字    String getLoggerName()    //获得用于本地化消息的资源包或资源包的名字,如果没有获得,则返回null    ResourceBundle getresourceBundle()    String getresourceBundleName()    //获得本地化和格式化之前的原始消息    String getMessage()    //获得参数对象, 如果没有获得,则返回null    Object[] getParameters()    //获得被抛出的对象, 如果不存在,则返回null    Throwable getThrown()    //获得记录这个日志记录的代码区域, 这个消息有可能是由日志记录代码提供的; 也有可能是自动从运行时堆栈推测出来的; 如果日志记录代码提供的值有误,或者运行至代码由于被优化而无法推测出确切位置,这两个方法的返回值就有可能不准确    String getSourceClassName()    String getSourceMethodName()    //获得创建时间, 以毫秒为单位(从1970年开始)    long getMills()    //获得这个日志记录的唯一序列序号    long getSequenceNumber()    //获得创建这个日志记录的线程的唯一ID, 这些ID是由LogRecord类分配的,而且与其他线程的ID无关    int getThreadID()java.util.logging.Filter    //如果给定日志记录需要记录,则返回true    boolean isLoggable(LogRecord record)java.util.logging.Formatter    //返回对日志记录格式化后得到的字符串    abstract string format(LogRecord record)    //返回应该出现在包含日志记录的文档的开头和结尾的字符串, 超类Formatter定义了这些方法,它们只返回空字符串。如果必要的话,可以对它们进行覆盖    String getHead(Header h)    String getTail(Header h)    //返回经过本地化和格式化后的日志记录的消息内容    String formatMessage(LogRecord record)

四. 调试技巧和建议

  1. 可以用下面的方法打印或记录任意变量的值:
    System.out.ptintln("x= "+x); 或 Logger.getGlobal().info("x= "+x); 如果x是一个对象,JVM会调用对象的toString()方法,想要获得隐式参数对象的状态,就可以打印this对象的状态:Logger.getGlobal().info(“this = “+this);`
  2. 可以利用在每一个类中加入一个main()方法这样就可以对每个类进行单元测试
  3. Junit是一个非常常见的单元测试框架,利用它可以很容易组织测试用例,只要修改类就需要运行测试,在发现bug后,还需要补充一些凄然的测试用例
  4. 日志代理(logging proxy)是一个子类的对象,它可以窃取方法调用,并进行日志记录,然后调用超类中的方法,例如如果调用一个面板的setBackground()方法出现了问题,就可以使用下面的方式以匿名子类实例的方式创建一个代理对象:
    Random generator = new Random() {        public double nextDouble() {            double result = super.nextDouble();            Logger.getGlobal().info("nextDouble: "+result);            return result;        }    }

当调用nextDouble()方法时就会出现一个日志消息,要想知道谁调用了这个方法就要生成一个堆栈跟踪
5. 利用Throwable类提供的printStackTrace()方法可以从任何一个对象中获得堆栈信息:

    try {        ...        }catch(Throwable t) {            t.printStackTrace();            throw t;        }    }
   上面的代码将捕获任何异常,打印异常对象和堆栈跟踪,然后重新抛出异常,以便能有合适的捕获处理   不一定要通过捕获异才能生成堆栈跟踪,只要在代码的任何位置插入`Thread.dumpStack();`就可以获得堆栈跟踪

6. 一般堆栈跟踪会显示在System.err上或通过printStackTrace(PrintWriter pw)发送到文件中,也可以捕获到字符串:“`
ByteArrayOutputStream bos = new ByteArrayOutputStream();
new Throwable().printStackTrace(bos);
String description = bos.toString();

7. 将程序中的错误信息保存到一个文件中是非常有用的,可通过如下方式将错误信息保存在txt文档中:`捕获错误流: java Myprogram 2 > errors.txt;``捕获输出和错误流: java Myprogram >& errors.txt;(我在cmd调试中报错>&不可用)`8. 让非捕获异常的堆栈出现在System.err流中会让客户感到迷惑,干扰诊断信息,可以调用静态的Thread.setDefaultUncaughtExceptionHandler()方法改变非捕获异常的处理器:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {    public void uncaughtException(Thread t, Throwable t) {    save information in log file    }});
9. 可以用-verbose标识启动虚拟机观察类的加载过程,可以观察到如下的输出结果,有助于诊断由于类路径引发的问题:
[Opened /usr/local/jdk5.0/jre/lib/rt.jar][Opened /usr/local/jdk5.0/jre/lib/jsse.jar][Opened /usr/local/jdk5.0/jre/lib/jce.jar][Opened /usr/local/jdk5.0/jre/lib/charsets.jar][Loaded java.lang.Object from shared objects file][Loaded java.io.Serializable from shared objects file][Loaded java.lang.Comparable from shared object file][Loaded java.lang.CharSequence from shared objects file]
10. Xlint选项告诉编译器对一些普遍容易出现的问题代码进行检查,例如如果使用下面这条命令编译:`javac -Xlint:fallthrough`,当switch语句中缺少break语句,编译器就会报告(术语“lint”最初用来描述一种定位C程序中潜在问题的工具、现在通常用于描述查找可以但不违背语法规则的代码问题的工具)11. Java虚拟机增加了对Java应用程序进行监控和管理的支持,它允许利用虚拟机中的代理跟踪内存消耗,线程使用,类加载等情况,这个功能对于像应用程序服务器这样大型的、长时间运行的Java程序来说特别重要。下面是一个能够展示这种功能的例子:JDK加载了一个称为jconsole的图形工具,可以用于显示虚拟机性能的统计结果。在UNIX/Linux环境下,运行ps实用工具,在Windows环境下,使用任务管理器。然后运行jconsole程序:`jconsole processID`12. 可以使用jmap使用工具获得一个堆的转储,其中显式了堆中的每个对象。使用命令如下:
    jmap -dump:format=b,file=dumpFileName processID    jhat dumpFileName

然后,通过在浏览中中输入localhost:7000将会运行一个网络应用程序,借此探查存储对象时堆得内容
13. 如果使用-Xprof标志运行Java虚拟机就会运行一个基本的剖析器来跟踪那些代码中经常被调用的方法,剖析信息发送给System.out,输出结果中还会显示那些方法是由及时编译器编译的

GUI程序排错技巧

  1. 如果查看Swing窗口,想知道设计者如何将所有这些组件排列得如此整齐,可以监视器内容。按下Ctrl+Shift+F1,会按照层次结构打开所有组件的信息
  2. 如果定义了自己定制的Swing组件,但它看起来不能正确显示,对此有一个很好的工具:Swing图形调试工具(Swing graphics debugger)。即使你并没有编写自己的组件类,能看到组件的内容如何绘制也很有意义,而且很有趣。要对一个Swing组件进行表示,可以使用JComponent类的setDebugGraphicsOptions方法。有以下可用选项:
    a. DebugGraphics.FLASHOPTION 绘制各线段、矩形和文本之前,用红色闪烁显示。
    b. DebugGraphics.LOG_OPTION 为各个绘制操作分别打印一个消息。
    c. DebugGraphics.BUFFERED_OPTION 显示在屏幕外缓冲区上完成的操作。
    d. DebugGraphics.NONE_OPTION 关闭图形调试。
    要让闪烁选项工作,不许禁用“双重缓冲”(Swing采用这种策略来缓解更新窗口时的屏幕抖动现象)。要打开闪烁选项,可以使用一下“魔咒”:
    RepaintManager.currentManager(getRootPane()).    setDoubleBufferingEnable(false);    ((JComponent) getContentPane()).    setDebugGraphicsOptions(DebugGraphics.FLASH_OPTION);
   只需要将这几行代码放在框架构造函数的最后。程序运行时,你会看到窗格缓慢地填充。或者,如果要完成更多本地化调试,只需要对单个组件调用setDebugGraphicsOptions。要控制闪烁,可以设置持续时间、次数和闪烁颜色

3. 如果想得到GUI应用中生成的各个AWT时间记录,可以在发出事件的各个组件中安装一个监听器。借助反射的强大能力,可以很容易地自动实现这一点
4. Robot类可以将案件和点击鼠标的事件发送给AWT程序,并能够对用户界面自动地检测
5. 要想获得Robot对象,首先要得到一个GraphicsDevice对象。通过下面的一系列调用获得默认的屏幕设备:

GraphicEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();GraphicsDevice screen = environment.getDefaultScreenDevice();Robot robot = new Robot(screen);要想发送一个按键的事件,就要告诉robot模拟按下键和释放建的动作:robot.keyPress(KeyEvent.VK_TAB);robot.keyRelease(KeyEvent.VK_TAB);要想发送一个点击鼠标的事件,首先要模拟移动鼠标的时间,然后在模拟按下和释放鼠标的事件:robot.mouseMove(x, y);robot.mousePress(InputEvent.BUTTON1_MASK);robot.mouseRelease(InputEvent.BUTTON1_MASK);这里的思路是:模拟键盘和鼠标的输入,然后进行屏幕快照,以便查看应用程序是否实施了预期的操作。可以调用createScreenCapture方法实现捕捉屏幕的操作:Rectangle rect = new Rectangle(x, y, width, height);BufferedImage image = robot.createScreenCapture(rect);最后,通常希望在上面的各条命令之间加上一个短暂的延迟,以保证程序能够捕获到各个时间。设置延迟的方法:调用delay方法,并传递一个以毫秒为单位的延迟,例如:    robot.delay(1000); // delay by 1000 milliseconds

6.Robot类自身并不适用与进行用户界面的测试。实际上,它是用于构建基本测试工具基础构件。一个专业的测试工具应该具有捕获、存储和再现用户交互场景的功能,并能够确定组件在名目中的位置,以及调整鼠标点击位置
7. 常用方法:

java.awt.GraphicsEnvironment 1.2:    //返回本地图形环境    static GraphicsEnvironment getLocalGraphicsEnvironment();    //返回默认的屏幕设备。需要注意的是,使用多态监视器的计算机,每一个屏幕有一个图形设备。通过调用getScreenDevices方法可以得到一个保存所有屏幕的数组    GraphicsDevice getDefaultScreenDevice();java.awt.Robot 1.3//构造一个能够与给定设备交互的Robot对象    Robot(GraphicsDevice device);    //模拟按下或释放按键,key键码    void keyPress(int key);    void keyRelease(int key);    //模拟移动鼠标,参数:x, y 用绝对像素坐标表示的鼠标位置    void mouseMove(int x, int y);    //模拟按下或释放鼠标键    void mousePress(int eventMask);    void mouseRelease(int eventMask);    //根据给的你给毫秒数延迟robot    void delay(int milliseconds);    //截取屏幕的一部分,参数:rect 用绝对像素坐标表示的所截取的矩形    BufferedImage createScreenCapture(Rectangle rect);
原创粉丝点击