提交 c1eca049 编写于 作者: W wizardforcel

2021-10-01 18:18:04

上级 dd3f8042
......@@ -30,7 +30,7 @@ public class finaldemo {
`final`关键字可以在方法级别使用,以确保该方法未被重写。它用于变量级别以确保我们没有更改它,也可以用于类级别以确保我们没有继承父类。
但请记住不要混淆`final``finally``finally`是与`try...catch`异常相关的东西,一旦执行`try``catch`块,并预告任何错误,无论脚本通过还是失败,控制器都会来到该日志并执行代码。`finally`都是关于限制访问的,比如我们不能使用它,不能继承它,甚至不能更改值。我们探讨了包,以及如何将包导入其他类。我们已经探索了接口的继承、运行时多态、字符串等。这都是关于关键词的。
但请记住不要混淆`final``finally``finally`是与`try...catch`异常相关的东西,一旦执行`try``catch`块,并预告任何错误,无论脚本通过还是失败,控制器都会来到该日志并执行代码。`finally`都是关于限制访问的,比如我们不能使用它,不能继承它,甚至不能更改值。我们探讨了包,以及如何将包导入其他类。我们已经探索了接口的继承、运行时多态、字符串等。这都是关于关键词的。
在下一节中,我们将学习包。
......
......@@ -244,7 +244,7 @@ java -XX:CompileThreshold=500 -XX:-TieredCompilation Test
## 静态编译与动态编译
许多高级编程语言如 C 或 C++从一开始就使用 AOT 编译。它们也被称为**静态编译**语言。由于 AOT(或静态)编译器不受性能要求的约束(至少没有运行时的解释器(也称为**动态编译器**)那么多),因此它们可以花时间进行复杂的代码优化。另一方面,静态编译器没有运行时(评测)数据,这在动态类型语言的情况下尤其有限,Java 就是其中之一。由于 Java 中的动态类型功能(向下转换到子类型、查询对象的类型以及其他类型操作)是面向对象编程(多态原理)的支柱之一,因此 Java 的 AOT 编译变得更加有限。Lambda 表达式暂停了静态编译的另一个挑战,目前还不受支持。**
许多高级编程语言如 C 或 C++从一开始就使用 AOT 编译。它们也被称为**静态编译**语言。由于 AOT(或静态)编译器不受性能要求的约束(至少没有运行时的解释器(也称为**动态编译器**)那么多),因此它们可以花时间进行复杂的代码优化。另一方面,静态编译器没有运行时(评测)数据,这在动态类型语言的情况下尤其有限,Java 就是其中之一。由于 Java 中的动态类型功能(向下转换到子类型、查询对象的类型以及其他类型操作)是面向对象编程(多态原理)的支柱之一,因此 Java 的 AOT 编译变得更加有限。Lambda 表达式暂停了静态编译的另一个挑战,目前还不受支持。**
动态编译器的另一个优点是,它可以做出假设并相应地优化代码。如果假设被证明是错误的,编译器可以尝试另一个假设,直到达到性能目标。这样的过程可能会减慢应用程序的速度和/或增加预热时间,但从长远来看,它可能会带来更好的性能。概要文件引导的优化也可以帮助静态编译器沿着这条路径前进,但与动态编译器相比,静态编译器的优化机会总是有限的。
......
......@@ -2,7 +2,7 @@
在本章中,我们将介绍以下配方:
* 实现**面向对象设计****面向对象设计**
* 实现**面向对象设计****OOD**
* 使用内部类
* 使用继承和聚合
* 对接口进行编码
......@@ -17,7 +17,7 @@
# 介绍
本章简要介绍了**o****面向对象编程****OOP**的概念,并介绍了自 Java 8 以来引入的一些增强功能。我们还将尝试在适用的地方介绍一些良好的 OOD 实践,并使用特定的代码示例演示它们。
本章简要介绍了**面向对象编程****OOP**的概念,并介绍了自 Java 8 以来引入的一些增强功能。我们还将尝试在适用的地方介绍一些良好的 OOD 实践,并使用特定的代码示例演示它们。
人们可以花很多时间阅读书籍和互联网上有关 OOD 的文章和实用建议。这样做对某些人是有益的。但是,根据我们的经验,掌握 OOD 的最快方法是在您自己的代码中尽早尝试其原则。这正是本章的目标,让您有机会了解并使用 OOD 原则,从而使正式定义立即变得有意义。
......@@ -29,7 +29,7 @@
* **封装**:隐藏数据和/或方法
* **继承**:扩展另一类数据和/或方法
* **接口**:隐藏类型的实现和编码
* **多态**:使用指向子类对象的基类类型引用
* **多态**:使用指向子类对象的基类类型引用
如果您在互联网上搜索,您可能会注意到许多其他概念和对它们的补充,以及所有 OOD 原则,都可以从前面列出的五个概念中派生出来。这意味着对它们的深入理解是成功设计面向对象系统的先决条件。
......@@ -43,7 +43,7 @@
*类*是字段和方法定义的集合,它们将出现在它的每个实例中——基于这个类创建的对象。封装是隐藏那些不应被其他对象访问的字段和方法。
通过在字段和方法的声明中使用称为*访问修饰符的`public`、`protected`或`private`Java 关键字*实现封装。当未指定访问修饰符时,还有一个默认的封装级别。
通过在字段和方法的声明中使用称为*访问修饰符*`public``protected``private`Java 关键字实现封装。当未指定访问修饰符时,还有一个默认的封装级别。
# 怎么做。。。
......@@ -106,7 +106,7 @@ public static void main(String... arg) {
![](img/5e877a71-e07d-4cdf-a2ba-4d06cf4abe6a.png)
值得注意的是,`Vehicle`类的`getSpeedMph(double timeSec)`方法依赖于分配给`engine`字段的值的存在。这样,`Vehicle`*的对象将*速度计算委托给`Engine`类的对象。如果后者未设置(`Vehicle()`构造函数中传递的`null`,例如),`NullPointerException`将在运行时抛出,如果应用程序未处理,JVM 将捕获并强制退出。为了避免这种情况,我们可以检查`Vehicle()`构造函数中是否存在`engine`字段值:
值得注意的是,`Vehicle`类的`getSpeedMph(double timeSec)`方法依赖于分配给`engine`字段的值的存在。这样,`Vehicle`*对象*速度计算委托给`Engine`类的对象。如果后者未设置(`Vehicle()`构造函数中传递的`null`,例如),`NullPointerException`将在运行时抛出,如果应用程序未处理,JVM 将捕获并强制退出。为了避免这种情况,我们可以检查`Vehicle()`构造函数中是否存在`engine`字段值:
```java
if(engine == null){
......@@ -174,7 +174,7 @@ public static void main(String... arg) {
![](img/2366a79d-188e-42bb-87d8-accfac3a3c97.png)
由于多态,可以将对`Car`类的对象的引用分配给其基类`Vehicle`的引用。`Car`类对象有两种类型—它自己的类型`Car`和基类的类型`Vehicle`
由于多态,可以将对`Car`类的对象的引用分配给其基类`Vehicle`的引用。`Car`类对象有两种类型—它自己的类型`Car`和基类的类型`Vehicle`
在 Java 中,一个类还可以实现多个接口,这样一个类的对象也可以具有每个实现接口的类型。我们将在随后的食谱中讨论这一点。
......@@ -341,7 +341,7 @@ public static void main(String... arg) {
![](img/3b0f5b59-fcd0-4847-8141-cb56a9c81995.png)
如果接口只有一个抽象方法(称为函数接口),则可以使用另一个构造(称为*lambda 表达式*,而不是匿名内部类)。它提供了一个较短的表示法。我们将在第 4 章“开始函数式”中讨论功能接口和 lambda 表达式。
如果接口只有一个抽象方法(称为函数接口),则可以使用另一个构造(称为 *lambda 表达式*,而不是匿名内部类)。它提供了一个较短的表示法。我们将在第 4 章“开始函数式”中讨论功能接口和 lambda 表达式。
# 还有更多。。。
......@@ -375,7 +375,7 @@ public class Vehicle {
# 使用继承和聚合
在本食谱中,您将进一步了解两个重要的 OOP 概念:继承和多态,这两个概念已经在前面的食谱示例中提到并使用过。加上聚合,这些概念使设计更具可扩展性。
在本食谱中,您将进一步了解两个重要的 OOP 概念:继承和多态,这两个概念已经在前面的食谱示例中提到并使用过。加上聚合,这些概念使设计更具可扩展性。
# 准备
......@@ -383,9 +383,9 @@ public class Vehicle {
扩展类称为基类、超类或父类。该类的新扩展称为子类或子类。
多态是使用基类类型引用其子类的对象的能力。
多态是使用基类类型引用其子类的对象的能力。
为了演示继承和多态的威力,让我们创建一些类来表示汽车和卡车,每个类都有重量、发动机功率和速度(作为时间的函数)以及最大负载。此外,在这种情况下,汽车的特征是乘客数量,而卡车的重要特征是其有效载荷。
为了演示继承和多态的威力,让我们创建一些类来表示汽车和卡车,每个类都有重量、发动机功率和速度(作为时间的函数)以及最大负载。此外,在这种情况下,汽车的特征是乘客数量,而卡车的重要特征是其有效载荷。
# 怎么做。。。
......@@ -464,7 +464,7 @@ public static void main(String... arg) {
}
```
注意,`Vehicle`类型的`vehicle`引用指向`Car`子类的对象,之后指向`Truck`子类的对象。由于多态性,这是可能的,根据多态性,一个对象在其继承行中具有每个类的类型,包括所有接口。
注意,`Vehicle`类型的`vehicle`引用指向`Car`子类的对象,之后指向`Truck`子类的对象。由于多态,这是可能的,根据多态,一个对象在其继承行中具有每个类的类型,包括所有接口。
如果您需要调用一个只存在于子类中的方法,那么您必须像在前面的示例中所做的那样,将这样的引用转换为子类类型。
......@@ -777,15 +777,15 @@ public static void main(String... arg) {
我们将速度计算功能隔离在一个单独的类中,现在可以修改或扩展它,而无需更改`Vehicle`继承层次结构的任何类。这就是聚合设计原则允许您在不更改实现的情况下更改行为的方式。
在下一个菜谱中,我们将向您展示接口的 OOP 概念如何释放聚合和多态的更强大功能,从而使设计更简单、更具表现力。
在下一个菜谱中,我们将向您展示接口的 OOP 概念如何释放聚合和多态的更强大功能,从而使设计更简单、更具表现力。
# 对接口进行编码
在本教程中,您将学习最后一个 OOP 概念,即接口,并进一步练习聚合和多态以及内部类和继承的使用。
在本教程中,您将学习最后一个 OOP 概念,即接口,并进一步练习聚合和多态以及内部类和继承的使用。
# 准备
接口定义了在实现接口的类中可以看到的方法的签名。它是客户端可以访问的功能的公共面,因此通常被称为**应用程序接口****API**。它支持多态性和聚合,并有助于更灵活和可扩展的设计。
接口定义了在实现接口的类中可以看到的方法的签名。它是客户端可以访问的功能的公共面,因此通常被称为**应用程序接口****API**)。它支持多态和聚合,并有助于更灵活和可扩展的设计。
接口是隐式抽象的,这意味着它不能被实例化。如果不实现接口,则不能仅基于接口创建任何对象。它仅用于包含抽象方法(无正文)。但是自从 Java8 以来,可以向接口添加默认方法和私有方法,这是我们将在下面的菜谱中讨论的功能。
......@@ -1007,7 +1007,7 @@ public static void main(String... arg) {
# 准备
接口中的默认方法允许我们添加新方法签名,而无需在添加新方法签名之前更改已实现此接口的类。该方法称为*default*,因为它提供了在类未实现该方法时的功能。但是,如果类实现了它,则接口的默认实现将被类实现忽略并覆盖。
接口中的默认方法允许我们添加新方法签名,而无需在添加新方法签名之前更改已实现此接口的类。该方法称为*默认*,因为它提供了在类未实现该方法时的功能。但是,如果类实现了它,则接口的默认实现将被类实现忽略并覆盖。
接口中的静态方法可以提供与类中的静态方法相同的功能。与类静态方法类似,类静态方法可以在没有类实例化的情况下调用,接口静态方法也可以使用应用于接口的点运算符`SomeInterface.someStaticMethod()`来调用。
......
......@@ -405,7 +405,7 @@ public static Integer sumOfFirstNOdds(Integer count){
* `->`在代码库中的使用
* `IntPredicate`类的使用
如果您确实感到疑惑,那么您不必担心,因为我们将在第 4 章、*开始运行、*和第 5 章、*溪流和管道*中介绍这些内容。
如果您确实感到疑惑,那么您不必担心,因为我们将在第 4 章、“开始函数式”和第 5 章、“流和管道中介绍这些内容。
到目前为止,我们已经看到了一些关于数学计算的 API。这些 API 是我们`com.packt.math.MathUtil`类的一部分。此类的完整代码可在本书下载的代码库中的`Chapter03/2_simple-modular-math-util/math.util/com/packt/math`中找到。
......@@ -423,7 +423,7 @@ public static Integer sumOfFirstNOdds(Integer count){
* 它使用的服务
* 它为其提供实现的服务
正如第 1 章、*安装和 Java 11*中提到的,JDK 附带了很多模块,即现有的 Java SDK 已经模块化了!其中一个模块是名为`java.base`的模块。所有用户定义的模块都隐式地依赖(或需要)于`java.base`模块(想想每个类都隐式地扩展了`Object`类)。
正如第 1 章、“安装 Java 11”中提到的,JDK 附带了很多模块,即现有的 Java SDK 已经模块化了!其中一个模块是名为`java.base`的模块。所有用户定义的模块都隐式地依赖(或需要)于`java.base`模块(想想每个类都隐式地扩展了`Object`类)。
我们的`math.util`模块不依赖于任何其他模块(当然,除了`java.base`模块)。但是,它使其 API 可用于其他模块(如果不是,则该模块的存在是有问题的)。让我们继续并将此语句转换为代码:
......@@ -433,7 +433,7 @@ module math.util{
}
```
我们正在告诉 Java 编译器和运行时,我们的`math.util`模块正在*将`com.packt.math`包中的*代码导出到依赖于`math.util`的任何模块。
我们正在告诉 Java 编译器和运行时,我们的`math.util`模块正在`com.packt.math`包中的代码导出到依赖于`math.util`的任何模块。
此模块的代码可在`Chapter03/2_simple-modular-math-util/math.util`中找到。
......@@ -599,7 +599,7 @@ ModuleStatement:
* `uses`:用于声明对可通过`java.util.ServiceLoader`访问的服务接口的依赖关系。服务接口可以位于当前模块中,也可以位于当前模块所依赖的任何模块中。
* `provides`:用于声明一个服务接口,并为其提供至少一个实现。服务接口可以在当前模块或任何其他依赖模块中声明。但是,服务实现必须在同一模块中提供;否则,将发生编译时错误。
我们将在*中更详细地了解`uses`和`provides`条款,使用服务在消费者和提供者模块*之间创建松散耦合
我们将在“使用服务在消费者和提供者模块之间创建松散耦合”中更详细地了解`uses``provides`条款
可以使用`--module-source-path`命令行选项一次编译所有模块的模块源代码。这样,所有模块都将被编译并放置在`-d`选项提供的目录下相应的目录中。例如,`javac -d mods --module-source-path . $(find . -name "*.java")`将当前目录中的代码编译成`mods`目录。
......@@ -607,7 +607,7 @@ ModuleStatement:
# 另见
第一章*安装中的*编译和运行 Java 应用程序*配方,以及对 Java 11*的窥探
第一章“安装以及对 Java 11 的窥探”中的“编译和运行 Java 应用程序配方,
# 创建模块化 JAR
......@@ -615,7 +615,7 @@ ModuleStatement:
# 准备
我们已经在*创建更简单的模块化应用程序*配方中看到并创建了一个简单的模块化应用程序。为了构建模块化 JAR,我们将使用`Chapter03/3_modular_jar`中提供的示例代码。此示例代码包含两个模块:`math.util``calculator`。我们将为这两个模块创建模块化 jar。
我们已经在“创建更简单的模块化应用程序”配方中看到并创建了一个简单的模块化应用程序。为了构建模块化 JAR,我们将使用`Chapter03/3_modular_jar`中提供的示例代码。此示例代码包含两个模块:`math.util``calculator`。我们将为这两个模块创建模块化 jar。
# 怎么做。。。
......@@ -698,7 +698,7 @@ math.util@1.0
# 准备
对于这个配方,我们需要一个模块化的 jar 和一个非模块化的应用程序。我们的模块化代码可以在`Chapter03/4_modular_jar_with_pre_java9/math.util`中找到(这与我们在*创建简单模块化应用程序*配方中创建的`math.util`模块相同)。让我们编译此模块化代码,并使用以下命令创建模块化 JAR:
对于这个配方,我们需要一个模块化的 jar 和一个非模块化的应用程序。我们的模块化代码可以在`Chapter03/4_modular_jar_with_pre_java9/math.util`中找到(这与我们在“创建简单模块化应用程序”配方中创建的`math.util`模块相同)。让我们编译此模块化代码,并使用以下命令创建模块化 JAR:
```java
javac -d classes --module-source-path . $(find math.util -name *.java)
......@@ -717,7 +717,7 @@ math.util@1.0
# 怎么做。。。
现在,让我们创建一个简单的应用程序,它是非模块化的。我们的应用程序将由一个名为`NonModularCalculator`的类组成,该类在*创建一个简单的模块化应用程序*配方时借用了`Calculator`类的代码。
现在,让我们创建一个简单的应用程序,它是非模块化的。我们的应用程序将由一个名为`NonModularCalculator`的类组成,该类在“创建一个简单的模块化应用程序”配方时借用了`Calculator`类的代码。
您可以在`Chapter03/4_modular_jar_with_pre_java9/calculator`目录下的`com.packt.calculator`包中找到`NonModularCalculator`类定义。由于它是非模块化的,所以不需要`module-info.java`文件。此应用程序使用我们的模块化 JAR`math.util.jar`执行一些数学计算。
......@@ -764,7 +764,7 @@ java -cp classes:mlib/* com.packt.calculator.NonModularCalculator
使用未命名模块的概念,您可以原样使用 Java 8 应用程序并在 Java 9 上运行它(除了任何不推荐使用的内部 API,这些 API 可能不适用于 Java 9 中的用户代码)。
如果您尝试了使用 JDEP 在 Java 应用程序配方中查找依赖项的*方法,您可能已经看到了这一点,在 Java 应用程序*配方中,我们有一个非模块化的应用程序,并且能够在 Java 9 上运行它。然而,在 Java9 上按原样运行会破坏引入模块化系统的目的。
如果您尝试了“使用 JDEP 在 Java 应用程序中查找依赖项的方法”配方,您可能已经看到了这一点,在 Java 应用程序*配方中,我们有一个非模块化的应用程序,并且能够在 Java 9 上运行它。然而,在 Java9 上按原样运行会破坏引入模块化系统的目的。
如果在命名模块和未命名模块中都定义了包,则命名模块中的包将优先于未命名模块中的包。这有助于防止来自命名模块和未命名模块的包冲突。
......@@ -826,7 +826,7 @@ java -cp calculator/out/classes:calculator/lib/*:math_util/out/math.util.jar:ban
# 怎么做。。。
模块化应用程序的第一步是理解其依赖关系图。让我们为应用程序创建一个依赖关系图。为此,我们使用了`jdeps`工具。如果您想知道`jdeps`工具是什么,请立即停止并阅读*使用 JDEP 查找 Java 应用程序*配方中的依赖项。好的,让我们运行`jdeps`工具:
模块化应用程序的第一步是理解其依赖关系图。让我们为应用程序创建一个依赖关系图。为此,我们使用了`jdeps`工具。如果您想知道`jdeps`工具是什么,请立即停止并阅读“使用 JDEP 查找 Java 应用程序的依赖项”配方。好的,让我们运行`jdeps`工具:
```java
jdeps -summary -R -cp calculator/lib/*:math_util/out/*:banking_util/out/* calculator/out/calculator.jar
......@@ -886,9 +886,9 @@ math.util.jar -> java.base
jar --create --file=mlib/banking.util.jar -C mods/banking.util .
```
如果您想知道什么是模块化JAR,请随意阅读本章中的*创建模块化JAR***配方******
如果您想知道什么是模块化JAR,请随意阅读本章中的“创建模块化 JAR”配方。
****现在我们已经模块化了`banking.util.jar`,让我们使用这个模块化的`jar`来代替前面*准备*部分中使用的非模块化JAR。您应该从`6_bottom_up_migration_before`文件夹执行以下操作,因为我们尚未完全模块化应用程序:
现在我们已经模块化了`banking.util.jar`,让我们使用这个模块化的`jar`来代替前面“准备”部分中使用的非模块化JAR。您应该从`6_bottom_up_migration_before`文件夹执行以下操作,因为我们尚未完全模块化应用程序:
```java
java --add-modules ALL-MODULE-PATH --module-path ../6_bottom_up_migration_after/mods/banking.util -cp calculator/out/classes:calculator/lib/*:math_util/out/math.util.jar com.packt.calculator.Calculator
......@@ -926,9 +926,9 @@ java --add-modules ALL-MODULE-PATH --module-path ../6_bottom_up_migration_after/
jar --create --file=mlib/math.util.jar -C mods/math.util .
```
如果您想知道什么是模块化`jar`,请阅读本章中的*创建模块化JAR*配方。
如果您想知道什么是模块化`jar`,请阅读本章中的“创建模块化 JAR”配方。
6. 现在我们已经模块化了`math.util.jar`,让我们使用这个模块化的`jar`来代替前面在*准备*部分中使用的非模块化的`jar`。您应该从`6_bottom_up_migration_before`文件夹执行以下操作,因为我们尚未完全模块化应用程序:
6. 现在我们已经模块化了`math.util.jar`,让我们使用这个模块化的`jar`来代替前面在“准备”部分中使用的非模块化的`jar`。您应该从`6_bottom_up_migration_before`文件夹执行以下操作,因为我们尚未完全模块化应用程序:
```java
java --add-modules ALL-MODULE-PATH --module-path
......@@ -1038,7 +1038,7 @@ jar 表示一个代码基。我们假设代码库是以 JAR 的形式提供的
# 准备
我们将使用前面配方中介绍的计算器示例,*自底向上迁移*。继续从`Chapter03/7_top_down_migration_before`复制非模块化代码。如果要运行它并查看它是否工作,请使用以下命令:
我们将使用前面“自底向上迁移”配方中介绍的计算器示例。继续从`Chapter03/7_top_down_migration_before`复制非模块化代码。如果要运行它并查看它是否工作,请使用以下命令:
```java
$ javac -d math_util/out/classes/ -sourcepath math_util/src $(find math_util/src -name *.java)
......@@ -1100,7 +1100,7 @@ $ java -cp calculator/out/classes:calculator/lib/*:math_util/out/math.util.jar:b
`banking.util.jar` and `math.util.jar` will exist only if you have compiled and JAR-ed the code in the `Chapter03/7_top_down_migration_before/banking_util` and `Chapter03/7_top_down_migration_before/math_util` directories. We did this in the *Getting ready*section earlier.
2.`src`下新建一个`calculator`文件夹。这将包含`calculator`模块的代码。
3.包含以下**的`Chapter03/7_top_down_migration_after/src/calculator`目录下创建`module-info.java`:**
3.`Chapter03/7_top_down_migration_after/src/calculator`目录下创建`module-info.java`,包含以下内容:
```java
module calculator{
......@@ -1148,7 +1148,7 @@ $ java -cp calculator/out/classes:calculator/lib/*:math_util/out/math.util.jar:b
由于这不依赖于其他非模块代码,我们可以通过以下步骤直接将其转换为模块:
1.`src`下新建一个`banking.util`文件夹。这将包含`banking.util`模块的代码。
2.`Chapter03/7_top_down_migration_after/src/banking.util`**目录**下创建`module-info.java`,其中包含以下**:******
2.`Chapter03/7_top_down_migration_after/src/banking.util`目录下创建`module-info.java`,其中包含以下:
****```java
module banking.util{
......@@ -1187,7 +1187,7 @@ $ java -cp calculator/out/classes:calculator/lib/*:math_util/out/math.util.jar:b
# 模块化 math.util
1.`src`下新建一个`math.util`文件夹。这将包含`math.util`模块的代码。
2.`Chapter03/7_top_down_migration_after/src/math.util`**目录下创建`module-info.java`,其中包含以下******
2.`Chapter03/7_top_down_migration_after/src/math.util`目录下创建`module-info.java`,其中包含以下:
**```java
module math.util{
......@@ -1436,7 +1436,7 @@ Java9 中引入了一个名为`jlink`的新工具,它支持创建模块化运
# 准备
*创建简单模块化应用程序*配方中,我们创建了一个由以下模块组成的简单模块化应用程序:
“创建简单模块化应用程序”配方中,我们创建了一个由以下模块组成的简单模块化应用程序:
* `math.util`
* `calculator`:由主类组成
......@@ -1751,7 +1751,7 @@ Multi-Release: true
# 使用 Maven 开发模块化应用程序
在本教程中,我们将介绍如何使用 Maven(Java 生态系统中最流行的构建工具)来开发简单的模块化应用程序。我们将重复使用本章*服务*配方中介绍的想法。
在本教程中,我们将介绍如何使用 Maven(Java 生态系统中最流行的构建工具)来开发简单的模块化应用程序。我们将重复使用本章“服务”配方中介绍的想法。
# 准备
......@@ -1929,7 +1929,7 @@ mvn clean install
对于一个完全模块化的应用程序,它应该将自身及其依赖项模块化。现在,制作第三方模块不在应用程序开发人员的手中。一种方法是在模块路径中包含第三方`jar`,并使用`jar`的名称作为模块的名称来声明依赖关系。在这种情况下,`jar`成为一个自动模块。这是可以的,但通常情况下,`jar`的名称对模块名不友好,或者不符合有效模块名的语法。在这种情况下,我们使用 JDK 9 中添加的另一个支持,其中可以在`jar``MANIFEST.mf`文件中定义`jar`的名称,然后库使用者可以声明对定义名称的依赖关系。这样,在将来,库开发人员可以模块化他们的库,同时仍然使用相同的模块名。
在本配方中,我们将向您展示如何为从非模块化`jar`创建的自动模块提供名称。首先,我们将向您展示如何使用 maven 实现这一点,然后在*中还有更多。。。*部分,我们将了解如何在不使用任何构建工具的情况下创建 JAR。
在本配方中,我们将向您展示如何为从非模块化`jar`创建的自动模块提供名称。首先,我们将向您展示如何使用 maven 实现这一点,然后在“更多”部分,我们将了解如何在不使用任何构建工具的情况下创建 JAR。
# 准备
......
# 流和管道
# 流和管道
在 Java8 和 Java9 中,CollectionsAPI 通过利用 lambda 表达式引入流和内部迭代进行了重大的改头换面。在 Java10(JDK18.3)中,添加了新方法-`List.copyOf``Set.copyOf``Map.copyOf`,允许我们从现有实例创建新的不可变集合。此外,新方法`toUnmodifiableList``toUnmodifiableSet``toUnmodifiableMap`被添加到`java.util.stream`包中的`Collectors`类中,允许将`Stream`中的元素收集到一个不可变的集合中。本章介绍如何使用流和链多个操作来创建管道。此外,读者还将了解如何并行完成这些操作。配方列表包括以下内容:
......@@ -17,7 +17,7 @@
这种库的一个例子是`java.util.stream`包,这将是本章的重点。该包允许您对随后可以应用于数据的过程进行声明性表示,也可以并行应用;这些过程以流的形式呈现,流是`Stream`接口的对象。为了更好地从传统集合过渡到流,在`java.util.Collection`接口中添加了两种默认方法`stream()``parallelStream()`,同时在`Stream`接口中添加了流生成的新工厂方法。
这种方法利用了聚合的能力,如第 2 章*中所述,快速进入 OOP——类和接口*。与其他设计原则(封装、接口和多态)一起,它促进了高度可扩展和灵活的设计,而 lambda 表达式允许您以简洁的方式实现它。
这种方法利用了聚合的能力,如第 2 章*中所述,快速进入 OOP——类和接口*。与其他设计原则(封装、接口和多态)一起,它促进了高度可扩展和灵活的设计,而 lambda 表达式允许您以简洁的方式实现它。
如今,当海量数据处理和操作微调的机器学习需求变得无处不在时,这些新特性加强了 Java 在几种现代编程语言中的地位。
......
......@@ -1090,7 +1090,7 @@ Docker 是 Docker 集装箱化平台背后的公司,它创建了一组基本
测微计支持 [Prometheus](https://prometheus.io/)[Netflix Atlas](https://github.com/Netflix/atlas)[DataDogHQ](https://www.datadoghq.com/) 和即将推出的[对 XDB 的支持](https://www.influxdata.com/)[statsd](https://github.com/etsy/statsd)[Graphite](https://graphiteapp.org/)。使用早期版本的 Spring Boot(如 1.5)的应用程序也可以使用这个新的检测库,如*中所示,还有更多。。。*节。
在这个配方中,我们将使用测微计来检测我们的代码,并将度量值发送给Prometheus。因此,首先,我们将在*准备*部分设置Prometheus。
在这个配方中,我们将使用测微计来检测我们的代码,并将度量值发送给Prometheus。因此,首先,我们将在“准备”部分设置Prometheus。
# 准备
......
......@@ -12,7 +12,7 @@
* 选修课
* 重温职能
*
*
* TDD 在函数式编程中的应用
# 建立环境
......@@ -428,7 +428,7 @@ int compute(String expression) {
lambdas 非常适合的另一个很好的例子是 Streams API,因为大多数函数都有一个自解释的名称,比如`filter``map``reduce`等等。让我们在下一节更深入地探讨这个问题。
#
# 流
Java8 中包含的一个顶级实用程序是流。在本章中,我们将结合使用 lambda 和小代码片段中的流,并创建一个测试来验证它们。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册