第 4章 异常处理和常用系统类
4.1 异常处理机制
4.2 String类和 StringBuffer类
4.3 AWT
4.4 Java applet
4.1 异常处理机制
4.1.1 什么是异常用任何一种计算机语言设计的程序在运行时都可能出现各种错误,常见的错误如除数为 0,文件不存在,文件不能打开,
数组下标超过界限,内存不够用等 。 对于这种在运行中出现的错误,计算机系统中通常有两种处理办法 。
( 1)由计算机系统本身直接检测程序错误,遇到错误时使程序终止运行。这种处理方法的优点是使程序设计比较简单。
但是,对程序错误一概地采用终止运行办法,显然过于简单化。因为有些情况下,
完全可以通过其他途径保持程序继续运行。
比如,由于文件名不符合要求而无法打开文件,那么,可以提示用户输入一个新的文件名,从而使程序继续往下运行。
( 2)由程序员在程序设计中兼顾错误检测、错误信息显示和出错处理。这种处理方法的优点是减少了中途终止程序运行的可能性。但是,要求程序员在程序设计中不仅将精力用于正常处理过程,还要精心考虑错误检测和处理,这会使程序变得复杂。并且,这类错误检测往往是多数程序中重复甚至在一个程序中多次重复。
而另一方面,如果程序中某处忽略了应有的检测,又将引起程序总体结果的错误。
Java采用异常处理机制来处理程序运行中的错误 。 按照这种机制,将程序运行中的所有错误都看成一种异常,通过对语句块的检测,一个程序中所有的异常被收集起来放在程序的某一段中去处理 。 在
Java系统中,专门设置了一个调用栈,此栈中装有指向异常处理方法的指针 。
在程序运行时,系统会把收集到的异常和异常处理指针所指的处理类型逐个比较,如果找到相符的类型,那么就转向相应的方法处理,如没有在调用栈中找到相应的类型指针,则终止程序运行,并显示解释信息。
在 Java程序中,异常一般由以下两种原因引起。
( 1)程序中存在非法操作,最简单的例子就是除数为 0的除法操作。这种原因常常是程序员出于无意或大意造成的,所以称为隐式异常。常见的隐式异常可以通过
java.lang包中的 Throwable类的子类 Error
处理。
( 2)程序员在程序中使用了 throw语句引起的异常。这种异常是程序员出于某种考虑有意安排的,所以称为显式异常。
在 throw语句中,都会指出处理显式异常的对象,这些对象都是由 java.lang包的类
Throwable的子类 Exception再派生的子类生成的,每个对象完成对某种异常的处理功能,这些对象综合起来实现各种异常处理。
比如 Array-
IndexOutOfBoundsException 子类处理数组越界异常,IOException子类处理输入输出异常,而 ArithmeticException子类处理除数为 0导致的算术异常等 。
4.1.2 异常的层次结构
4.1.3 异常的处理
4.1.4 创建自己的异常
4.2 String类和 StringBuffer类
4.2.1 String类
1,String类的主要构造方法
String类有多个构造方法,主要的有下列 5个:
String();
String(char chars[ ]);
String(char chars[ ],int startIndex,int
numChars);
String(byte ascii[ ],int hiByte);
String(byte ascii[ ],int hiByte,int
startIndex,int numChars);
第 1个构造方法生成一个空串。
第 2个构造方法生成一个字符数组。
第 3个构造方法生成一个字符串,这个字符串是从字符数组 chars[ ]中提取的,具体讲,即从 chars[ ]数组的 startIndex位置开始提取字符,共提取 numChars个字符组成一个字符串。
第 4个构造方法是以字节数组的形式生成一个字符串,数组中存放字符串各字符对应的 ASCII码。
第 5个构造方法也是从字节数组生成一个字符串。具体讲,就是以字节数组 ascii[ ]
的 startIndex处开始,共提取 numChars个字符构成字符串,如为 ASCII 字符,则
hiByte的值为 0。
例 4-5:
import javax.swing.*;
public class StringConstructors {
public static void main( String args[] )
{
char charArray[] = { 'b','i','r','t','h',
' ','d','a','y' };
byte byteArray[] = {(byte) 'n',(byte) 'e',
(byte) 'w',
(byte) ' ',(byte) 'y',(byte) 'e',
(byte) 'a',(byte) 'r' };
StringBuffer buffer;
String s,s1,s2,s3,s4,s5,s6,s7,output;
s = new String( "hello" );
buffer =new StringBuffer( "Welcome to
Java Programming!" );
s1 = new String();
s2 = new String( s );
s3 = new String( charArray );
s4 = new String( charArray,6,3 );
s5 = new String( byteArray,4,4 );
s6 = new String( byteArray );
s7 = new String( buffer );
output = "s1 = " + s1 +"\ns2 = " + s2 +
"\ns3 = " + s3 +"\ns4 = " + s4 +
"\ns5 = " + s5 +"\ns6 = " + s6 +
"\ns7 = " + s7;
JOptionPane.showMessageDialog( null,
output,
"Demonstrating String Class
Constructors",
JOptionPane.INFORMATION_MESSAG
E );
System.exit( 0 );
}
}
运行结果见图 4-5。
图 4-5

4-
5
程序分析,String类提供了 9个构造函数,以便使用各种方法初始化 String对象 。
例题共演示了 7种 。
程序,s1 = new String()”实例化一个新的 String对象,并使用 String类的缺省构造函数将它赋给引用 s1。 新的 String对象没有字符 ( 即空串 ),长度为 0。
,s2=new String( s);,例化一个新的 String对象,并使用 String类的拷贝构造函数,将它赋给引用 s2。 s被当作参数传送给构造函数,新的 String对象包含了 String
对象 s中的字符的拷贝。
在大多数情况下,没有必要拷贝已有的 String对象。 String对象是不变的,一旦创建后就不能改变它们的内容(字符串)。
而且,如果有一个或多个引用指向某个 String对象,垃圾收集器就不能回收该对象。也就是说,String引用既不能用于修改 String对象,也不能删除 String对象。
这一点与 C语言或 C++ 语言是不同的。
,s3=new String( charArray);,实例化一个新的 String对象,并使用以字符数组为参数的 String类构造函数,将它赋给引用 s3。 新的 String对象包含了数组中字符的拷贝。
,s4=new String( charArray,6,
3) ;,实例化一个 String对象,使用以一个字符数组和两个整数为参数的 String类构造函数,将它赋给引用 s4。 第 2个参数指定了在数组中拷贝字符的起始位置
( offset) 。 第 3个参数指定了数组中拷贝字符的数目 ( count),新的 String对象包含了数组中指定字符的拷贝 。 如果 offset或
count参数指定的所取元素超过了字符数组的界限,就 会 产 生
StringIndexOutOfBoundsException 的例外处理 。
,s5=new String( byteArray,4,
4) ;,实例化一个新的 String对象,使用以一个 byte数组和两个整数为参数的 String
类构造函数,将它赋给引用 s5。 第 2和第 3
个参数分别指定了 offset和 count。 新的
String对象包含了数组中指定 byte 的拷贝 。
如果 offset或 count参数指定的所取元素超过了 byte 数 组 的界限,就会产 生一个
StringIndexOutOfBoundsException的例外处理 。
,s6=new String( byteArray) ;,实例化一个新的 String对象,使用以一个 byte
数组为参数的 String类构造函数,将它赋给引用 s6。 新的 String对象包含了数组中
byte的拷贝 。
,s7=new String( buffer) ;,实例化一个新的 String对象,使用以 StringBuffer
为参数的 String类构造函数,将它赋给引用 s7。 StringBuffer是一个可动态改变大小和内容的字符串 。 新的 String对象包含了
StringBuffer中字符的拷贝 。
2,String 类的 length,charAt 和
getChars方法下面的例子演示了 String 类的 length、
charAt和 getChars方法,它们分别用于确定 String 类的长度,取 String某一指定位置的字符以及取 String某一子串 。
3,String类的字符串比较例 4-7:
import javax.swing.JOptionPane;
public class StringCompare {
public static void main( String args[] )
{
String s1,s2,s3,s4,output;
s1 = new String( "hello" );
s2 = new String( "good bye" );
s3 = new String( "Happy Birthday" );
s4 = new String( "happy birthday" );
output = "s1 = " + s1 + "\ns2 = " + s2
+
"\ns3 = " + s3 + "\ns4 = " + s4 + "\n\n";
if ( s1.equals( "hello" ) )
output += "s1 equals \"hello\"\n";
else
output += "s1 does not equal
\"hello\"\n";
if ( s1 == "hello" )
output += "s1 equals \"hello\"\n";
else
output += "s1 does not equal
\"hello\"\n";
if ( s3.equalsIgnoreCase( s4 ) )
output += "s3 equals s4\n";
else
output += "s3 does not equal s4\n";
output +=
"\ns1.compareTo( s2 ) is " +
s1.compareTo( s2 ) +
"\ns2.compareTo( s1 ) is " +
s2.compareTo( s1 ) +
"\ns1.compareTo( s1 ) is " +
s1.compareTo( s1 ) +
"\ns3.compareTo( s4 ) is " +
s3.compareTo( s4 ) +
"\ns4.compareTo( s3 ) is " +
s4.compareTo( s3 ) +
"\n\n";
if ( s3.regionMatches( 0,s4,0,5 ) )
output += "First 5 characters of s3
and s4 match\n";
else
output +="First 5 characters of s3 and
s4 do not match\n";
if ( s3.regionMatches( true,0,s4,0,5 ) )
output += "First 5 characters of s3
and s4 match";
else
output +="First 5 characters of s3
and s4 do not match";
JOptionPane.showMessageDialog( null,
output,
"Demonstrating String Class
Constructors",
JOptionPane.INFORMATION_MESSAG
E );
System.exit( 0 );
}
}
4.在字符串中定位字符和子串
5.从字符串中抽取子串
6,字符串连接
public String concat( String st) 可返回一个字符串,它将把参数 str添加在原字符串的后面形成一个新的字符串 。 但在
Java中,更多的是使用,+,来连接字符串 。
这里读者可能会产生一个小小的迷惑,
因为前面我们讲过 String对象是不能改变的 。 实际上,字符串的连接是由编译器利用 StringBuffer的方法 append来实现的 。 这在下面的章节中讲解 。
例 4-10:
import javax.swing.*;
public class StringConcat {
public static void main( String args[] )
{
String s1 = new String( "Happy " ),
s2 = new String( "Birthday" ),
output;
output = "s1 = " + s1 +"\ns2 = " + s2;
output += "\n\nResult of s1.concat( s2 )
= " +s1.concat( s2 );
output += "\ns1 after concatenation =
" + s1;
JOptionPane.showMessageDialog( null,
output,
"Demonstrating String Method concat",
JOptionPane.INFORMATION_MESSAG
E );
System.exit( 0 );
}
}
运行结果见图 4-10。
7.转化为字符串图 4-10
图 4-10
4.2.2 StringBuffer类
String 类提供了很多处理字符串的功能 。 但是,一旦创建了字符串对象,它的内容就永远不会变 。 下面将讨论
StringBuffer类的特点 。 这个类可以创建和操纵动态字符串,即可修改的字符串 。 每个 StringBuffer都能够存储由它的容量所指定的一些字符 。 如果超过了 StringBuffer的容量,容量就会自动地扩大以容纳多出来的字符 。 我们将看到,StringBuffer类还可用来实现用于字符串连接的运算符 "+ "。
String 对象是常量字符串,
StringBuffer 对象是可修改的字符串 。
Java 区分字符串和可修改的字符串是为了优化的目的 。 特别地,Java可以实现有关
String 对象的某些优化,例如多个引用共享一个 String 对象,因为它知道这些对象不会改变 。
注意:在选择是用 String对象还是用
StringBuffer对象来表示一个字符串时,如果该对象确实不会改变,则总是使用
String对象,这样做可以改善性能 。 对
String对象调用非 String 类的 StringBuffer
方法是一种语法错误 。 StringBuffer 提供的方法有一些与 String 相同,有一些不同 。
最主要的方法有两组,一组是 append,另一组是 insert。
4.3 AWT
4.3.1 AWT概述
4.3.2 AWT的特点
4.3.3 AWT应用
4.4 Java applet
4.4.1 Java applet的特点
Java applet与 Java应用程序不同 。 它们的不同之处有以下几个方面 。
( 1) Java应用程序中,必须有一个
main()方法 。 Main()方法是程序的入口,
当程序开始运行时,解释器首先查找 main()
方法并执行 。 而 Java applet中则不需要
main()方法,它必须嵌入 HTML文件中,
由支持 Java applet的浏览器运行 。
( 2) Java应用程序可以独立运行。而
Java applet不能独立运行,需要依赖于网络浏览器。
( 3) Java应用程序所实现的功能是完全的,不需依赖于其他程序。而 Java
applet实现的功能是不完全的,它必须借助于浏览器中预先设计好的功能和已有的图形界面。 Java applet只需接收浏览器发送给它的消息,并及时做出响应。
( 4) Java应用程序中的所有方法的使用是通过调用实现的 。 可以人为控制 。
而 Java applet中有一部分方法是固定的,
只能由浏览器在特定时刻和场合调用,不能人为控制,但可以重载 。
4.4.2 Java applet的程序结构
Java applet的一般程序结构如下:
import java.applet.*;
import java.awt.*;
public class 子类名 extends Applet
//定义 Applet类的子类
{ public void init()
{方法体 } //初始化方法
public void start()
{方法体 } //开始执行方法
public void stop()
{方法体 } //停止执行方法
public void destroy()
{方法体 } //退出方法
public void paint(Graphics g)
{方法体 } //绘画方法
}
……
从 Java applet程序结构看出,Java
applet由若干类组成,无需 main()方法,但必须有且仅有一个主类,该类是 Applet类的子类,且被声明为 public。 程序被保存时,程序名必须命名为主类名,即程序名与主类名完全相同,后缀为,java。 主类中定义了 init(),start(),stop(),destroy()和
paint()方法,这些方法是从 Applet中继承的,有固定的含义,由浏览器在时机成熟时自动执行 。
4.4.3 Applet的主要方法在浏览器中运行 Applet程序,从运行开始到运行结束,Applet程序需经历 4个状态,分别是初始状态,运行状态,停止态和消亡状态 。 这 4种状态分别对应 Applet的
4 个主要方法,init(),start(),stop() 和
destroy()。
对于支持 Java的浏览器,如果在运行一个 HTML文件时发现该文件包含 Applet
程序,浏览器就会生成该 Applet的一个实例,并调用 init()方法,进入初始化状态,
在该状态下完成 Applet的一些初始化操作。
初始化完成后,浏览器接着调用 start()方法,进入运行状态,真正开始执行 Applet,
在该状态下 Applet通常会启动一些线程执行各种任务。
当退出当前主页时,浏览器调用 stop()
方法终止在运行状态下启动的线程,进入停止状态 。 当用户退出浏览器时,浏览器首先调用 Applet的 stop()方法,停止 Applet
的执行,然 后 调 用 destroy() 方法释放
Applet占用的系统资源,进入消亡状态 。
下面具体介绍 init(),start(),stop()和
destroy()4种方法 。
1,Init()方法在 Applet执行过程中,init()方法只执行一次 。 当浏览器第一次浏览含有 Applet
的 Web页载入 Applet时,就会执行 init()方法 。
由于在 Applet执行过程中,该方法只被执行一次,所以可以在 init()方法中进行一些只需执行一次的初始化操作,如变量的初始化、设置 Applet初始状态、载入图形或字体、获取 HTML中 Applet标记单元中 <PARAM>设定的参数等。
2,start()方法调用完 init()方法,浏览器将调用 start()
方法启动 Applet。 和 init()方法不同,在
Applet的执行过程中,start()方法可被浏览器调用多次。在下列情况下,浏览器会调用 start()方法。
( 1)浏览器从图标状态恢复为窗口状态或缩放浏览器窗口时。
( 2) Applet第一次载入时。
( 3)离开该 Web页后又再返回时。
( 4) reload该页面时。
在 start()方法中可启动相关线程来控制 Applet,给引入类对象发送消息,或以某种方式通知 Applet开始运行。该方法是
Applet的主体。
3,stop()方法该方法与 start()方法是相对应的,在
Applet执行过程中,也会被浏览器调用多次。在下列情况下,浏览器会调用 stop()方法。
( 1)浏览器从图标状态恢复为窗口状态或缩放浏览器窗口时。
( 2)离开 Applet所在 Web页时。
( 3) reload该页面时。
( 4)关闭该 Web页时。
( 5)从该 Web页退出浏览器运行时。
stop()方法可在适当时机挂起 Applet,
停止一些占用系统资源的工作,释放系统处理资源,以提高系统的运行速度。
4,destroy()方法在彻底结束对该 Web页的访问或退出浏览器时调用 destroy()方法,卸载 Applet,
释放载入 Applet时分配的系统资源。在
Applet的执行过程中,destroy()方法只执行一次。
destroy()方法是 Applet类的类方法,
只能用于 Applet。 可在该方法中执行释放系统资源的代码。但一般不需重写 destroy()
方法,因为 Java运行系统本身会自动进行
“垃圾”处理和内存管理,除非用了特殊的资源如创建的线程。
注意,destroy()方法与 stop()方法不同。
除了上述 4个方法外,Applet还提供一个非常重要的方法,paint( Graphics g)
方法。该方法用于进行绘图的具体操作,
但没有实现任何操作,用户可重写该方法,
实现个性化的绘图操作。
在 Applet执行过程中,paint()方法可以被浏览器自动调用执行绘图操作,可调用多次。当调整浏览窗口大小、缩放浏览窗口、移动窗口或 reload等需要重绘窗口时都会调用 paint()方法。
与其他 4个方法不同的是,paint()中需传递一个参数,该参数是 Graphics类的对象,由这个对象来完成具体的绘图操作。
Graphics对象由浏览器自动创建并将其传送给 paint()方法。
注意:应在 Applet中引入 Graphics类的包或该类:
import java.awt.Graphics;
例 4-16:
import java.applet.*;
import java.awt.*;
public class example4_16 extends Applet
{
private int InitCount;
private int StartCount;
private int StopCount;
private int DestroyCount;
private int PaintCount;
public example4_16()
{
InitCount=0;
StartCount=0;
StopCount=0;
DestroyCount=0;
PaintCount=0;
}
public void init()
{
InitCount++;
}
public void destroy()
{
DestroyCount++;
}
public void start()
{
StartCount++;
}
public void stop()
{
StopCount++;
}
public void paint(Graphics g)
{
PaintCount++;
g.drawString("Paint()方法执行了,"+PaintCount+"次。 ",20,20);
g.drawString("Init()方法执行了,"+InitCount+"次。 ",20,70);
g.drawString("Start()方法执行了,"+StartCount+"次。 ",20,120);
g.drawString("Stop()方法执行了,"+StopCount+"次。 ",20,170);
g.drawString("Destroy()方法执行了,"+DestroyCount+"次。 ",20,220);
}
}
4.4.4 Java applet的运行
Java applet程序不能独立运行,必须由浏览器来运行,因此我们需编写一个
HTML文件,通过 <applet>标记将 applet程序编译生成的字节码文件嵌入 HTML文件,
通知浏览器来运行 Java applet。
如要运行例 4 - 16,可编写如下的
HTML文件:
<html>
<head>
<title>example4_16</title></head>
<body>
<applet code=example4_16.class
width=300 height=250></applet>
</body>
</html>