引言
- 异常是运行时错误
- 运行时错误会作为异常抛出
- 异常就是一种对象,表示阻止正常运行的错误或者情况
概述
-
异常是从方法抛出的,方法的调用者可以捕获以及处理该异常
-
Java可以让一个方法可以抛出一个异常,该异常可以被调用者捕获和处理
import java.util.Scanner;
public class QuotientWithException {
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 ...");
}
}
throw
语句的执行称为抛出一个异常- 调用方法的语句包含在一个
try
块和一个catch
块中 try
块包含了正常情况下执行的代码- 异常被
catch
块捕获,catch
块中的代码被执行以处理异常,之后,catch
块之后的语句被执行 catch (ArithmeticException ex)
中的ex
的作用很像是方法中的参数,所以,这个参数被称为catch
块的参数,ex
之前的类型指定了catch
块可以捕获的异常类型,一旦捕获该异常,就能从catch
块体中的参数访问这个抛出的值- 一个异常可能是通过
try
块中的throw
语句直接抛出,或者调用一个可能回抛出异常的方法而抛出
-异常处理可以使方法抛出一个异常给它的调用者,并由调用者处理该异常
异常处理最根本的优势是将检测错误(由被调用的方法完成)从处理错误(调用方法完成)中分离出来
异常类型
-
异常是对象,而对象都采用类定义
-
异常的根类是
java.lang.Throwable
-
预定义的异常类:
-
分类:
-
系统错误:由Java虚拟机抛出,用Error类表示,
Error
类描述的是内部系统错误,几乎什么都不能做 -
异常:用
Exception
类表示,描述的是由你的程序和外部环境所引起的错误,这些错误能被程序捕获和处理 -
运行时异常:用
RuntimeException
类表示,它描述的是程序设计错误,通常表明了编程错误 -
RuntimeException
,Error
以及它们的子类都称为免检异常 -
所以其他异常都称为必检异常,意味着编译器会强制程序员检查并通过
try-catch
块处理,或者在方法头进行声明 -
在大多数情况下,免检异常都会反映出程序设计上不可恢复的逻辑错误
关于异常的更多讨论
- 异常的处理器是通过从当前的方法开始,沿着方法调用链,按照异常的反向传播方向找到的
声明异常
- 每个方法都必须声明它可能抛出的必检异常的类型
- 声明:
public void myMethod( ) throws IOException;
- 如果在父类中声明异常,那么就不能在子类中对其重写时声明异常
抛出异常
- 检测到错误的程序可以创建一个合适的异常类型的实例并抛出它
- 关键字:
throw
捕获异常
- 如果在执行
try
块的过程中没有出现异常,则跳过catch
子句
- 各种异常类可以从一个共同的父类中派生,如果一个catch块可以捕获一个父类的异常对象,他就能捕获那个父类的所有子类的异常对象
- 在catch块中异常被指定的顺序很重要,如果父类的catch块出现在子类的catch块之前,就会导致编译错误
- Java强制程序员必须处理异常
从异常中获取信息
- 异常对象中包含关于异常的有价值的信息
finally子句
- 无论异常是否发生,finally子句总会被执行
- 语法:
try{
statements;
}
catch (TheException ex){
handling ex;
}
finally{
finalStatements;
}
- 在任何情况下,
finally
块中的代码都会执行,不论try块中是否出现异常或者是否被捕获
何时使用异常
- 当错误需要被方法的调用者处理的的时候,方法应该抛出一个异常
- 异常处理通常需要更多的时间和资源
- 异常发生在方法中
- 当必须处理不可预料的错误状况时应该使用
try- catch
块 - 不要用
try-catch
块处理简单的,可预料的情况 - 不要把异常处理错误地用来做简单的逻辑测试
重新抛出异常
- 如果异常处理器不能处理一个异常,或者只是简单地希望它的调用者注意到该异常,Java允许该异常处理器重新抛出异常
- 语法:
try{
statements;
}
catch(TheException ex){
perform operations before exits;
throw ex;
}
链式异常
- 与另一个异常一起抛出一个异常,构成了链式异常
创建自定义异常类
- 可以通过继承
java.lang.Exception
类来定义一个自定义异常类
public class InvalidRadiusException extends Exception {
private double radius;
/** Construct an exception */
public InvalidRadiusException(double radius) {
super("Invalid radius " + radius);
this.radius = radius;
}
/** Return the radius */
public double getRadius() {
return radius;
}
}
File类
-
File类包含了获得一个文件/目录的属性,以及对文件/目录进行改名和删除的方法
-
在文件系统中,每个文件都存放在一个目录下
-
绝对文件名是由文件名和他的完整路径以及驱动器字母组成
-
绝对文件名是依赖机器的
-
相对文件名是相对于当前工作目录的
-
File类用于提供一种抽象,这种抽象是指以不依赖机器的方式来处理很多依赖于机器的文件和路径名的复杂性
-
File类不包含读写文件内容的方法
-
文件名是一个字符串
-
File类是文件名及其目录路径的一个包装类
-
在Java中,反斜杠
\
是一个特殊的字符,应该写成\\
的形式 -
在程序中,不要直接使用绝对文件名,应该使用与当前目录相关的文件名
-
斜杠( / )是Java的目录分隔符
文件输入和输出
- 使用
Scanne
r类从文件中读取文本数据,使用PrintWeiter
类向文本文件写入数据 - 文件类型:文本和二进制
- 文本文件实质上是存储在磁盘上的字符
使用PrinterWriter
写数据
java.io.PrintWriter
类可用来创建一个文件并向文本文件写入数据- 首先,创建一个
PrintWriter
对象:
PrintWriter output = new PrintWriter(Filename);
PrintWriter
中的常用方法
public class WriteData {
public static void main(String[] args) throws Exception {
java.io.File file = new java.io.File("scores.txt");
if (file.exists()) {
System.out.println("File already exists");
System.exit(0);
}
// 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);
// Close the file
output.close();
}
}
使用try-with-resources自动关闭资源
- 使用新的
try-with-resources
语法来自动关闭文件
try(声明和创建资源){
使用资源来处理文件;
}
public static void main(String[] args) throws Exception {
java.io.File file = new java.io.File("scores1.txt");
if (file.exists()) {
System.out.println("File already exists");
System.exit(0);
}
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);
}
}
}
- 关键字
try
后声明和创建了一个资源 - 注意:资源放在括号中
- 资源必须是
AutoCloseable
的子类型 - 资源的声明和创建必须在同一个语句中,并且可以在括号中进行多个资源的声明和创建
使用Scanner读取数据
- 需要为文件创建一个
Scanner
Scanner input = new Scanner(new File(filename));
- Scanner中的常用方法:
import java.util.Scanner;
public class ReadData {
public static void main(String[] args) throws Exception {
// Create a File instance
java.io.File file = new java.io.File("scores.txt");
// Create a Scanner for the file
Scanner input = new Scanner(file);
// Read data from a file
while (input.hasNext()) {
String firstName = input.next();
String mi = input.next();
String lastName = input.next();
int score = input.nextInt();
System.out.println(
firstName + " " + mi + " " + lastName + " " + score);
}
// Close the file
input.close();
}
}
- 没有必要关闭输入文件,但这是一种释放被文件占用的自愿的好做法
Scanner如何工作
从Web上读取数据
-
URL:统一资源定位符,即为Web上的文件提供唯一的地址
-
使用
java.net.URL
类的以下构造方法创建一个对象 -
public URL(String spec) throws MalformedURLException
-
要让URL类来识别一个有效的URL,前缀
http://
是必需的 -
创建了一个URL对象后,可以使用URL类中定义的openStream( )方法来打开一个输入流,并且使用这个输入流来创建一个
Scanner
对象 -
Scanner input = new Scaner( url.openStream( ));
import java.util.Scanner;
public class ReadFileFromURL {
public static void main(String[] args) {
System.out.print("Enter a URL: ");
String URLString = new Scanner(System.in).next(); //提示用户输入一个URL字符串
try {
java.net.URL url = new java.net.URL(URLString); //创建一个URL对象
int count = 0;
Scanner input = new Scanner(url.openStream()); //从URL的输入流中创建一个Scanner对象
while (input.hasNext()) {
String line = input.nextLine();
count += line.length();
}
System.out.println("The file size is " + count + " characters");
}
catch (java.net.MalformedURLException ex) { //没有正确表示URL
System.out.println("Invalid URL");
}
catch (java.io.IOException ex) { //URL不存在
System.out.println("IO Errors");
}
}
}