From 8070244bf958fa666c1c47b19ff5275090533a6b Mon Sep 17 00:00:00 2001 From: wizardforcel <562826179@qq.com> Date: Fri, 1 Oct 2021 23:45:26 +0800 Subject: [PATCH] 2021-10-01 23:45:26 --- docs/java11-cb/04.md | 8 ++++---- docs/java11-cb/05.md | 26 +++++++++++++------------- docs/java11-cb/06.md | 32 ++++++++++++++++---------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/docs/java11-cb/04.md b/docs/java11-cb/04.md index b0e4f33..0258e96 100644 --- a/docs/java11-cb/04.md +++ b/docs/java11-cb/04.md @@ -332,7 +332,7 @@ Consumer failure = new Consumer() { ``` -我们现在可以调用 calculate 方法,如下所示: +我们现在可以调用`calculate`方法,如下所示: ```java calculate(source, process, condition, success, failure); @@ -764,7 +764,7 @@ public String m1(double x, double y){ # 还有更多。。。 -与在匿名类中一样,在 Lambda 表达式外部创建但在内部使用的变量实际上是 final,不能修改。您可以编写以下代码: +与在匿名类中一样,在 Lambda 表达式外部创建但在内部使用的变量实际上是`final`,不能修改。您可以编写以下代码: ```java double v = 10d; @@ -826,7 +826,7 @@ class Demo{ ![](img/324ceaa7-1714-4153-bd7a-43ae67258283.png) -Lambda 表达式不是内部类,不能被`this`引用。Lambda 表达式没有字段或属性。它是无国籍的。这就是为什么在 Lambda 表达式中,`this`关键字引用周围的上下文。这也是要求 Lambda 表达式使用的周围上下文的所有变量必须是 final 或有效 final 的另一个原因。 +Lambda 表达式不是内部类,不能被`this`引用。Lambda 表达式没有字段或属性。它是无国籍的。这就是为什么在 Lambda 表达式中,`this`关键字引用周围的上下文。这也是要求 Lambda 表达式使用的周围上下文的所有变量必须是`final`或有效`final`的另一个原因。 # 使用 Lambda 表达式 @@ -1343,7 +1343,7 @@ System.out.println("new Food(Carrot, Broccoli) .sayFavorite() => " + func.apply(food3)); ``` -如您所见,参数(CallReceiver 对象)与任何参数一样,仅来自当前上下文。无论函数传递到哪里,它都不携带上下文。它的接收者未绑定到用于创建函数的上下文。这就是为什么这个方法引用被称为*未绑定*。 +如您所见,参数(`CallReceiver`对象)与任何参数一样,仅来自当前上下文。无论函数传递到哪里,它都不携带上下文。它的接收者未绑定到用于创建函数的上下文。这就是为什么这个方法引用被称为*未绑定*。 上述代码的输出如下所示: diff --git a/docs/java11-cb/05.md b/docs/java11-cb/05.md index c006c36..2ef7bc5 100644 --- a/docs/java11-cb/05.md +++ b/docs/java11-cb/05.md @@ -1,6 +1,6 @@ # 流和管道 -在 Java8 和 Java9 中,CollectionsAPI 通过利用 Lambda 表达式引入流和内部迭代进行了重大的改头换面。在 Java10(JDK18.3)中,添加了新方法-`List.copyOf`、`Set.copyOf`和`Map.copyOf`,允许我们从现有实例创建新的不可变集合。此外,新方法`toUnmodifiableList`、`toUnmodifiableSet`和`toUnmodifiableMap`被添加到`java.util.stream`包中的`Collectors`类中,允许将`Stream`中的元素收集到一个不可变的集合中。本章介绍如何使用流和链多个操作来创建管道。此外,读者还将了解如何并行完成这些操作。配方列表包括以下内容: +在 Java8 和 Java9 中,集合 API 通过利用 Lambda 表达式引入流和内部迭代进行了重大的改头换面。在 Java10(JDK18.3)中,添加了新方法-`List.copyOf`、`Set.copyOf`和`Map.copyOf`,允许我们从现有实例创建新的不可变集合。此外,新方法`toUnmodifiableList`、`toUnmodifiableSet`和`toUnmodifiableMap`被添加到`java.util.stream`包中的`Collectors`类中,允许将`Stream`中的元素收集到一个不可变的集合中。本章介绍如何使用流和链多个操作来创建管道。此外,读者还将了解如何并行完成这些操作。配方列表包括以下内容: * 使用`of()`和`copyOf()`工厂方法创建不可变集合 * 创建和操作流 @@ -124,9 +124,9 @@ static List of(E... elements) 如 [JEP 269](http://openjdk.java.net/jeps/269) 所述,针对性能优化了具有固定数量元素的 10 种重载工厂方法,这些方法 -“*避免**varargs 调用所产生的阵列分配、初始化和垃圾收集开销。* +“*避免可变参数调用所产生的阵列分配、初始化和垃圾收集开销。*” - *使用`of()`工厂方法使代码更加紧凑: +使用`of()`工厂方法使代码更加紧凑: ```java List.of("This ", "is ", "created ", "by ", "List.of()") @@ -250,7 +250,7 @@ setA = new HashSet<>(listB); # 还有更多。。。 -在 Lambda 表达式和流被引入后不久,非空值和不变性被强制执行,这不是偶然的。正如您将在后续配方中看到的,函数式编程和流管道鼓励流畅的编码风格(使用方法链接,以及在本配方示例中使用`forEach()`方法)。Fluent 样式提供了更紧凑、可读性更强的代码。不需要检查`null`值有助于保持紧凑,并专注于主要处理过程。 +在 Lambda 表达式和流被引入后不久,非空值和不变性被强制执行,这不是偶然的。正如您将在后续配方中看到的,函数式编程和流管道鼓励流畅的编码风格(使用方法链接,以及在本配方示例中使用`forEach()`方法)。流畅样式提供了更紧凑、可读性更强的代码。不需要检查`null`值有助于保持紧凑,并专注于主要处理过程。 不变性特性反过来与 Lambda 表达式使用的变量的`finale`概念非常一致。例如,可变集合允许我们绕过此限制: @@ -283,7 +283,7 @@ list.forEach(System.out::print); //prints: 12545 * `java.nio.file.Files`类的`Stream list()`、`Stream lines()`和`Stream find()`方法 * `java.io.BufferedReader`类的`Stream lines()`方法 -创建流后,可以对其元素应用各种方法(称为操作)。流本身不存储数据。相反,它根据需要从源获取数据(并向操作提供或发送数据)。这些操作可以使用 fluent 样式形成管道,因为许多中间操作也可以返回流。这种操作称为*中间*操作。中间操作的示例包括: +创建流后,可以对其元素应用各种方法(称为操作)。流本身不存储数据。相反,它根据需要从源获取数据(并向操作提供或发送数据)。这些操作可以使用流畅样式形成管道,因为许多中间操作也可以返回流。这种操作称为*中间*操作。中间操作的示例包括: * `map()`:根据函数变换元素 * `flatMap()`:根据函数将每个元素转换成流 @@ -325,7 +325,7 @@ Map.of(1, "This ", 2, "is ", 3, "built ", 4, "by ", 5, .entrySet().stream().forEach(System.out::print); ``` -我们使用 fluent 样式使代码更加紧凑和插入`System.out.println()`,以便在输出中开始一行新代码。 +我们使用流畅样式使代码更加紧凑和插入`System.out.println()`,以便在输出中开始一行新代码。 2. 运行前面的示例,您将看到以下结果: @@ -424,13 +424,13 @@ try(Stream stream = Files.list(dir)) { “必须在`try-with-resources`语句或类似的控制结构中使用此方法,以确保在流的操作完成后立即关闭流的打开目录。” -这就是我们所做的;我们使用了 try with resources 语句。或者,我们可以使用 try-catch-finally 构造,关闭 finally 块中的流,结果不会改变。 +这就是我们所做的;我们使用了资源试用语句。或者,我们可以使用`try-catch-finally`构造,关闭`finally`块中的流,结果不会改变。 12. 运行前面的示例并观察输出: ![](img/9faf4c8d-cc86-43ce-9bcc-d116b5953269.png) -并非所有流都必须显式关闭,尽管`Stream`接口扩展了`AutoCloseable`,并且人们希望所有流都必须使用 try with resources 语句自动关闭。但事实并非如此。[`Stream`接口的 Javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) 表示, +并非所有流都必须显式关闭,尽管`Stream`接口扩展了`AutoCloseable`,并且人们希望所有流都必须使用资源试用语句自动关闭。但事实并非如此。[`Stream`接口的 Javadoc](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html) 表示, “流有一个`BaseStream.close()`方法并实现`AutoCloseable`。大多数流实例在使用后实际上不需要关闭,因为它们由集合、数组或生成函数支持,不需要特殊的资源管理。通常,只有源为 I/O 通道的流,例如`Files.lines(Path)`返回的流。”,将需要关闭。” @@ -713,7 +713,7 @@ Stream.of("3","2","1").parallel().forEachOrdered(System.out::print); ![](img/062c4c7d-21e1-4ad9-8e69-c21ec4476bb5.png) -现在,让我们谈谈下一组终端操作,称为`reduce()`。在处理所有流元素后,三个重载方法中的每一个都返回一个值。其中最简单的例子是查找流元素的总和,如果它们是数字,或者是 max、min 和类似的值。但对于任何类型的对象流,都可以构造更复杂的结果。 +现在,让我们谈谈下一组终端操作,称为`reduce()`。在处理所有流元素后,三个重载方法中的每一个都返回一个值。其中最简单的例子是查找流元素的总和,如果它们是数字,或者是最大、最小和类似的值。但对于任何类型的对象流,都可以构造更复杂的结果。 第一个方法`Optional reduce(BinaryOperator accumulator)`返回`Optional`对象,因为计算结果是提供的累加器函数的责任,JDK 实现的作者不能保证它始终包含非空值: @@ -1116,8 +1116,8 @@ LongStream.range(1, 3).asDoubleStream() `IntSummaryStatistics`类有以下两种方法: -* void accept(int 值):将新值包含到统计摘要中 -* void combine(`IntSummaryStatistics`other):将提供的`other`对象收集到的统计信息添加到当前统计信息中 +* `void accept(int value)`:将新值包含到统计摘要中 +* `void combine(IntSummaryStatistics other)`:将提供的`other`对象收集到的统计信息添加到当前统计信息中 这些方法允许我们在任何`Stream`对象上使用`R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)`操作的重载版本,如下所示: @@ -2071,7 +2071,7 @@ System.out.println(map); ``` -如您所见,`Collectors.groupingBy(Person::getName)`采集器生成的 map 的`List`值后来(下游)被`Collectors.toSet()`采集器更改为一个集合。 +如您所见,`Collectors.groupingBy(Person::getName)`采集器生成的映射的`List`值后来(下游)被`Collectors.toSet()`采集器更改为一个集合。 或者,每个`List`值可以仅转换为列表元素的计数,如下所示: @@ -2082,7 +2082,7 @@ Map map = getStreamPerson() System.out.println(map); //prints: {John=2, Jill=1} ``` -要计算流中有多少相同的`Person`对象(根据`equals()`方法相等的对象),我们可以使用 identity 函数,该函数定义为返回未更改的输入。例如: +要计算流中有多少相同的`Person`对象(根据`equals()`方法相等的对象),我们可以使用恒等函数,该函数定义为返回未更改的输入。例如: ```java Stream.of("a","b","c") diff --git a/docs/java11-cb/06.md b/docs/java11-cb/06.md index cc7f96b..b674d20 100644 --- a/docs/java11-cb/06.md +++ b/docs/java11-cb/06.md @@ -201,7 +201,7 @@ CREATE TABLE traffic_unit ( ); ``` -`size`参数是可选的。如果未设置,如前面的示例代码中所示,则表示该列可以存储任意长度的值。在本例中,`integer`类型允许您存储从`Integer.MIN_VALUE`(即-2147483648)到`Integer.MAX_VALUE`(即+2147483647)的数字。添加了`NOT NULL`类型,因为默认情况下,该列可以为 null,并且我们希望确保填充所有列。 +`size`参数是可选的。如果未设置,如前面的示例代码中所示,则表示该列可以存储任意长度的值。在本例中,`integer`类型允许您存储从`Integer.MIN_VALUE`(即`-2147483648`)到`Integer.MAX_VALUE`(即`+2147483647`)的数字。添加了`NOT NULL`类型,因为默认情况下,该列可以为`null`,并且我们希望确保填充所有列。 我们还将`id`列标识为`PRIMARY KEY`,这表示该列(或列的组合)唯一地标识了该记录。例如,如果有一个表包含所有国家的所有人的信息,那么唯一的组合可能是他们的全名、地址和出生日期。好吧,我们可以想象,在一些家庭中,双胞胎出生并有相同的名字,所以我们说*可能*。如果出现这种情况的可能性很高,我们需要在主键组合中添加另一列,这是一个出生顺序,默认值为`1`。以下是我们如何在 PostgreSQL 中做到这一点: @@ -534,7 +534,7 @@ void traverseRS(String sql){ HikariCP 框架由居住在日本的 Brett Wooldridge 创建。*Hikari*在日语中的意思是*光*。它是一个轻量级且相对较小的 API,经过高度优化,允许通过许多属性进行调优,其中一些属性在其他池中不可用。除了标准用户、密码、最大池大小、各种超时设置和缓存配置属性外,它还公开了诸如`allowPoolSuspension`、`connectionInitSql`、`connectionTestQuery`等属性,甚至包括处理未及时关闭的连接的属性`leakDetectionThreshold`。 -要使用 Hikari pool 的最新版本(在编写本书时),请向项目添加以下依赖项: +要使用 Hikari 池子的最新版本(在编写本书时),请向项目添加以下依赖项: ```java @@ -866,7 +866,7 @@ org.postgresql.util.PSQLException: ERROR: syntax error at or near "inst" ![](img/e419c1af-ae1e-4f52-942c-a47dacd0d441.png) -未插入第二行。如果在第一个`INSERT INTO`语句之后没有`conn.commit()`,则也不会应用第一个 insert。这是编程事务控制的优点,在许多独立数据更改的情况下,如果一个失败,我们可以跳过它并继续应用其他更改。 +未插入第二行。如果在第一个`INSERT INTO`语句之后没有`conn.commit()`,则也不会应用第一个插入。这是编程事务控制的优点,在许多独立数据更改的情况下,如果一个失败,我们可以跳过它并继续应用其他更改。 现在,让我们尝试在第二行插入三行有错误的内容(将字母而不是数字设置为`id`值): @@ -981,7 +981,7 @@ traverseRS("select * from test"); `Clob`允许您存储字符数据。`NClob`存储 Unicode 字符数据以支持国际化。它扩展了`Clob`接口并提供了相同的方法。这两个接口都允许您查找 LOB 的长度,并在值中获取子字符串。 -`ResultSet`、`CallableStatement`(我们将在下一个配方中讨论)和`PreparedStatement`接口中的方法允许应用程序以各种方式存储和访问存储的值,其中一些方式是通过相应对象的设置器和 getter,而另一些方式是`bytes[]`或二进制、字符或 ASCII 流。 +`ResultSet`、`CallableStatement`(我们将在下一个配方中讨论)和`PreparedStatement`接口中的方法允许应用程序以各种方式存储和访问存储的值,其中一些方式是通过相应对象的设置器和获取器,而另一些方式是`bytes[]`或二进制、字符或 ASCII 流。 # 怎么做。。。 @@ -1007,7 +1007,7 @@ execute("create table lobs (id integer, lob oid)"); execute("create table texts (id integer, text text)"); ``` -查看 JDBC 接口`PreparedStatement`和`ResultSet`,您会注意到对象的设置器和 getter—`get/setBlob()`、`get/setClob()`、`get/setNClob()`、`get/setBytes()`——以及使用`InputStream`和`Reader`—`get/setBinaryStream()`、`get/setAsciiStream()`或`get/setCharacterStream()`的方法。流式方法的最大优点是,它们在数据库和源之间移动数据,而无需将整个 LOB 存储在内存中。 +查看 JDBC 接口`PreparedStatement`和`ResultSet`,您会注意到对象的设置器和获取器—`get/setBlob()`、`get/setClob()`、`get/setNClob()`、`get/setBytes()`——以及使用`InputStream`和`Reader`—`get/setBinaryStream()`、`get/setAsciiStream()`或`get/setCharacterStream()`的方法。流式方法的最大优点是,它们在数据库和源之间移动数据,而无需将整个 LOB 存储在内存中。 然而,对象的设置器和获取器更接近我们的心,与面向对象的编码保持一致。因此,我们将从它们开始,使用不太大的对象进行演示。我们希望以下代码能够正常工作: @@ -1355,7 +1355,7 @@ try (PreparedStatement st = conn.prepareStatement(sql)) { [这里是 PostgreSQL 文档中的另一条建议](https://jdbc.postgresql.org/documentation/80/binary-data.html): -“BYTEA 数据类型不太适合存储非常大量的二进制数据。虽然 BYTEA 类型的列最多可以容纳 1 GB 的二进制数据,但它需要大量内存来处理如此大的值。 +“`BYTEA`数据类型不太适合存储非常大量的二进制数据。虽然`BYTEA`类型的列最多可以容纳 1 GB 的二进制数据,但它需要大量内存来处理如此大的值。 用于存储二进制数据的大对象方法更适合存储非常大的值,但它有其自身的局限性。 专门删除包含大对象引用的行不会删除大对象。 删除大对象是需要执行的单独操作。 大对象也有一些安全问题,因为连接到数据库的任何人都可以查看和/或修改任何大对象,即使他们没有查看/更新包含大对象引用的行的权限。” @@ -1599,7 +1599,7 @@ try (CallableStatement st = conn.prepareCall(sql)) { 我们试过了,但没有成功。以下是 PostgreSQL 文档对此的说明: -以集合形式返回数据的函数不应通过 CallableStatement 接口调用,而应使用普通语句或 PreparedStatement 接口 +以集合形式返回数据的函数不应通过`CallableStatement`接口调用,而应使用普通语句或`PreparedStatement`接口 不过,有一种方法可以绕过这一限制。相同的数据库文档描述了如何检索`refcursor`(PostgreSQL 特定功能)值,然后将其转换为`ResultSet`: @@ -2097,9 +2097,9 @@ create table person1 ( 如您所见,``标记有一个`namespace`属性,用于解析不同位置具有相同名称的文件。它可能与映射器文件位置匹配,也可能不匹配。映射器文件位置在配置文件`mb-config1.xml`中指定为标签``的属性资源(参见上一步)。 -标签``、``、``和``的属性在很大程度上是不言自明的。添加属性`keyProperty`、`keyColumn`和`useGeneratedKeys`(在配置``中)以使用数据库生成的值填充插入的对象。如果您在全局范围内不需要该属性,则可以从配置中的设置中删除该属性`useGeneratedKeys`,并仅将其添加到希望利用自动生成某些值的插入语句中。我们这样做是因为我们希望获得生成的 ID,并在稍后的代码中使用它来演示如何通过 ID 检索记录。 -使用``的 ID 属性和类似的标记来调用它们,以及映射器名称空间值。我们将很快向您展示这是如何完成的。构造`#{id}`是指作为参数传入的值,如果该值是基元类型。否则,传入的对象应该有这样一个字段。不需要在对象上具有获取器。如果存在获取器,它必须符合 JavaBean 方法格式。 对于返回值,默认情况下,列的名称与对象字段或设置器的名称匹配(必须符合 JavaBean 方法格式)。如果字段(或设置器名称)和列名不同,可以使用标记``提供映射。例如,如果表`person`有`person_id`和`person_name`列,而域对象`Person`有`id`和`name`字段,我们可以创建一个映射: @@ -2119,7 +2119,7 @@ create table person1 ( ``` -或者,也可以使用标准 select 子句别名: +或者,也可以使用标准`select`子句别名: ```java