Java 中文官方教程 2022 版(七)(4)

简介: Java 中文官方教程 2022 版(七)

Java 中文官方教程 2022 版(七)(3)https://developer.aliyun.com/article/1486322

优点 2:将错误传播到调用堆栈上

异常的第二个优点是能够将错误报告传播到方法的调用堆栈上。假设readFile方法是主程序进行的一系列嵌套方法调用中的第四个方法:method1调用method2method2调用method3,最终调用readFile

method1 {
    *call method2;*
}
method2 {
    *call method3;*
}
method3 {
    *call readFile;*
}

假设method1是唯一对readFile中可能发生的错误感兴趣的方法。传统的错误通知技术会强制method2method3readFile返回的错误代码传播到调用堆栈上,直到错误代码最终到达method1——唯一对它们感兴趣的方法。

method1 {
    errorCodeType error;
    error = *call method2;*
    if (error)
        *doErrorProcessing;*
    else
        *proceed;*
}
errorCodeType method2 {
    errorCodeType error;
    error = call method3;
    if (error)
        return error;
    else
        *proceed;*
}
errorCodeType method3 {
    errorCodeType error;
    error = call readFile;
    if (error)
        return error;
    else
        *proceed;*
}

请记住,Java 运行时环境会逆向搜索调用堆栈,以找到任何对处理特定异常感兴趣的方法。一个方法可以规避其内部抛出的任何异常,从而允许调用堆栈中更高层的方法捕获它。因此,只有关心错误的方法才需要担心检测错误。

method1 {
    try {
        *call method2;*
    } catch (*exception* e) {
        *doErrorProcessing;*
    }
}
method2 throws *exception* {
    *call method3;*
}
method3 throws exception {
    *call readFile;*
}

然而,正如伪代码所示,规避异常需要中间方法付出一些努力。在方法内部可能抛出的任何已检查异常必须在其throws子句中指定。

优势 3:分组和区分错误类型

因为程序中抛出的所有异常都是对象,异常的分组或分类是类层次结构的自然结果。Java 平台中一组相关的异常类的示例是java.io中定义的那些 — IOException及其后代。IOException是最一般的,表示在执行 I/O 时可能发生的任何类型的错误。其后代表示更具体的错误。例如,FileNotFoundException表示无法在磁盘上找到文件。

一个方法可以编写特定的处理程序,可以处理非常具体的异常。FileNotFoundException类没有后代,因此以下处理程序只能处理一种类型的异常。

catch (FileNotFoundException e) {
    ...
}

一个方法可以通过在catch语句中指定任何异常的超类来基于其组或一般类型捕获异常。例如,为了捕获所有 I/O 异常,无论其具体类型如何,异常处理程序指定一个IOException参数。

catch (IOException e) {
    ...
}

这个处理程序将能够捕获所有 I/O 异常,包括FileNotFoundExceptionEOFException等。您可以通过查询传递给异常处理程序的参数来找到发生的详细信息。例如,使用以下内容打印堆栈跟踪。

catch (IOException e) {
    // Output goes to System.err.
    e.printStackTrace();
    // Send trace to stdout.
    e.printStackTrace(System.out);
}

你甚至可以设置一个异常处理程序,用于处理这里的任何Exception

// *A (too) general exception handler*
catch (Exception e) {
    ...
}

Exception类接近Throwable类层次结构的顶部。因此,此处理程序将捕获许多其他异常,除了处理程序打算捕获的异常之外。如果您只希望程序执行的操作是打印出用户的错误消息,然后退出,您可能希望以这种方式处理异常。

然而,在大多数情况下,您希望异常处理程序尽可能具体。原因是处理程序必须首先确定发生了什么类型的异常,然后才能决定最佳的恢复策略。实际上,通过不捕获特定错误,处理程序必须适应任何可能性。过于一般化的异常处理程序可能会使代码更容易出错,因为它会捕获和处理程序员未预料到的异常,而处理程序并不打算处理这些异常。

正如所指出的,您可以创建异常组并以一般方式处理异常,或者您可以使用特定的异常类型来区分异常并以精确方式处理异常。

摘要

原文:docs.oracle.com/javase/tutorial/essential/exceptions/summary.html

程序可以使用异常来指示发生了错误。要抛出异常,请使用throw语句,并提供一个异常对象 — 一个Throwable的后代 — 以提供有关发生的具体错误的信息。抛出未捕获的已检查异常的方法必须在其声明中包含一个throws子句。

程序可以通过使用trycatchfinally块的组合来捕获异常。

  • try块标识出可能发生异常的代码块。
  • catch块标识出一个代码块,称为异常处理程序,可以处理特定类型的异常。
  • finally块标识出保证执行的代码块,并且是关闭文件、恢复资源以及在try块中封闭的代码之后进行清理的正确位置。

try语句应至少包含一个catch块或一个finally块,并且可以有多个catch块。

异常对象的类表示抛出的异常类型。异常对象可以包含有关错误的进一步信息,包括错误消息。通过异常链接,一个异常可以指向导致它的异常,后者又可以指向导致的异常,依此类推。

问题和练习

原文:docs.oracle.com/javase/tutorial/essential/exceptions/QandE/questions.html

问题

  1. 以下代码是否合法?
try {
} finally {
}
  1. 以下处理程序可以捕获哪些异常类型?
catch (Exception e) {
}
  1. 使用这种类型的异常处理程序有什么问题?
  2. 以下异常处理程序的写法有什么问题?这段代码能编译吗?
try {
} catch (Exception e) {
} catch (ArithmeticException a) {
}
  1. 将第一个列表中的每种情况与第二个列表中的一项进行匹配。
  1. `int[] A;
    A[0] = 0;`
  2. JVM 开始运行您的程序,但 JVM 找不到 Java 平台类。(Java 平台类位于classes.ziprt.jar中。)
  3. 一个程序正在读取流并达到流结束标记。
  4. 在关闭流之前和达到流结束标记之后,一个程序尝试再次读取流。
  5. __ 错误
  6. __ 已检查异常
  7. __ 编译错误
  8. __ 无例外
  1. 练习
  1. ListOfNumbers.java中添加一个readList方法。该方法应从文件中读取int值,打印每个值,并将它们附加到向量的末尾。您应该捕获所有适当的错误。您还需要一个包含要读取的数字的文本文件。
  2. 修改以下cat方法以便能够编译。
public static void cat(File file) {
    RandomAccessFile input = null;
    String line = null;
    try {
        input = new RandomAccessFile(file, "r");
        while ((line = input.readLine()) != null) {
            System.out.println(line);
        }
        return;
    } finally {
        if (input != null) {
            input.close();
        }
    }
}
  1. 检查您的答案。

课程:基本 I/O

原文:docs.oracle.com/javase/tutorial/essential/io/index.html

本课程涵盖了用于基本 I/O 的 Java 平台类。它首先关注* I/O 流*,这是一个极大简化 I/O 操作的强大概念。该课程还涉及序列化,它允许程序将整个对象写入流并再次读取它们。然后课程将查看文件 I/O 和文件系统操作,包括随机访问文件。

大多数在“ I/O 流”部分涵盖的类位于java.io包中。大多数在“文件 I/O”部分涵盖的类位于java.nio.file包中。

I/O 流

  • 字节流处理原始二进制数据的 I/O。
  • 字符流处理字符数据的 I/O,自动处理与本地字符集之间的转换。
  • 缓冲流通过减少对本机 API 的调用次数来优化输入和输出。
  • 扫描和格式化允许程序读取和写入格式化文本。
  • 从命令行进行 I/O 描述了标准流和控制台对象。
  • 数据流处理基本数据类型和String值的二进制 I/O。
  • 对象流处理对象的二进制 I/O。

文件 I/O(使用 NIO.2)

  • 什么是路径?探讨了文件系统上路径的概念。
  • Path 类介绍了java.nio.file包的基石类。
  • 路径操作查看了Path类中处理语法操作的方法。
  • 文件操作介绍了许多文件 I/O 方法共有的概念。
  • 检查文件或目录展示了如何检查文件的存在性和可访问性级别。
  • 删除文件或目录。
  • 复制文件或目录。
  • 移动文件或目录。
  • 管理元数据解释了如何读取和设置文件属性。
  • 读取、写入和创建文件展示了读取和写入文件的流和通道方法。
  • 随机访问文件展示了如何以非顺序方式读取或写入文件。
  • 创建和读取目录涵盖了特定于目录的 API,例如如何列出目录的内容。
  • 链接,符号或其他涵盖了与符号链接和硬链接相关的特定问题。
  • 遍历文件树演示了如何递归访问文件树中的每个文件和目录。
  • 查找文件展示了如何使用模式匹配搜索文件。
  • 监视目录变化展示了如何使用监视服务检测一个或多个目录中添加、删除或更新的文件。
  • 其他有用的方法涵盖了在本课程中其他地方无法涵盖的重要 API。
  • 旧版文件 I/O 代码展示了如何利用Path功能,如果你的旧代码使用了java.io.File类。提供了一个将java.io.File API 映射到java.nio.file API 的表格。

总结

本教程涵盖的关键要点总结。

问题和练习

通过尝试这些问题和练习来测试你在本教程中学到的知识。

I/O 类的实际运用

下一个教程中的许多示例,自定义网络,使用了本课程中描述的 I/O 流来从网络连接读取和写入。


安全注意事项: 一些 I/O 操作需要当前安全管理器的批准。这些教程中包含的示例程序是独立应用程序,默认情况下没有安全管理器。要在小程序中运行,大多数这些示例都需要进行修改。查看小程序的能力和限制以获取有关小程序所受的安全限制的信息。


I/O 流

原文:docs.oracle.com/javase/tutorial/essential/io/streams.html

I/O 流表示输入源或输出目的地。流可以表示许多不同类型的源和目的地,包括磁盘文件、设备、其他程序和内存数组。

流支持许多不同类型的数据,包括简单的字节、基本数据类型、本地化字符和对象。一些流只是传递数据;另一些以有用的方式操作和转换数据。

无论它们内部如何工作,所有流对使用它们的程序呈现相同简单的模型:流是一系列数据。程序使用输入流从源读取数据,一次读取一个项目:

将信息读入程序。

程序使用输出流向目的地写入数据,一次写入一个项目:

将信息从程序写入。

在本课程中,我们将看到可以处理从基本值到高级对象的各种数据的流。

上图中的数据源和数据目的地可以是任何保存、生成或消耗数据的东西。显然,这包括磁盘文件,但源或目的地也可以是另一个程序、外围设备、网络套接字或数组。

在下一节中,我们将使用最基本的流类型,字节流,来演示流 I/O 的常见操作。作为示例输入,我们将使用示例文件xanadu.txt,其中包含以下诗句:

In Xanadu did Kubla Khan
A stately pleasure-dome decree:
Where Alph, the sacred river, ran
Through caverns measureless to man
Down to a sunless sea.

字节流

原文:docs.oracle.com/javase/tutorial/essential/io/bytestreams.html

程序使用字节流来执行 8 位字节的输入和输出。所有字节流类都是从InputStreamOutputStream继承而来。

有许多字节流类。为了演示字节流的工作原理,我们将重点放在文件 I/O 字节流FileInputStreamFileOutputStream上。其他类型的字节流使用方式基本相同;它们主要在构造方式上有所不同。

使用字节流

我们将通过检查一个名为CopyBytes的示例程序来探讨FileInputStreamFileOutputStream,该程序使用字节流逐字节复制xanadu.txt

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CopyBytes {
    public static void main(String[] args) throws IOException {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream("xanadu.txt");
            out = new FileOutputStream("outagain.txt");
            int c;
            while ((c = in.read()) != -1) {
                out.write(c);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

CopyBytes 在一个简单的循环中花费大部分时间,逐字节读取输入流并写入输出流,如下图所示。

简单的字节流输入和输出。

总是关闭流

当不再需要流时关闭流非常重要—非常重要,以至于CopyBytes 使用finally块来确保即使发生错误,两个流也将被关闭。这种做法有助于避免严重的资源泄漏。

一个可能的错误是CopyBytes 无法打开一个或两个文件。当发生这种情况时,对应于文件的流变量从未从其初始的null值更改。这就是为什么CopyBytes 确保每个流变量在调用close之前包含一个对象引用。

何时不使用字节流

CopyBytes 看起来像一个普通程序,但实际上代表了一种应该避免的低级 I/O。由于xanadu.txt包含字符数据,最好的方法是使用字符流,如下一节所讨论的。还有用于更复杂数据类型的流。字节流应该仅用于最基本的 I/O。

那么为什么要谈论字节流呢?因为所有其他流类型都是建立在字节流之上的。

字符流

原文:docs.oracle.com/javase/tutorial/essential/io/charstreams.html

Java 平台使用 Unicode 约定存储字符值。字符流 I/O 会自动将内部格式与本地字符集进行转换。在西方区域,本地字符集通常是 ASCII 的 8 位超集。

对于大多数应用程序,使用字符流进行 I/O 与使用字节流进行 I/O 并无太大区别。使用流类进行的输入和输出会自动转换为本地字符集。使用字符流而不是字节流的程序会自动适应本地字符集,并且为国际化做好准备,而无需程序员额外努力。

如果国际化不是首要任务,您可以简单地使用字符流类,而不必过多关注字符集问题。稍后,如果国际化成为首要任务,您的程序可以在不进行大量重编码的情况下进行调整。查看国际化教程以获取更多信息。

使用字符流

所有字符流类都是从ReaderWriter继承而来。与字节流一样,有专门用于文件 I/O 的字符流类:FileReaderFileWriterCopyCharacters示例演示了这些类。

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyCharacters {
    public static void main(String[] args) throws IOException {
        FileReader inputStream = null;
        FileWriter outputStream = null;
        try {
            inputStream = new FileReader("xanadu.txt");
            outputStream = new FileWriter("characteroutput.txt");
            int c;
            while ((c = inputStream.read()) != -1) {
                outputStream.write(c);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

CopyCharactersCopyBytes非常相似。最重要的区别在于,CopyCharacters使用FileReaderFileWriter进行输入和输出,而不是FileInputStreamFileOutputStream。请注意,CopyBytesCopyCharacters都使用一个int变量进行读取和写入。但是,在CopyCharacters中,int变量在其最后 16 位中保存字符值;而在CopyBytes中,int变量在其最后 8 位中保存byte值。

使用字节流的字符流

字符流通常是字节流的“包装器”。字符流使用字节流执行物理 I/O,而字符流处理字符和字节之间的转换。例如,FileReader使用FileInputStream,而FileWriter使用FileOutputStream

有两个通用的字节到字符的“桥梁”流:InputStreamReaderOutputStreamWriter。当没有符合您需求的预打包字符流类时,请使用它们来创建字符流。网络教程中的套接字课程展示了如何从套接字类提供的字节流创建字符流。

面向行的 I/O

字符 I/O 通常以比单个字符更大的单位进行。一个常见的单位是行:一串带有行终止符的字符。行终止符可以是回车/换行序列("\r\n"),单个回车("\r")或单个换行("\n")。支持所有可能的行终止符允许程序读取在任何广泛使用的操作系统上创建的文本文件。

让我们修改CopyCharacters示例以使用面向行的 I/O。为此,我们必须使用两个以前未见过的类,BufferedReaderPrintWriter。我们将在缓冲 I/O 和格式化中更深入地探讨这些类。现在,我们只关注它们对面向行的 I/O 的支持。

CopyLines示例调用BufferedReader.readLinePrintWriter.println来逐行进行输入和输出。

import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.PrintWriter;
import java.io.IOException;
public class CopyLines {
    public static void main(String[] args) throws IOException {
        BufferedReader inputStream = null;
        PrintWriter outputStream = null;
        try {
            inputStream = new BufferedReader(new FileReader("xanadu.txt"));
            outputStream = new PrintWriter(new FileWriter("characteroutput.txt"));
            String l;
            while ((l = inputStream.readLine()) != null) {
                outputStream.println(l);
            }
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
        }
    }
}

调用readLine返回带有行的文本。CopyLines使用println输出每一行,该方法会附加当前操作系统的行终止符。这可能与输入文件中使用的行终止符不同。

除了字符和行之外,还有许多结构化文本输入和输出的方式。更多信息,请参见扫描和格式化。

相关文章
|
9天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)
【4月更文挑战第21天】本文介绍了Selenium中处理特殊测试场景的方法,如鼠标悬停。Selenium的Actions类提供了鼠标悬停功能,用于模拟用户在网页元素上的悬停行为。文中通过实例展示了如何使用Actions悬停并展开下拉菜单,以及在搜索时选择自动补全的字段。代码示例包括了打开百度首页,悬停在“更多”元素上显示下拉菜单并点击“音乐”,以及在搜索框输入关键词并自动补全的过程。
33 0
|
1天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)
【4月更文挑战第28天】本文简要介绍了自动化测试的实战应用,通过一个在线问卷调查(<https://www.sojump.com/m/2792226.aspx/>)为例,展示了如何遍历并点击问卷中的选项。测试思路包括找到单选和多选按钮的共性以定位元素,然后使用for循环进行点击操作。代码设计方面,提供了Java+Selenium的示例代码,通过WebDriver实现自动答题。运行代码后,可以看到控制台输出和浏览器的相应动作。文章最后做了简单的小结,强调了本次实践是对之前单选多选操作的巩固。
9 0
|
2天前
|
Java 测试技术 项目管理
Java基础教程(22)-构建工具Maven的基本使用
【4月更文挑战第22天】Maven是Java项目管理及构建工具,简化构建、测试、打包和部署等任务。遵循约定优于配置原则,核心是`pom.xml`配置文件,用于管理依赖和项目信息。安装涉及下载、解压、配置环境变量。在IDEA中使用Maven创建项目,通过`pom.xml`添加依赖和管理版本。常用命令包括`clean`、`compile`、`test`、`package`、`install`和`deploy`。IDEA支持直接执行这些命令。
|
2天前
|
NoSQL Java 关系型数据库
Java基础教程(21)-Java连接MongoDB
【4月更文挑战第21天】MongoDB是开源的NoSQL数据库,强调高性能和灵活性。Java应用通过MongoDB Java驱动与之交互,涉及MongoClient、MongoDatabase、MongoCollection和Document等组件。连接MongoDB的步骤包括:配置连接字符串、创建MongoClient、选择数据库和集合。伪代码示例展示了如何建立连接、插入和查询数据。
|
3天前
|
存储 前端开发 测试技术
《手把手教你》系列技巧篇(三十五)-java+ selenium自动化测试-单选和多选按钮操作-下篇(详解教程)
【4月更文挑战第27天】本文介绍了使用Java+Selenium进行Web自动化测试时,如何遍历和操作多选按钮的方法。文章分为两个部分,首先是一个本地HTML页面的示例,展示了多选按钮的HTML代码和页面效果,并详细解释了遍历多选按钮的思路:找到所有多选按钮的共同点,通过定位这些元素并放入list容器中,然后使用for循环遍历并操作。 第二部分介绍了在JQueryUI网站上的实战,给出了被测网址,展示了代码设计,同样使用了findElements()方法获取所有多选按钮并存储到list中,然后遍历并进行点击操作。最后,文章对整个过程进行了小结,并推荐了作者的其他自动化测试教程资源。
11 0
|
3天前
|
Java 关系型数据库 MySQL
Java基础教程(20)-Java连接mysql数据库CURD
【4月更文挑战第19天】MySQL是流行的关系型数据库管理系统,支持SQL语法。在IDEA中加载jar包到项目类路径:右击项目,选择“Open Module Settings”,添加库文件。使用JDBC连接MySQL,首先下载JDBC驱动,然后通过`Class.forName()`加载驱动,`DriverManager.getConnection()`建立连接。执行CRUD操作,例如创建表、插入数据和查询,使用`Statement`或`PreparedStatement`,并确保正确关闭数据库资源。
|
4天前
|
设计模式 算法 Java
Java基础教程(19)-设计模式简述
【4月更文挑战第19天】设计模式是软件设计中反复使用的代码设计经验,旨在提升代码的可重用性、可扩展性和可维护性。23种模式分为创建型、结构型和行为型三类。创建型模式如工厂方法、抽象工厂、建造者、原型和单例,关注对象创建与使用的分离。结构型模式涉及对象组合,如适配器、装饰器、外观等,增强结构灵活性。行为型模式专注于对象间职责分配和算法合作,包括责任链、命令、观察者等。设计模式提供标准化解决方案,促进代码交流和复用。
|
4天前
|
前端开发 测试技术 Python
《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)
【4月更文挑战第25天】本文介绍了自动化测试中如何处理单选和多选按钮的操作,包括它们的定义、HTML代码示例以及如何判断和操作这些元素。文章通过一个简单的HTML页面展示了单选和多选框的示例,并提供了Java+Selenium实现的代码示例,演示了如何检查单选框是否选中以及如何进行全选操作。
11 0
|
5天前
|
网络协议 Java 网络架构
Java基础教程(18)-Java中的网络编程
【4月更文挑战第18天】Java网络编程简化了底层协议处理,利用Java标准库接口进行TCP/IP通信。TCP协议提供可靠传输,常用于HTTP、SMTP等协议;UDP协议则更高效但不保证可靠性。在TCP编程中,ServerSocket用于监听客户端连接,Socket实现双进程间通信。UDP编程中,DatagramSocket处理无连接的数据报文。HTTP编程可以通过HttpURLConnection发送请求并接收响应。
|
6天前
|
前端开发 Java 测试技术
《手把手教你》系列技巧篇(三十二)-java+ selenium自动化测试-select 下拉框(详解教程)
【4月更文挑战第24天】本文介绍了在自动化测试中处理HTML下拉选择(select)的方法。使用Selenium的Select类,可以通过index、value或visible text三种方式选择选项,并提供了相应的取消选择的方法。此外,文章还提供了一个示例HTML页面(select.html)和相关代码实战,演示了如何使用Selenium进行选择和取消选择操作。最后,文章提到了现代网页中类似下拉框的新设计,如12306网站的出发地选择,并给出了相应的代码示例,展示了如何定位并选择特定选项。
16 0