您的位置:首页 > 编程语言 > Java开发

Java学习笔记(12)Exception Handling and Text I/O

2016-06-23 11:20 741 查看

12.1异常的一个例子:运行时错误( runtime error )

import java.util.Scanner;
public class Quotient {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Enter two integers: ");
int number1 = input.nextInt();
int number2 = input.nextInt();
System.out.println(number1 + " / " + number2 + " is " + (number1 / number2));
}
}


某两次运行结果



显然除数为0是不行的,所以程序引发异常后就崩溃了。
顺便提一下,如果是除数为0.0的浮点除法,例如double f = 5.0/0.0; 则不会引发异常,f会得到Infinity的特殊值。



12.1.1使用if和方法来改写程序

为了让程序不至于异常退出,首先想到的方法是多一个判断,然后除数为0时提示并主动退出程序:


public static int quotient(int number1, int number2) {
if (number2 == 0) {
System.out.println("Divisor cannot be zero");
System.exit(1); //主动退出程序
}

return number1 / number2;
}


改写


public static int quotient(int number1, int number2) {
if (number2 == 0)
throw new ArithmeticException("Divisor cannot be zero");

return number1 / number2;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Prompt the user to enter two integers
System.out.print("Enter two integers: ");
int number1 = input.nextInt();
int number2 = input.nextInt();

try {
int result = quotient(number1, number2);
System.out.println(number1 + " / " + number2 + " is " + result);
} catch (ArithmeticException ex) {
System.out.println("Exception: an integer " + "cannot be divided by zero ");
}

System.out.println("Execution continues ...");
}


某两次的执行结果





可以看到程序通过了除数为0的考验。
原因在于除数为0时,引发了这个异常:throw new ArithmeticException(“Divisor cannot be zero”); 然后这个异常被程序自己捕获了(这点很重要,否则程序又要挂了):
catch (ArithmeticException ex)
总结一下
自己捕捉异常的代码模版如下:

try {
Code to run;
A statement or a method that may throw an exception;
More code to run;
}
catch (type ex) {
Code to process the exception;
}

12.2再来一个例子:输入不匹配异常



12.3 Exception Types异常的类型







Note

The class names Error,
Exception, and
RuntimeException are somewhat confusing. All three of these classes are exceptions, and all of the errors occur at runtime.

System errors are thrown by the JVM and are represented
in the Error class. The
Error
class describes internal system errors, though such errors rarely occur. If one does, there is little you can do beyond notifying the user and trying to terminate the program gracefully. Examples of subclasses
of Error are listed in Table 12.1.



Exceptions are represented in the
Exception class, which describes errors caused by your program and by external circumstances. These errors can be caught and handled by your program. Examples of subclasses
of Exception are listed in Table 12.2.



Runtime exceptions are represented in the
RuntimeException class, which describes programming errors, such as bad casting, accessing an out-of-bounds array, and numeric errors. Runtime exceptions are generally thrown
by the JVM. Examples of subclasses are listed in Table 12.3.





12.4受检异常(Checked Exceptions)VS.非受检异常(Unchecked Exceptions)

RuntimeException, Error以及它们的子类,都属于非受检异常,其余异常属于受检异常。
受检异常:强制要求程序员在源代码中显式处理这些异常,否则编译器会报错。
非受检异常:大部分情况下,非受检异常反映的是程序的逻辑错误,这是无法挽回的错误(除非修改源代码重编译,否则无法避免再次运行出错)。
例如空指针异常NullPointerException ,表示你访问了一个空对象,下标越界IndexOutOfBoundsException,表示你的数组下标超出范围,这些逻辑错误应该在开发过程中就修改。
如果全部借助try-catch机制来保证程序的稳定是不现实的,不但代码冗长并且效率低下,所以 Java不会强制你捕捉这类异常。

12.5声明,抛出及捕捉异常



12.5.1声明异常

每一个方法可以声明几种受检异常,以强制方法的调用者显式捕获这些异常。这种叫做声明异常( declaring exceptions)。下面是两个例子:

public void myMethod()
throws IOException
public void myMethod()
throws Exception1, Exception2, ..., ExceptionN

12.5.2抛出异常

当程序检测到异常时,可以创建一个能够恰当描述该异常的实例并将其抛出,至于由谁来处理这个异常,它就不管了。这种叫做抛出异常(throwing an exception),例如下面这两个例子:

throw new IllegalArgumentException("Wrong Argument");

或者:

IllegalArgumentException ex =new IllegalArgumentException("Wrong Argument");
throw ex;

12.5.3捕捉异常

抛出的异常一定要自己捕获,否则等到操作系统检测到异常,你的程序已经挂了。语法如下:

try {
statements;
}
catch (Exception1 exVar1) {
handler for exception1;
}
catch (Exception2 exVar2) {
handler for exception2;
}
...
catch (ExceptionN exVar3) {
handler for exceptionN;
}



12.6异常捕捉的层次

假设method3引发异常,则异常的捕捉顺序是:Exception3, Exception2, Exception1,某一层方法捕捉失败,将导致该方法退栈,并由下一层继续尝试捕捉。



12.7捕捉或声明受检异常

Java强制你处理受检异常。如果一个方法声明为会抛出受检异常 (非 Error 或 RuntimeException 及其子类),你必须显式写明 try-catch ,或者选择把这个异常继续向外抛出。例如,假设方法 p1 调用了 p2 ,并且 p2 可能抛出受检异常 IOException, 这时候你的代码只有写成(a)或(b)的形式,才能够通过编译。



12.8例题:声明,抛出并捕捉异常

LISTING
12.7
CircleWithException.java

public class CircleWithException {
/** The radius of the circle */
private double radius;

/** The number of the objects created */
private static int numberOfObjects = 0;

/** Construct a circle with radius 1 */
public CircleWithException() {
this(1.0);
}

/** Construct a circle with a specified radius */
public CircleWithException(double newRadius) {
setRadius(newRadius);
numberOfObjects++;
}

/** Return radius */
public double getRadius() {
return radius;
}

/** Set a new radius */
public void setRadius(double newRadius)
throws IllegalArgumentException {
if (newRadius >= 0)
radius = newRadius;
else
throw new IllegalArgumentException(
"Radius cannot be negative");
}

/** Return numberOfObjects */
public static int getNumberOfObjects() {
return numberOfObjects;
}

/** Return the area of this circle */
public double findArea() {
return radius * radius * 3.14159;
}
}


LISTING
12.8
TestCircleWithException.java

public class TestCircleWithException {
public static void main(String[] args) {
try {
CircleWithException c1 = new CircleWithException(5);
CircleWithException c2 = new CircleWithException(-5);
CircleWithException c3 = new CircleWithException(0);
}
catch (IllegalArgumentException ex) {
System.out.println(ex);
}

System.out.println("Number of objects created: " +
CircleWithException.getNumberOfObjects());
}
}


java.lang.IllegalArgumentException: Radius cannot be negative

Number of objects created: 1

12.9再次抛出异常

try {
statements;
}
catch(TheException ex) {
perform operations before exits;
throw ex;
}


12.10 finally子句

finally的作用是确保语句总能被执行,无论异常是否发生。finally的语法如下:

try {
statements;
}
catch(TheException ex) {
handling ex;
}
finally {
finalStatements;
}

12.11关于异常处理

1、由于将出错处理的代码和常规代码分开,异常处理的可读性和可维护性都很好。
2、不过异常处理需要更多的运行资源和运行时间,因为它需要一个异常的实例,回滚调用堆栈,并调用出错处理方法。
3、何时需要主动抛出异常
异常是在方法中发生的。如果希望异常被调用者自行处理,那就需要创建一个异常并抛出;如果方法可以自己处理异常,那就不需要抛出异常。
4、何时需要使用异常处理
由于效率问题,try-catch块不应该到处使用。应该使用它来处理意外的错误条件。如果是简单的条件,最好不要使用,例如:

try {
System.out.println(refVar.toString());
}
catch (NullPointerException ex) {
System.out.println("refVar is null");
}

因为出错的情况太简单,只有一种可能性,所以上面那个语句块最好写成下面这样:

if (refVar != null)
System.out.println(refVar.toString());
else
System.out.println("refVar is null");

12.12 File类

这个类提供平台无关的,针对文件的操作和文件属性的读取。例如删除文件,查看是否只读,查看文件路径及创建日期等。
注意:File类提供的操作,都是在不需要打开文件就能够进行的。这个类不能读写文件内容。



12.12.1 一个例子

LISTING
12.12
TestFileClass.java

public class TestFileClass {
public static void main(String[] args) {
java.io.File file = new java.io.File("image/us.gif");
System.out.println("Does it exist? " + file.exists());
System.out.println("The file has " + file.length() + " bytes");
System.out.println("Can it be read? " + file.canRead());
System.out.println("Can it be written? " + file.canWrite());
System.out.println("Is it a directory? " + file.isDirectory());
System.out.println("Is it a file? " + file.isFile());
System.out.println("Is it absolute? " + file.isAbsolute());
System.out.println("Is it hidden? " + file.isHidden());
System.out.println("Absolute path is " +
file.getAbsolutePath());
System.out.println("Last modified on " +
new java.util.Date(file.lastModified()));
}
}


12.12.2 文件输入输出

可以用PrintWriter写文本文件。用法和System.out.print差不多,除了需要先打开文件。







12.13 try-with-resources

Java支持一种自动关闭资源(例如文件)的写法,格式为:

try (declare and create resources) {
Use the resource to process the file;
}

小括号内是声明并打开资源的代码,大括号内是针对资源的操作。离开大括号后,资源自动关闭。

12.13.1重写上一个例子

现在可以不用close语句了。这种写法特别适合总是忘记关闭文件的同学。

try (
// Create a file
java.io.PrintWriter output = new java.io.PrintWriter(file);
) {
// Write formatted output to the file
output.print("John T Smith ");
output.println(90);
output.print("Eric K Jones ");
output.println(85);
}


12.14读文本文件

文本文件可以使用Scanner类读取。记得当初从键盘读取输入,我们也用过Scanner。是的,你没有看错,它们就是同一个Scanner。

从键盘读取输入,是这样子的:

Scanner input = new Scanner(System.in);

从文件读取输入,是这样子的:

Scanner input = new Scanner(new File(filename));

也就是说,Scanner的构造方法用于指定源。





12.14.1例题:替换文本

写一个程序,将一个文本文件中的字符串替换成目标字符串,并将结果写入到一个新文件中。命令行格式为:

java ReplaceText sourceFile targetFile oldString newString

用法举例:

java ReplaceText FormatString.java t.txt StringBuilder StringBuffer



<p><u><span style="color:#000000;">//代码段一:检查命令行参数</span></u></p>import java.io.*;
import java.util.*;
public class ReplaceText {
public static void main(String[] args) throws Exception {
// Check command line parameter usage
if (args.length != 4) {
System.out.println("Usage: java ReplaceText sourceFile targetFile oldStr newStr");
System.exit(1);
}
//代码段二:检查文件
// Check if source file exists
File sourceFile = new File(args[0]);
if (!sourceFile.exists()) {
System.out.println("Source file " + args[0] + " does not exist");
System.exit(2);
}
// Check if target file exists
File targetFile = new File(args[1]);
if (targetFile.exists()) {
System.out.println("Target file " + args[1] + " already exists");
System.exit(3);
}
//代码段三:读取、替换、写入
try ( // Create input and output files
Scanner input = new Scanner(sourceFile);
PrintWriter output = new PrintWriter(targetFile);
) {
while (input.hasNext()) {
String s1 = input.nextLine();
String s2 = s1.replaceAll(args[2], args[3]);
output.println(s2);
}
}
}
}
}
}


12.15从网上读取数据

其实,Scanner比你想象的强大,因为它还可以从网上读取数据,只要修改源就可以了。

当然,网络数据是以流(stream)的形式传输的,所以与打开文件的方式略有不同。传输示意如下:



12.15.1 URL (Uniform Resource Locator)

网络资源是用URL来定位的,所以读取之前,需要用URL指定源。例如:

try {

URL url = new URL("http://www.xmu.edu.cn");

} catch (MalformedURLException ex) {

ex.printStackTrace();

}

然后,Scanner就可以读取这个源:

import java.util.Scanner;
public class ReadFileFromURL {
public static void main(String[] args) {
try {
java.net.URL url = new java.net.URL("http://www.xmu.edu.cn/");
int count = 0;
Scanner input = new Scanner(url.openStream());
while (input.hasNext()) {
String line = input.nextLine();
count += line.length();
}
System.out.println("The file size is " + count + " characters");
}
catch (java.net.MalformedURLException ex) {
System.out.println("Invalid URL");
}
catch (java.io.IOException ex) {
System.out.println("I/O Errors: no such file");
}
}
}


12.15.2网络爬虫

网络爬虫是一个自动提取网页的程序,它为搜索引擎从WWW下载网页,是搜索引擎的重要组成。传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。



12.15.3网络爬虫设计

可以从一个网页出发,提取页面上所有http://格式的字符串,然后当作新目标继续爬行。算法如下:

把起始URL添加到队列listOfPendingURLs;

当 listOfPendingURLs非空,且队列listOfTraversedURLs大小<=100 {

URL从listOfPendingURLs出队;

如果URL不在已访问队列listOfTraversedURLs中
{

URL入队listOfTraversedURLs;

显示URL;

读取URL所在页面,搜索页面上所有新URL {

如果新URL没有在队列listOfTraversedURLs中出现,将其入队listOfPendingURLs;

}

}

}

代码段:读取用户输入的URL并开始爬行



代码段:网络爬虫算法的具体实现



代码段:页面URL提取



CHAPTER 12 SUMMARY

1. Exception handling enables a method to throw an exception to its caller.

2. A Java
exception is an instance of a class derived from
java.lang.Throwable. Java provides a number of predefined exception classes, such as
Error,Exception, RuntimeException,
ClassNotFoundException,
NullPointerException, and ArithmeticException. You
can also define your own exception class by extending Exception.

3. Exceptions occur during the execution of a method.
RuntimeException and
Error are
unchecked exceptions; all other exceptions are
checked.

4. When
declaring a method, you have to declare a checked exception if the method might throw it, thus telling the compiler
what can go wrong.

5. The keyword for declaring an exception is
throws, and the keyword for throwing an exception is
throw.

6. To invoke the method that declares checked exceptions, enclose it in a
try statement. When an exception occurs during the execution of the method, the
catch block catches and handles the exception.

7. If an exception is not caught in the current method, it is passed to its caller. The process is repeated
until the exception is caught or passed to the main
method.

8. Various exception classes can be derived from a common superclass. If a
catch block catches the exception objects of a superclass, it can also catch all the exception objects of
the subclasses of that superclass.

9. The order in which exceptions are specified in a
catch block is important. A compile error will result if you specify an exception object of a class after an exception object of

the superclass of that class.

10. When an exception occurs in a method, the method exits immediately if it does not catch the exception.
If the method is required to perform some task before exiting, you can catch the exception in the method and then rethrow it to its caller.

11. The code in the
finally block is executed under all circumstances, regardless of whether an exception occurs in the
try block or whether an exception is caught if it occurs.

12. Exception handling separates error-handling code from normal programming tasks, thus making programs
easier to read and to modify.

13. Exception handling should not be used to replace simple tests. You should perform simple test using
if statements whenever possible, and reserve exception handling for dealing with situations that cannot
be handled with if statements.

14. The
File class is used to obtain file properties and manipulate files. It does not contain the methods for
creating a file or for reading/writing data from/to a file.

15. You can use
Scanner to read string and primitive data values from a text file and use PrintWriter
to create a file and write data to a text file.

16. You can read from a file on the Web using the
URL class.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java