012 异常处理和文本 IO

本贴最后更新于 2046 天前,其中的信息可能已经时移世改

本文为《Java 语言程序设计》第十版 章节笔记

12.1 引言

异常 就是一种对象,表示阻止正常进行程序执行的错误或情况。

12.2 异常处理概述

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

不应该让方法来终止程序,应该由调用者决定是否终止程序。Java 可以让一个方法可以抛出一个异常,该异常可以被调用者捕获和处理。

  • throw 语句 的执行称为抛出一个异常。
  • catch 块 中的代码执行处理异常。

catch(ExceptionName ex) ,标识符 ex 的作用很像是方法中的参数,称为 catch 块的参数。

一个异常可能是通过 try 块中的 throw 语句直接抛出,或者调用一个可能抛出异常的方法而抛出。

异常处理的最根本的优势就是将检测错误(由被调用的方法完成)从处理错误(由调用方法完成)中分离出来。

12.3 异常类型

异常 IO
异常的根类是 java.lang.Throwable

可以通过继承 Exception 或者 Exception 的子类来创建自己的异常类。

RuntimeExceptionError 以及它们的子类都称为免检异常(unchecked exception)。所有其他异常都成为必检异常(checked exception),意思是指编译器会强制程序员检查并通过 try-catch 块处理它们,或者在方法头进行声明。

12.4 关于异常处理的更多知识

Java 的异常处理模型基于三种操作:声明一个异常(declaring an exception)、抛出一个异常(throwing an exception)和捕获一个异常(catching an exception)。

12.4.1 声明异常

为了在方法中声明一个异常,就要在方法头中使用关键字 throws,如:public void myMethod() throws IOException。多个异常用逗号隔开。

注意:如果方法没有在父类中声明异常,那么就不能在子类中对其进行继承来声明异常。

12.4.2 抛出异常

抛出一个异常:检测到错误的程序可以创建一个合适的异常类型的实例并抛出它。

提示:声明异常的关键字是 throws,抛出异常的关键字是 throw。

12.4.3 捕获异常

如果在执行 try 块的过程中没有出现异常,则跳过 catch 子句。

如果 try 块中的某条语句抛出一个异常,Java 就会跳过 try 块中的剩余语句,然后开始查找处理这个异常的代码的过程。处理这个异常的代码称为异常处理器。

寻找处理器的过程称为捕获一个异常。

12.4.4 从异常中获取信息

java.lang.Thorwable

12.5 finally 子句

无论异常是否产生,finally 子句总是会被执行的。即使在到达 finally 块之前有一个 return 语句,finally 块还是会执行。

注意:使用 finally 子句时可以省略掉 catch 块。

12.6 何时使用异常

当错误需要被方法的调用者处理的时候,方法应该抛出一个异常。

一般来说,一个项目中多个类都会发生的共同异常应该考虑作为一个异常类。对于发生在个别方法中的简单错误最好进行局部处理,无需抛出异常。

在代码中何时应该使用 try-catch 块呢?当必须处理不可预料的错误状况时应该使用它。

12.7 重新抛出异常

如果异常处理器不能处理一个异常,或者只是简单地希望它的调用者注意到该异常,Java 允许该异常处理器重新抛出异常。

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

12.8 链式异常

catch 块重新抛出原始的异常后,有时候,可能需要同原始异常一起抛出一个新的异常(带有附加信息),这称为链式异常。

12.9 创建自定义异常类

可以通过派生 java.lang.Exception 类来定义一个自定义异常类。

12.10 File 类

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

但是,File 类不包含读写文件内容的方法。

绝对文件名(absolute file name)是由文件名和它的完整路径以及驱动器字符组成。
绝对文件名 = 驱动器字符 + 完整路径 + 文件名
例如,c:\book\Welcome.java 是文件 Welcome.java 在 Window 操作系统的绝对文件名。

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

java.File

构建一个 File 实例并不会在机器上创建一个文件。不管文件是否存在,都可以创建任意文件名的 File 实例。可以调用 File 实例上的 exists()方法来判断这个文件是否存在。

在程序中,不要直接使用绝对文件名。

12.11 文件输入和输出

使用 Scanner 类从文件中读取文件数据,使用 PrintWriter 类向文本文件写入数据。

java.io.PrintWriter 类可用来创建一个文件并向文本文件写入数据。

java.io.PrintWriter

必须使用 close() 方法关闭文件,如果没有调用该方法,数据就不能正确的保存在文件中。

使用 try-with-resources 自动关闭资源

JDK 7 提供了下面的额新的 try-with-resources 语法来自动关闭文件:

try ( 声明和创建资源 ) {
    使用资源来处理文件;
}

资源必须是 AutoCloseable 的子类型,比如 PrinterWriter,具有一个 close()方法。
处理完后,资源的 close()方法自动调用以关闭资源。

使用 Scanner 读取数据

java.util.Scanner

Scanner 如何工作

方法 nextByte()、nextShort()、nextInt()、nextLong()、nextFloat()、nextDouble()和 next() 等都称为 标记读取方法(token-reading method),因为它们会读取用分隔符分隔开的标记。默认情况下,分隔符是空格。可以使用 useDelimiter(String regex) 方法设置新的分隔符模式。

一个标记读取方法首先跳过任意分隔符(默认情况下是空格),然后去读一个以分隔符结束的标记,并把标记自动转换成相应的类型值。不匹配,抛出异常 java.util.InputMismatchException

方法 next() 和 enxtLine() 都会读取一个字符串。next() 方法读取一个由 分隔符 分隔的 字符串,但是 nextLine() 读取一个以换行符结束的行(不包括换行符)。

12.12 从 Web 上读取数据

  • 为了读取一个文件,首先要使用 java.net.URL 类的这个构造方法,为该文件创建一个 URL 对象。
    public URL(String spec) throws MalformedURLException

    URL url = new URL("http://www.google.com/index.html");

  • 创建一个 URL 对象后,使用 URL 类中定义的 openStream() 方法来打开输入流和用输入流创建如下 Scanner 对象。
    Scanner input = new Scanner(url.openStream());

现在就可以从输入流中读取数据了,就如同从本地文件中的读取一样。

//web爬虫
import java.util.Scanner;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.io.FileNotFoundException;
import java.io.FileWrite;

public class Test {
  public static void main(String[] args) {
    java.util.Scanner input = new java.util.Scanner(System.in);
    System.out.print("Enter a URL: ");
    String url = input.nextLine(); 
    crawler(url); // Traverse the Web from the a starting url
  }

  public static void crawler(String startingURL) {
    ArrayList<String> listOfPendingURLs = new ArrayList<>();
    ArrayList<String> listOfTraversedURLs = new ArrayList<>();
    
    listOfPendingURLs.add(startingURL);
    while (!listOfPendingURLs.isEmpty() && 
        listOfTraversedURLs.size() <= 10) {
      String urlString = listOfPendingURLs.remove(0);
      if (!listOfTraversedURLs.contains(urlString)) {
        listOfTraversedURLs.add(urlString);
        System.out.println("Craw " + urlString);

            java.io.File file = new java.io.File("web-crawler.txt");
            FileWrite fw = new FileWrite(file, true);
            try {
              PrintWriter output = new PrintWriter(file);
              output.print(urlString); 
              output.close(); 
            }catch(FileNotFoundException ex){
              System.out.println(ex);
            }        

        for (String s: getSubURLs(urlString)) {
          if (!listOfTraversedURLs.contains(s))
            listOfPendingURLs.add(s);
        }
      }
    }
  }
  
  public static ArrayList<String> getSubURLs(String urlString) {
    ArrayList<String> list = new ArrayList<>();
    
    try {
      java.net.URL url = new java.net.URL(urlString); 
      Scanner input = new Scanner(url.openStream());
      int current = 0;
      while (input.hasNext()) {
        String line = input.nextLine();
        current = line.indexOf("http:", current);
        while (current > 0) {
          int endIndex = line.indexOf("\"", current);
          if (endIndex > 0) { // Ensure that a correct URL is found
            list.add(line.substring(current, endIndex)); 
            current = line.indexOf("http:", endIndex);
          }
          else 
            current = -1;
        }
      } 
    }
    catch (Exception ex) {
      System.out.println("Error: " + ex.getMessage());
    }
    
    return list;
  }
}

END

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3168 引用 • 8207 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...