第十二章 异常处理和文本I/O

引言

  • 异常是运行时错误
  • 运行时错误会作为异常抛出
  • 异常就是一种对象,表示阻止正常运行的错误或者情况

概述

  • 异常是从方法抛出的,方法的调用者可以捕获以及处理该异常

  • 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类表示,它描述的是程序设计错误,通常表明了编程错误

  • RuntimeExceptionError以及它们的子类都称为免检异常

  • 所以其他异常都称为必检异常,意味着编译器会强制程序员检查并通过try-catch块处理,或者在方法头进行声明

  • 在大多数情况下,免检异常都会反映出程序设计上不可恢复的逻辑错误

关于异常的更多讨论

  • 异常的处理器是通过从当前的方法开始,沿着方法调用链,按照异常的反向传播方向找到的

声明异常

  • 每个方法都必须声明它可能抛出的必检异常的类型
  • 声明:
public void myMethod( ) throws IOException;
  • 如果在父类中声明异常,那么就不能在子类中对其重写时声明异常

抛出异常

  • 检测到错误的程序可以创建一个合适的异常类型的实例并抛出它
  • 关键字:throw
    在这里插入图片描述

捕获异常

List item

  • 如果在执行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;
  }
}

List item

File类

  • File类包含了获得一个文件/目录的属性,以及对文件/目录进行改名和删除的方法

  • 在文件系统中,每个文件都存放在一个目录下

  • 绝对文件名是由文件名和他的完整路径以及驱动器字母组成

  • 绝对文件名是依赖机器的

  • 相对文件名是相对于当前工作目录的

  • File类用于提供一种抽象,这种抽象是指以不依赖机器的方式来处理很多依赖于机器的文件和路径名的复杂性

  • File类不包含读写文件内容的方法
    在这里插入图片描述

  • 文件名是一个字符串

  • File类是文件名及其目录路径的一个包装类

  • 在Java中,反斜杠\是一个特殊的字符,应该写成\\的形式

  • 在程序中,不要直接使用绝对文件名,应该使用与当前目录相关的文件名

  • 斜杠( / )是Java的目录分隔符

文件输入和输出

  • 使用Scanner类从文件中读取文本数据,使用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();
  }
}

在这里插入图片描述

List item

使用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");
    }
  }
}  
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值