Java 中文官方教程 2022 版(九)(2)

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

Java 中文官方教程 2022 版(九)(1)https://developer.aliyun.com/article/1486342

观察服务概述

WatchService API 相当低级,允许您自定义它。您可以直接使用它,或者您可以选择在此机制之上创建一个高级 API,以使其适合您的特定需求。

下面是实现观察服务所需的基本步骤:

  • 为文件系统创建一个WatchService“观察者”。
  • 对于要监视的每个目录,请将其注册到观察者中。在注册目录时,指定要接收通知的事件类型。您为每个注册的目录收到一个WatchKey实例。
  • 实现一个无限循环以等待传入事件。当事件发生时,键被标记并放入观察者队列中。
  • 从观察者队列中检索键。您可以从键中获取文件名。
  • 检索键的每个待处理事件(可能有多个事件)并根据需要处理。
  • 重置键,并恢复等待事件。
  • 关闭服务:当线程退出或调用其closed方法关闭服务时,监视服务将退出。

WatchKeys是线程安全的,可以与java.nio.concurrent包一起使用。您可以为此目的专门分配一个线程池。

试一试

由于此 API 更为高级,请在继续之前先尝试一下。将WatchDir示例保存到您的计算机上,并对其进行编译。创建一个将传递给示例的test目录。WatchDir使用单个线程处理所有事件,因此在等待事件时会阻止键盘输入。要么在单独的窗口中运行程序,要么在后台运行,如下所示:

java WatchDir test &

test目录中创建、删除和编辑文件。当发生任何这些事件时,将在控制台上打印消息。完成后,删除test目录,WatchDir退出。或者,如果您愿意,也可以手动终止进程。

您还可以通过指定-r选项来监视整个文件树。当您指定-r时,WatchDir遍历文件树,将每个目录注册到监视服务中。

创建监视服务并注册事件

第一步是通过FileSystem类中的newWatchService方法创建一个新的WatchService,如下所示:

WatchService watcher = FileSystems.getDefault().newWatchService();

接下来,向监视服务注册一个或多个对象。任何实现了Watchable接口的对象都可以注册。Path类实现了Watchable接口,因此要监视的每个目录都被注册为一个Path对象。

与任何Watchable一样,Path类实现了两个register方法。本页使用了两个参数版本的register(WatchService, WatchEvent.Kind...)。(三个参数版本接受一个WatchEvent.Modifier,目前尚未实现。)

在向监视服务注册对象时,您需要指定要监视的事件类型。支持的StandardWatchEventKinds事件类型如下:

  • ENTRY_CREATE – 创建目录条目。
  • ENTRY_DELETE – 删除目录条目。
  • ENTRY_MODIFY – 修改目录条目。
  • OVERFLOW – 表示事件可能已丢失或被丢弃。您无需注册OVERFLOW事件即可接收它。

以下代码片段显示了如何为所有三种事件类型注册Path实例:

import static java.nio.file.StandardWatchEventKinds.*;
Path dir = ...;
try {
    WatchKey key = dir.register(watcher,
                           ENTRY_CREATE,
                           ENTRY_DELETE,
                           ENTRY_MODIFY);
} catch (IOException x) {
    System.err.println(x);
}

处理事件

事件处理循环中事件的顺序如下:

  1. 获取一个监视键。提供了三种方法:
  • poll – 如果可用,则返回一个排队的键。如果不可用,则立即返回null值。
  • poll(long, TimeUnit) – 如果有排队的键可用,则返回一个。如果没有立即可用的排队键,则程序将等待指定的时间。TimeUnit参数确定指定的时间是纳秒、毫秒还是其他时间单位。
  • take – 返回一个排队的键。如果没有可用的排队键,此方法将等待。
  1. 处理键的待处理事件。您从pollEvents方法中获取WatchEventsList
  2. 使用kind方法检索事件的类型。无论键注册了什么事件,都有可能收到OVERFLOW事件。您可以选择处理溢出或忽略它,但应该对其进行测试。
  3. 检索与事件关联的文件名。文件名存储为事件的上下文,因此使用context方法来检索它。
  4. 处理键的事件后,需要通过调用reset将键放回ready状态。如果此方法返回false,则键不再有效,循环可以退出。这一步非常重要。如果未调用reset,则此键将不会接收到进一步的事件。

观察键具有状态。在任何给定时间,其状态可能是以下之一:

  • Ready表示键已准备好接受事件。创建时,键处于准备状态。
  • Signaled表示有一个或多个事件排队。一旦键被标记,它就不再处于准备状态,直到调用reset方法。
  • Invalid表示键不再活动。当发生以下事件之一时,会出现此状态:
  • 进程通过使用cancel方法显式取消键。
  • 目录变得无法访问。
  • 观察服务已经被关闭

这里是一个事件处理循环的示例。它取自于 Email 示例,该示例监视一个目录,等待新文件出现。当新文件可用时,通过使用 probeContentType(Path) 方法来检查它是否是一个 text/plain 文件。意图是将 text/plain 文件发送到一个别名,但具体实现细节留给读者。

Watch service API 特定的方法用粗体显示:

for (;;) {
    // wait for key to be signaled
    WatchKey key;
    try {
        key = watcher.take();
    } catch (InterruptedException x) {
        return;
    }
    for (WatchEvent<?> event: key.pollEvents()) {
        WatchEvent.Kind<?> kind = event.kind();
        // This key is registered only
        // for ENTRY_CREATE events,
        // but an OVERFLOW event can
        // occur regardless if events
        // are lost or discarded.
        if (kind == OVERFLOW) {
            continue;
        }
        // The filename is the
        // context of the event.
        WatchEvent<Path> ev = (WatchEvent<Path>)event;
        Path filename = ev.context();
        // Verify that the new
        //  file is a text file.
        try {
            // Resolve the filename against the directory.
            // If the filename is "test" and the directory is "foo",
            // the resolved name is "test/foo".
            Path child = dir.resolve(filename);
            if (!Files.probeContentType(child).equals("text/plain")) {
                System.err.format("New file '%s'" +
                    " is not a plain text file.%n", filename);
                continue;
            }
        } catch (IOException x) {
            System.err.println(x);
            continue;
        }
        // Email the file to the
        //  specified email alias.
        System.out.format("Emailing file %s%n", filename);
        //Details left to reader....
    }
    // Reset the key -- this step is critical if you want to
    // receive further watch events.  If the key is no longer valid,
    // the directory is inaccessible so exit the loop.
    boolean valid = key.reset();
    if (!valid) {
        break;
    }
}

检索文件名

文件名是从事件上下文中检索的。Email 示例使用以下代码检索文件名:

WatchEvent<Path> ev = (WatchEvent<Path>)event;
Path filename = ev.context();

当你编译 Email 示例时,会生成以下错误:

Note: Email.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

这个错误是由将 WatchEvent 强制转换为 WatchEvent 的代码行引起的。WatchDir 示例通过创建一个抑制未经检查警告的实用 cast 方法来避免这个错误,如下所示:

@SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
    return (WatchEvent<Path>)event;
}

如果你对 @SuppressWarnings 语法不熟悉,请参见 Annotations。

何时使用和不使用这个 API

Watch Service API 适用于需要通知文件更改事件的应用程序。它非常适合任何可能有许多打开文件并需要确保文件与文件系统同步的应用程序,比如编辑器或 IDE。它也非常适合监视目录的应用服务器,也许等待 .jsp.jar 文件的出现,以便部署它们。

这个 API 是为了索引硬盘而设计的。大多数文件系统实现都原生支持文件更改通知。Watch Service API 利用了这种支持(如果可用)。然而,当文件系统不支持这种机制时,Watch Service 将轮询文件系统,等待事件发生。

其他有用的方法

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

本课程中未涵盖的一些有用方法在此处介绍。本节涵盖以下内容:

  • 确定 MIME 类型
  • 默认文件系统
  • 路径字符串分隔符
  • 文件系统的文件存储器

确定 MIME 类型

要确定文件的 MIME 类型,您可能会发现probeContentType(Path)方法很有用。例如:

try {
    String type = Files.probeContentType(filename);
    if (type == null) {
        System.err.format("'%s' has an" + " unknown filetype.%n", filename);
    } else if (!type.equals("text/plain") {
        System.err.format("'%s' is not" + " a plain text file.%n", filename);
        continue;
    }
} catch (IOException x) {
    System.err.println(x);
}

注意,如果无法确定内容类型,probeContentType会返回 null。

此方法的实现高度依赖于平台,并不是绝对可靠的。内容类型由平台的默认文件类型检测器确定。例如,如果检测器根据.class扩展名确定文件的内容类型为application/x-java,可能会被欺骗。

如果默认的方法不符合您的需求,您可以提供自定义的FileTypeDetector

电子邮件示例使用probeContentType方法。

默认文件系统

要检索默认文件系统,请使用getDefault方法。通常,此FileSystems方法(注意是复数形式)链接到FileSystem方法之一(注意是单数形式),如下所示:

PathMatcher matcher =
    FileSystems.getDefault().getPathMatcher("glob:*.*");

路径字符串分隔符

POSIX 文件系统的路径分隔符是正斜杠/,Microsoft Windows 的路径分隔符是反斜杠\。其他文件系统可能使用其他分隔符。要检索默认文件系统的Path分隔符,可以使用以下方法之一:

String separator = File.separator;
String separator = FileSystems.getDefault().getSeparator();

getSeparator方法也用于检索任何可用文件系统的路径分隔符。

文件系统的文件存储器

文件系统有一个或多个文件存储器来保存其文件和目录。文件存储器代表底层存储设备。在 UNIX 操作系统中,每个挂载的文件系统都由一个文件存储器表示。在 Microsoft Windows 中,每个卷都由一个文件存储器表示:C:D:等等。

要检索文件系统的所有文件存储器列表,可以使用getFileStores方法。此方法返回一个Iterable,允许您使用增强的 for 语句遍历所有根目录。

for (FileStore store: FileSystems.getDefault().getFileStores()) {
   ...
}

如果要检索特定文件所在的文件存储器,请使用Files类中的getFileStore方法,如下所示:

Path file = ...;
FileStore store= Files.getFileStore(file);

DiskUsage示例使用getFileStores方法。

传统文件 I/O 代码

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

与旧代码的互操作性

在 Java SE 7 发布之前,java.io.File 类是文件 I/O 的机制,但它有一些缺点。

  • 许多方法在失败时不会抛出异常,因此无法获得有用的错误消息。例如,如果文件删除失败,程序将收到“删除失败”,但不知道是因为文件不存在、用户没有权限还是其他问题。
  • rename 方法在各个平台上的工作不一致。
  • 没有对符号链接的真正支持。
  • 需要更多对元数据的支持,如文件权限、文件所有者和其他安全属性。
  • 访问文件元数据效率低下。
  • 许多 File 方法不具备可扩展性。在服务器上请求大型目录列表可能导致挂起。大型目录也可能导致内存资源问题,导致拒绝服务。
  • 不可能编写可靠的代码,可以递归遍历文件树,并在存在循环符号链接时做出适当响应。

也许您有使用 java.io.File 的旧代码,并希望最小影响地利用 java.nio.file.Path 功能。

java.io.File 类提供了 toPath 方法,将旧式 File 实例转换为 java.nio.file.Path 实例,如下所示:

Path input = file.toPath();

然后,您可以利用 Path 类提供的丰富功能集。

例如,假设您有一些删除文件的代码:

file.delete();

您可以修改此代码以使用 Files.delete 方法,如下所示:

Path fp = file.toPath();
Files.delete(fp);

相反,Path.toFile 方法为 Path 对象构造一个 java.io.File 对象。

将 java.io.File 功能映射到 java.nio.file

由于 Java SE 7 发布中的文件 I/O 实现已完全重新架构,因此不能将一个方法替换为另一个方法。如果您想使用 java.nio.file 包提供的丰富功能,最简单的解决方案是使用前一节中建议的 File.toPath 方法。但是,如果您不想使用该方法或该方法不符合您的需求,您必须重写文件 I/O 代码。

两个 API 之间没有一对一对应关系,但以下表格给出了 java.io.File API 中的功能在 java.nio.file API 中的映射,并告诉您可以在哪里获取更多信息。

java.io.File 功能 java.nio.file 功能 教程覆盖范围
java.io.File java.nio.file.Path Path 类
java.io.RandomAccessFile SeekableByteChannel 功能。 随机访问文件
File.canReadcanWritecanExecute Files.isReadableFiles.isWritableFiles.isExecutable。在 UNIX 文件系统上,使用 管理元数据(文件和文件存储属性) 包来检查九个文件权限。 检查文件或目录 管理元数据
File.isDirectory()File.isFile()File.length() Files.isDirectory(Path, LinkOption...)Files.isRegularFile(Path, LinkOption...)Files.size(Path) 管理元数据
File.lastModified()File.setLastModified(long) Files.getLastModifiedTime(Path, LinkOption...)Files.setLastMOdifiedTime(Path, FileTime) 管理元数据
设置各种属性的 File 方法:setExecutablesetReadablesetReadOnlysetWritable 这些方法被 Files 方法 setAttribute(Path, String, Object, LinkOption...) 替代。 管理元数据
new File(parent, "newfile") parent.resolve("newfile") 路径操作
File.renameTo Files.move 移动文件或目录
File.delete Files.delete 删除文件或目录
File.createNewFile Files.createFile 创建文件
File.deleteOnExit createFile 方法中指定的 DELETE_ON_CLOSE 选项替代。 创建文件

| File.createTempFile | Files.createTempFile(Path, String, FileAttributes)Files.createTempFile(Path, String, String, FileAttributes) | 创建文件 通过流 I/O 创建和写入文件

通过通道 I/O 读写文件 |

File.exists Files.existsFiles.notExists 验证文件或目录的存在性
File.compareTo and equals Path.compareTo and equals 比较两个路径
File.getAbsolutePath and getAbsoluteFile Path.toAbsolutePath 转换路径

| File.getCanonicalPath and getCanonicalFile | Path.toRealPathnormalize | 转换路径 (toRealPath) 从路径中删除冗余部分 (normalize)

|

File.toURI Path.toURI 转换路径
File.isHidden Files.isHidden 检索路径信息
File.list and listFiles Path.newDirectoryStream 列出目录内容
File.mkdirmkdirs Files.createDirectory 创建目录
File.listRoots FileSystem.getRootDirectories 列出文件系统的根目录
File.getTotalSpaceFile.getFreeSpaceFile.getUsableSpace FileStore.getTotalSpaceFileStore.getUnallocatedSpaceFileStore.getUsableSpaceFileStore.getTotalSpace 文件存储属性

摘要

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

java.io 包包含许多类,您的程序可以使用这些类来读取和写入数据。大多数类实现顺序访问流。顺序访问流可以分为两组:那些读取和写入字节的流以及读取和写入 Unicode 字符的流。每个顺序访问流都有其特长,例如从文件中读取或写入数据,过滤读取或写入的数据,或者序列化对象。

java.nio.file 包提供了广泛的文件和文件系统 I/O 支持。这是一个非常全面的 API,但关键入口点如下:

  • Path 类具有操作路径的方法。
  • Files 类具有文件操作的方法,例如移动、复制、删除,以及检索和设置文件属性的方法。
  • FileSystem 类具有各种方法用于获取有关文件系统的信息。

关于 NIO.2 的更多信息可以在 OpenJDK: NIO 项目网站上找到。该网站包括 NIO.2 提供的超出本教程范围的功能资源,例如多播、异步 I/O 和创建自己的文件系统实现。

问题和练习:基本 I/O

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

问题

1. 你会使用什么类和方法来读取大文件末尾附近已知位置的几个数据片段?

2. 在调用format时,如何最好地指示一个新行?

3. 如何确定文件的 MIME 类型?

4. 您会使用什么方法来确定文件是否是符号链接?

练习

1. 编写一个示例,计算文件中特定字符(如e)出现的次数。可以在命令行指定字符。您可以使用xanadu.txt作为输入文件。

2. 文件datafile以一个告诉你同一文件中一个int数据偏移量的long开头。编写一个程序获取这个int数据。这个int数据是什么?

检查你的答案。

课程:并发编程

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

计算机用户认为他们的系统可以同时执行多项任务是理所当然的。他们认为他们可以在一个文字处理器中继续工作,同时其他应用程序可以下载文件,管理打印队列和流式传输音频。甚至单个应用程序通常也被期望同时执行多项任务。例如,流式传输音频应用程序必须同时从网络上读取数字音频,解压缩它,管理播放和更新显示。即使文字处理器也应该始终准备好响应键盘和鼠标事件,无论它是在重新格式化文本还是更新显示。能够执行这些操作的软件被称为并发软件。

Java 平台从头开始就设计用于支持并发编程,在 Java 编程语言和 Java 类库中具有基本的并发支持。自 5.0 版本以来,Java 平台还包括高级并发 API。本课程介绍了平台的基本并发支持,并总结了java.util.concurrent包中的一些高级 API。

进程和线程

原文:docs.oracle.com/javase/tutorial/essential/concurrency/procthread.html

在并发编程中,有两个基本的执行单位:进程线程。在 Java 编程语言中,并发编程主要涉及线程。然而,进程也很重要。

计算机系统通常有许多活动进程和线程。即使在只有一个执行核心的系统中,因此在任何给定时刻只有一个线程实际执行,也是如此。单核心的处理时间通过操作系统的时间片特性在进程和线程之间共享。

现在越来越普遍的是计算机系统具有多个处理器或具有多个执行核心的处理器。这极大地增强了系统对进程和线程并发执行的能力 — 但即使在简单系统上,没有多个处理器或执行核心,也可以实现并发。

进程

一个进程有一个独立的执行环境。一个进程通常有一个完整的,私有的基本运行时资源集;特别是,每个进程都有自己的内存空间。

进程通常被视为与程序或应用程序同义。然而,用户所看到的单个应用程序实际上可能是一组协作的进程。为了促进进程之间的通信,大多数操作系统支持进程间通信(IPC)资源,如管道和套接字。IPC 不仅用于同一系统上进程之间的通信,还用于不同系统上的进程。

大多数 Java 虚拟机的实现作为一个单独的进程运行。Java 应用程序可以使用ProcessBuilder对象创建额外的进程。多进程应用程序超出了本课程的范围。

线程

线程有时被称为轻量级进程。进程和线程都提供执行环境,但创建一个新线程所需的资源比创建一个新进程少。

线程存在于一个进程中 — 每个进程至少有一个。线程共享进程的资源,包括内存和打开的文件。这样做可以实现高效的,但潜在的有问题的通信。

多线程执行是 Java 平台的一个重要特性。每个应用程序至少有一个线程 — 或者多个,如果计算“系统”线程,执行诸如内存管理和信号处理等任务。但从应用程序员的角度来看,你从一个称为主线程的线程开始。这个线程有能力创建额外的线程,我们将在下一节中演示。

线程对象

原文:docs.oracle.com/javase/tutorial/essential/concurrency/threads.html

每个线程都与类Thread的实例相关联。使用Thread对象创建并发应用程序有两种基本策略。

  • 要直接控制线程的创建和管理,只需在应用程序需要启动异步任务时实例化Thread即可。
  • 要将线程管理与应用程序的其余部分抽象出来,将应用程序的任务传递给一个执行器

本节介绍了Thread对象的使用。执行器与其他高级并发对象一起讨论。

定义和启动线程

原文:docs.oracle.com/javase/tutorial/essential/concurrency/runthread.html

创建 Thread 实例的应用程序必须提供将在该线程中运行的代码。 有两种方法可以做到这一点:

  • 提供一个 Runnable 对象. Runnable 接口定义了一个名为 run 的方法,用于包含在线程中执行的代码。 Runnable 对象被传递给 Thread 构造函数,就像 HelloRunnable 示例中那样:
public class HelloRunnable implements Runnable {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        (new Thread(new HelloRunnable())).start();
    }
}
  • 子类 Thread. Thread 类本身实现了 Runnable,尽管它的 run 方法什么也不做。 应用程序可以子类化 Thread,提供自己的 run 实现,就像 HelloThread 示例中那样:
public class HelloThread extends Thread {
    public void run() {
        System.out.println("Hello from a thread!");
    }
    public static void main(String args[]) {
        (new HelloThread()).start();
    }
}

请注意,这两个示例都调用了 Thread.start 来启动新线程。

你应该使用哪种习语?第一个习语使用了一个 Runnable 对象,更通用,因为 Runnable 对象可以是 Thread 以外的类的子类。 第二个习语在简单应用程序中更容易使用,但受到任务类必须是 Thread 的后代的限制。 本课程重点介绍第一种方法,它将 Runnable 任务与执行任务的 Thread 对象分开。 这种方法不仅更灵活,而且适用于后面介绍的高级线程管理 API。

Thread 类定义了一些对线程管理有用的方法。 这些方法包括 static 方法,提供有关调用方法的线程的信息或影响其状态。 其他方法是从参与管理线程和 Thread 对象的其他线程调用的。 我们将在以下部分中检查其中一些方法。

暂停执行与睡眠

原文:docs.oracle.com/javase/tutorial/essential/concurrency/sleep.html

Thread.sleep会导致当前线程暂停执行一段指定的时间。这是一种有效的方式,可以让处理器时间可用于应用程序的其他线程或者可能在计算机系统上运行的其他应用程序。sleep方法也可以用于节奏控制,就像下面的示例中展示的那样,以及等待另一个线程,该线程的任务被理解为具有时间要求,就像稍后章节中的SimpleThreads示例一样。

提供了两个重载版本的sleep:一个指定以毫秒为单位的睡眠时间,另一个指定以纳秒为单位的睡眠时间。然而,这些睡眠时间不能保证是精确的,因为它们受到底层操作系统提供的设施的限制。此外,睡眠时间可以被中断,我们将在稍后的章节中看到。无论如何,你不能假设调用sleep会精确地暂停线程指定的时间段。

SleepMessages示例使用sleep以四秒的间隔打印消息:

public class SleepMessages {
    public static void main(String args[])
        throws InterruptedException {
        String importantInfo[] = {
            "Mares eat oats",
            "Does eat oats",
            "Little lambs eat ivy",
            "A kid will eat ivy too"
        };
        for (int i = 0;
             i < importantInfo.length;
             i++) {
            //Pause for 4 seconds
            Thread.sleep(4000);
            //Print a message
            System.out.println(importantInfo[i]);
        }
    }
}

注意,main声明了它会throws InterruptedException。这是一个异常,当另一个线程在sleep处于活动状态时中断当前线程时会抛出。由于这个应用程序没有定义另一个线程来引起中断,所以它不会去捕获InterruptedException

中断

原文:docs.oracle.com/javase/tutorial/essential/concurrency/interrupt.html

中断是对线程的指示,告诉它应该停止当前操作并执行其他操作。程序员需要决定线程如何响应中断,但通常线程会终止。这是本课程强调的用法。

一个线程通过在要中断的线程的Thread对象上调用interrupt来发送中断。为了使中断机制正常工作,被中断的线程必须支持自身的中断。

支持中断

一个线程如何支持自身的中断?这取决于它当前正在做什么。如果线程频繁调用抛出InterruptedException的方法,它只需在捕获异常后从run方法返回。例如,假设SleepMessages示例中的中央消息循环在线程的Runnable对象的run方法中。那么可以修改如下以支持中断:

for (int i = 0; i < importantInfo.length; i++) {
    // Pause for 4 seconds
    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // We've been interrupted: no more messages.
        return;
    }
    // Print a message
    System.out.println(importantInfo[i]);
}

许多抛出InterruptedException的方法,如sleep,设计为在接收到中断时取消当前操作并立即返回。

如果一个线程长时间不调用抛出InterruptedException的方法会怎样?那么它必须定期调用Thread.interrupted,如果接收到中断则返回true。例如:

for (int i = 0; i < inputs.length; i++) {
    heavyCrunch(inputs[i]);
    if (Thread.interrupted()) {
        // We've been interrupted: no more crunching.
        return;
    }
}

在这个简单的例子中,代码只是检测中断并在接收到中断时退出线程。在更复杂的应用程序中,抛出InterruptedException可能更合理:

if (Thread.interrupted()) {
    throw new InterruptedException();
}

这使得中断处理代码可以集中在catch子句中。

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

相关文章
|
9天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)
【4月更文挑战第21天】本文介绍了Selenium中处理特殊测试场景的方法,如鼠标悬停。Selenium的Actions类提供了鼠标悬停功能,用于模拟用户在网页元素上的悬停行为。文中通过实例展示了如何使用Actions悬停并展开下拉菜单,以及在搜索时选择自动补全的字段。代码示例包括了打开百度首页,悬停在“更多”元素上显示下拉菜单并点击“音乐”,以及在搜索框输入关键词并自动补全的过程。
33 0
|
2天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)
【4月更文挑战第28天】本文简要介绍了自动化测试的实战应用,通过一个在线问卷调查(&lt;https://www.sojump.com/m/2792226.aspx/&gt;)为例,展示了如何遍历并点击问卷中的选项。测试思路包括找到单选和多选按钮的共性以定位元素,然后使用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