提交 f5859a9a 编写于 作者: W wizardforcel

2021-04-11 16:09:19

上级 bb2bd2c4
......@@ -43,7 +43,7 @@
代码块设置如下:
```
```java
public class Car extends Vehicle
{
public Car(String name)
......@@ -55,7 +55,7 @@ public class Car extends Vehicle
任何命令行输入或输出的编写方式如下:
```
```java
java --list-modules
```
......
......@@ -72,7 +72,7 @@
让我们看看这将如何作为代码;我们将首先创建一个名为`Vehicle`的基类。该类有一个构造函数,它接受一个`String`(车辆名称):
```
```java
public class Vehicle
{
private Stringname;
......@@ -85,7 +85,7 @@ public class Vehicle
现在我们可以用构造函数创建一个`Car`类。`Car`类派生自`Vehicle`类,因此继承并可以访问基类中声明为 protected 或 public 的所有成员和方法:
```
```java
public class Car extends Vehicle
{
public Car(String name)
......@@ -103,7 +103,7 @@ public class Car extends Vehicle
为了详细说明,让我们以前面的示例为例,向 vehicle type 添加一个新方法来打印对象的类型和名称:
```
```java
public String toString()
{
return "Vehicle:"+name;
......@@ -112,7 +112,7 @@ public String toString()
我们在派生的`Car`类中重写相同的方法:
```
```java
public String toString()
{
return "Car:"+name;
......@@ -121,7 +121,7 @@ public String toString()
现在我们可以看到子类型多态性在起作用。我们创建一个`Vehicle`对象和一个`Car`对象。我们将每个对象分配给一个`Vehicle`变量类型,因为一个`Car`也是一个`Vehicle`。然后我们为每个对象调用`toString`方法。对于`vehicle1`,它是`Vehicle`类的一个实例,它将调用`Vehicle.toString()`类。`vehicle2``Car`类的实例,调用`Car`类的`toString`方法:
```
```java
Vehicle vehicle1 = new Vehicle("A Vehicle");
Vehicle vehicle2 = new Car("A Car")
System.out.println(vehicle1.toString());
......@@ -154,7 +154,7 @@ System.out.println(vehicle2.toString());
每个使用 Java 的人都知道集合。我们以一种强制性的方式使用集合:我们告诉程序如何做它应该做的事情。让我们以下面的示例为例,其中我们实例化了一个由 10 个整数组成的集合,从 1 到 10:
```
```java
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++)
{
......@@ -164,7 +164,7 @@ for (int i = 0; i < 10; i++)
现在,我们将创建另一个集合,在其中只过滤奇数:
```
```java
List<Integer> odds = new ArrayList<Integer>();
for (int val : list)
{
......@@ -175,7 +175,7 @@ for (int val : list)
最后,我们要打印结果:
```
```java
for (int val : odds)
{
System.out.print(val);
......@@ -184,7 +184,7 @@ for (int val : odds)
如您所见,我们编写了相当多的代码来执行三个基本操作:创建数字集合、过滤奇数,然后打印结果。当然,我们可以只在一个循环中完成所有的操作,但是如果我们完全不使用一个循环呢?毕竟,使用循环意味着我们告诉程序如何完成它的任务。从 Java 8 开始,我们就可以使用流在一行代码中完成同样的任务:
```
```java
IntStream
.range(0, 10)
.filter(i -> i % 2 == 0)
......@@ -328,7 +328,7 @@ LSP 声明,在设计模块和类时,我们必须确保从行为的角度来
我们已经定义了一个`Car`类。我们现在创建一个`Key`类,并在 car 类中添加两个方法:lock 和 unlock。我们添加了相应的方法,以便助手检查钥匙是否与汽车匹配:
```
```java
public class Assistant
{
void checkKey(Car car, Key key)
......@@ -349,7 +349,7 @@ public class Assistant
四轮马车没有门,所以不能上锁或开锁。我们相应地实现我们的代码:
```
```java
public bool lock(Key key)
{
// this is a buggy so it can not be locked return false;
......
......@@ -20,7 +20,7 @@ singleton 模式可能是自 Java 诞生以来使用最广泛的设计模式。
singleton 模式的实现非常简单,只包含一个类。为了确保 singleton 实例是唯一的,所有 singleton 构造函数都应该是私有的。全局访问是通过一个静态方法完成的,可以全局访问该方法来获取 singleton 实例,如下代码所示:
```
```java
public class Singleton
{
private static Singleton instance;
......@@ -43,7 +43,7 @@ public class Singleton
当我们需要在代码中的某个地方使用 singleton 对象时,我们只需这样调用它:
```
```java
Singleton.getInstance().doSomething();
```
......@@ -59,13 +59,13 @@ Singleton.getInstance().doSomething();
* 通过在其声明中添加`synchronized`关键字,使`getInstance`方法线程安全:
```
```java
public static synchronized Singleton getInstance()
```
*`if (instance == null)`状态包装在`synchronized`块中。当我们在这个上下文中使用`synchronized`块时,我们需要指定一个提供锁的对象。我们为此使用了`Singleton.class`对象,如下代码段所示:
```
```java
synchronized (SingletonSync2.class)
{
if (instance == null)
......@@ -79,7 +79,7 @@ synchronized (SingletonSync2.class)
`synchronized`块前增加一个附加条件,只有在单例还没有实例化时,才会移动线程安全锁:
```
```java
if (instance == null)
{
synchronized (SingletonSync2.class)
......@@ -96,7 +96,7 @@ if (instance == null)
Java 中单例模式的最佳实现之一依赖于一个类是一次加载的事实。通过在声明时直接实例化静态成员,我们可以确保只有一个类实例。此实现避免了锁定机制和查看实例是否已创建的附加检查:
```
```java
public class LockFreeSingleton
{
private static final LockFreeSingleton instance = new
......@@ -124,7 +124,7 @@ public class LockFreeSingleton
目前,Java 中没有可靠的选项来创建早期加载的单例。如果我们真的需要一个早期的实例化,我们应该在应用程序开始时强制它,只需调用`getInstance()`方法,如下代码所示:
```
```java
Singleton.getInstance();
```
......@@ -134,13 +134,13 @@ Singleton.getInstance();
当我们处理这样的场景时,最棘手的部分之一就是对象的创建。在面向对象编程中,使用特定类的构造函数实例化每个对象,如下代码所示:
```
```java
Vehicle vehicle = new Car();
```
这段代码意味着实例化对象的类和实例化对象的类之间的依赖关系。这样的依赖关系使得我们的代码紧密耦合,在不修改代码的情况下很难扩展。例如,如果我们需要用另一个类型替换`Car`,比如说`Truck`,我们需要相应地更改代码:
```
```java
Vehicle vehicle = new Truck();
```
......@@ -162,7 +162,7 @@ Vehicle vehicle = new Truck();
让我们编写一个简单的工厂来创建车辆实例。我们有一个抽象的`Vehicle`类和从中继承的三个具体类:`Bike``Car``Truck`。工厂,也称为静态工厂,将如下所示:
```
```java
public class VehicleFactory
{
public enum VehicleType
......@@ -193,13 +193,13 @@ public class VehicleFactory
对于此方法,我们将使用一个映射来保留产品 ID 及其相应的类:
```
```java
private Map<String, Class> registeredProducts = new HashMap<String,Class>();
```
然后,我们添加了一个注册新车的方法:
```
```java
public void registerVehicle(String vehicleId, Class vehicleClass)
{
registeredProducts.put(vehicleId, vehicleClass);
......@@ -208,7 +208,7 @@ public void registerVehicle(String vehicleId, Class vehicleClass)
`create`方法如下:
```
```java
public Vehicle createVehicle(String type) throws InstantiationException, IllegalAccessException
{
Class productClass = registeredProducts.get(type);
......@@ -224,13 +224,13 @@ public Vehicle createVehicle(String type) throws InstantiationException, Illegal
我们首先在基类`Vehicle`中添加一个抽象方法:
```
```java
abstract public Vehicle newInstance();
```
对于每个产品,必须实现基类中声明为 abstract 的方法:
```
```java
@Override
public Car newInstance()
{
......@@ -240,13 +240,13 @@ public Car newInstance()
`factory`类中,我们将更改映射以保留对象的 ID 以及`vehicle`对象:
```
```java
private Map<String, Vehicle> registeredProducts = new HashMap<String,Vehicle>();
```
然后我们通过传递一个实例来注册一个新类型的车辆:
```
```java
public void registerVehicle(String vehicleId, Vehicle vehicle)
{
registeredProducts.put(vehicleId, vehicle);
......@@ -255,7 +255,7 @@ public void registerVehicle(String vehicleId, Vehicle vehicle)
我们相应地改变`createVehicle`方法:
```
```java
public AbstractProduct createVehicle(String vehicleId)
{
return registeredProducts.get(vehicleId).newInstance();
......@@ -272,7 +272,7 @@ public AbstractProduct createVehicle(String vehicleId)
现在我们有了车辆结构,让我们建立抽象工厂。请注意,工厂没有创建新实例的任何代码:
```
```java
public abstract class VehicleFactory
{
protected abstract Vehicle createVehicle(String item);
......@@ -288,7 +288,7 @@ public abstract class VehicleFactory
为了添加代码来创建 car 实例,我们将`VehicleFactory`子类化,创建一个`CarFactory`。汽车工厂必须实现从父类调用的`createVehicle`抽象方法。实际上,`VehicleFactory`将具体车辆的实例化委托给子类:
```
```java
public class CarFactory extends VehicleFactory
{
@Override
......@@ -305,14 +305,14 @@ public class CarFactory extends VehicleFactory
在客户机中,我们只需创建工厂并创建订单:
```
```java
VehicleFactory carFactory = new CarFactory();
carFactory.orderVehicle("large", "blue");
```
在这一点上,我们意识到一个汽车厂能带来多少利润。是时候扩展我们的业务了,我们的市场调查告诉我们,卡车的需求量很大。那么让我们构建一个`TruckFactory`
```
```java
public class TruckFactory extends VehicleFactory
{
@Override
......@@ -329,7 +329,7 @@ public class TruckFactory extends VehicleFactory
启动订单时,我们使用以下代码:
```
```java
VehicleFactory truckFactory = new TruckFactory();
truckFactory.orderVehicle("large", "blue");
```
......@@ -338,7 +338,7 @@ truckFactory.orderVehicle("large", "blue");
我们继续前面的代码,添加了一个`BikeFactory`,客户可以从中选择一辆小自行车或一辆大自行车。我们不需要创建单独的类文件就可以做到这一点;我们可以简单地创建一个匿名类,直接在客户机代码中扩展`VehicleFactory`
```
```java
VehicleFactory bikeFactory = new VehicleFactory()
{
@Override
......@@ -413,7 +413,7 @@ builder 模式的作用与其他创造性模式相同,但它以不同的方式
`Director`类使用构建器来创建新的 car 对象。`buildElectricCar``buildGasolineCar`可能相似,但略有不同:
```
```java
public Car buildElectricCar(CarBuilder builder)
{
builder.buildCar();
......@@ -429,7 +429,7 @@ public Car buildElectricCar(CarBuilder builder)
但假设我们想制造一辆混合动力汽车,配备电动和汽油发动机:
```
```java
public Car buildHybridCar(CarBuilder builder)
{
builder.buildCar();
......@@ -459,7 +459,7 @@ public Car buildHybridCar(CarBuilder builder)
方法链接是一种从某些方法返回当前对象(`this`)的技术。这样,可以在链中调用这些方法。例如:
```
```java
public Builder setColor()
{
// set color
......@@ -469,7 +469,7 @@ public Builder setColor()
在我们定义了更多这样的方法之后,我们可以在一个链中调用它们:
```
```java
builder.setColor("Blue")
.setEngine("1500cc")
.addTank("50")
......@@ -479,7 +479,7 @@ builder.setColor("Blue")
但是,在我们的例子中,我们将使`builder`成为`Car`对象的内部类。因此,当我们需要新客户时,我们可以执行以下操作:
```
```java
Car car = new Car.Builder.setColor("Blue")
.setEngine("1500cc")
.addTank("50")
......@@ -532,7 +532,7 @@ Car car = new Car.Builder.setColor("Blue")
当一个`Client`需要一个新的`Resource`时,它向`ResourcePool`请求。池检查并获取第一个可用资源并将其返回给客户端:
```
```java
public Resource acquireResource()
{
if ( available.size() <= 0 )
......@@ -550,7 +550,7 @@ public Resource acquireResource()
然后,当`Client`结束使用`Resource`时,它释放它。资源被添加回工具,以便可以重用。
```
```java
public void releaseResource(Resource resource)
{
available.add(resource);
......
......@@ -41,7 +41,7 @@
每个处理程序都应该实现一个方法,客户机使用该方法设置下一个处理程序,如果无法处理请求,则应该将请求传递给该处理程序。此方法可以添加到基`Handler`类中:
```
```java
protected Handler successor;
public void setSuccessor(Handler successor)
{
......@@ -51,7 +51,7 @@ public void setSuccessor(Handler successor)
在每个`ConcreteHandler`类中,我们都有下面的代码,检查它是否能够处理请求;否则,它将传递请求:
```
```java
public void handleRequest(Request request)
{
if (canHandle(request))
......@@ -108,7 +108,7 @@ public void handleRequest(Request request)
最初,我们的冲动是在一个大的`if-else`块中处理所有可能的命令:
```
```java
public void performAction(ActionEvent e)
{
Object obj = e.getSource();
......@@ -125,7 +125,7 @@ public void performAction(ActionEvent e)
但是,我们可以决定将命令模式应用于绘图应用程序。我们首先创建一个命令界面:
```
```java
public interface Command
{
public void execute();
......@@ -134,7 +134,7 @@ public interface Command
下一步是将菜单项、按钮等所有对象定义为类,实现命令界面和`execute()`方法:
```
```java
public class OpenMenuItem extends JMenuItem implements Command
{
public void execute()
......@@ -146,7 +146,7 @@ public class OpenMenuItem extends JMenuItem implements Command
在我们重复前面的操作,为每个可能的操作创建一个类之后,我们将 naive 实现中的`if-else`块替换为以下块:
```
```java
public void performAction(ActionEvent e)
{
Command command = (Command)e.getSource();
......@@ -166,7 +166,7 @@ public void performAction(ActionEvent e)
在下面的代码中,runnable 接口作为命令接口,由`RunnableThread`实现:
```
```java
class RunnableThread implements Runnable
{
public void run()
......@@ -178,7 +178,7 @@ class RunnableThread implements Runnable
客户端调用命令以启动新线程:
```
```java
public class ClientThread
{
public static void main(String a[])
......@@ -217,7 +217,7 @@ public class ClientThread
以下代码为表达式创建接口:
```
```java
public interface Expression
{
public float interpret();
......@@ -229,7 +229,7 @@ public interface Expression
* **数字**:解释数字
* **运算符类****(+,-,*,/)**:对于下面的示例,我们将使用加号(+)和减号(-):
```
```java
public class Number implements Expression
{
private float number;
......@@ -246,7 +246,7 @@ public class Number implements Expression
现在我们到了困难的部分。我们需要实施运营商。运算符是复合表达式,由两个表达式组成:
```
```java
public class Plus implements Expression
{
Expression left;
......@@ -265,7 +265,7 @@ public class Plus implements Expression
类似地,我们有一个负实现,如下所示:
```
```java
public class Minus implements Expression
{
Expression left;
......@@ -286,7 +286,7 @@ public class Minus implements Expression
现在我们必须编写代码,使用我们创建的类来构建树:
```
```java
public class Evaluator
{
public float evaluate(String expression)
......@@ -349,7 +349,7 @@ public class Evaluator
Java 实现了`java.util.Parser`中的解释器模式,用于解释正则表达式。首先,在解释正则表达式时,将返回 matcher 对象。匹配器使用模式类基于正则表达式创建的内部结构:
```
```java
Pattern p = Pattern. compile("a*b");
Matcher m = p.matcher ("aaaaab");
boolean b = m.matches();
......@@ -380,7 +380,7 @@ boolean b = m.matches();
在 Java 中使用迭代器可能是每个程序员在日常生活中都要做的事情之一。让我们看看如何实现迭代器。首先,我们应该定义一个简单的迭代器接口:
```
```java
public interface Iterator
{
public Object next();
......@@ -395,7 +395,7 @@ public Iterator createIterator();
然后我们实现一个简单的`Aggregator`,它维护一个字符串值数组:
```
```java
public class StringArray implements Aggregate
{
private String values[];
......@@ -427,7 +427,7 @@ public class StringArray implements Aggregate
我们在聚合中嵌套了迭代器类。这是最好的选择,因为迭代器需要访问聚合器的内部变量。我们可以在这里看到它的样子:
```
```java
String arr[]= {"a", "b", "c", "d"};
StringArray strarr = new StringArray(arr);
for (Iterator it = strarr.createIterator(); it.hasNext();)
......@@ -438,7 +438,7 @@ System.out.println(it.next());
迭代器现在在大多数编程语言中都很流行。它可能与 collections 包一起在 Java 中使用最广泛。当使用以下循环构造遍历集合时,它也在语言级别实现:
```
```java
for (String item : strCollection)
System.out.println(item);
```
......@@ -526,7 +526,7 @@ memento 模式依赖于以下类:
我们首先创建`originator`类。我们将其命名为`CarOriginator`,并添加两个成员变量。`state`表示测试运行时车辆的参数。这是我们要保存的对象的状态;第二个成员变量是 result。这是测得的汽车输出,我们不需要存储在纪念品。这是一个空巢纪念品的发起者:
```
```java
public class CarOriginator
{
private String state;
......@@ -566,7 +566,7 @@ public class CarOriginator
现在我们对不同的州进行汽车测试:
```
```java
public class CarCaretaker
{
public static void main(String s[])
......
......@@ -48,7 +48,7 @@ JDK 中的`java.io.InputStreamReader`和`java.io.OutputStreamWriter`类是适配
下面的代码模拟在 USB 总线中使用 PS/2 键盘。它定义了一个 PS/2 键盘(适配器)、一个 USB 设备接口(目标)、一个 PS2ToUSBAdapter(适配器)和使设备工作的连接线:
```
```java
package gof.structural.adapter;
import java.util.Arrays;
import java.util.Collections;
......@@ -86,7 +86,7 @@ class WireCap
顾名思义,`WireCap`类模型是每根导线的两端。默认情况下,所有导线都是松的;因此,我们需要一种方法来发出信号。这是通过使用空对象模式来完成的,`LooseCap`是我们的空对象(一个空替换,它不抛出`NullPointerException`)。请看下面的代码:
```
```java
class Wire
{
private String name;
......@@ -141,7 +141,7 @@ class Wire
`Wire`类对来自 USB 或 PS/2 设备的电线进行建模。它有两端,默认情况下是松散的,如以下代码所示:
```
```java
class USBPort
{
publicfinal Wire wireRed = new Wire("USB Red5V");
......@@ -153,7 +153,7 @@ class USBPort
根据 USB 规范,USBPort 有四根导线:5V 红色、绿色和白色导线用于数据,黑色导线用于接地,如下代码所示:
```
```java
interface PS2Device
{
staticfinal String GND = "PS/2 GND";
......@@ -188,7 +188,7 @@ class PS2Keyboard implements PS2Device
`PS2Keyboard`是适配器。我们需要使用的是旧设备,如下代码所示:
```
```java
interface USBDevice
{
publicvoid plugInto(USBPort port);
......@@ -197,7 +197,7 @@ interface USBDevice
`USBDevice`是目标接口。它知道如何与`USBPort`接口,如下代码所示:
```
```java
class PS2ToUSBAdapter implements USBDevice
{
private PS2Device device;
......@@ -234,7 +234,7 @@ class PS2ToUSBAdapter implements USBDevice
`PS2ToUSBAdapter`是我们的适配器类。它知道如何布线,以便新的`USBPort`仍然可以使用旧的设备,如下代码所示:
```
```java
publicclass Main
{
publicstaticvoid main (String[] args)
......@@ -282,7 +282,7 @@ publicclass Main
下面的代码模拟从 localhost EJB 上下文中查找 bean 的远程代理。我们的远程代理是在另一个 JVM 中运行的几何计算器。我们将使用工厂方法来制作代理和真实对象,以证明它们是可互换的。代理版本的计算时间更长,因为我们还模拟 JNI 查找部分并发送/检索结果。看看代码:
```
```java
package gof.structural.proxy;
publicclass Main
{
......@@ -304,7 +304,7 @@ interface GeometryCalculatorBean
这是我们的主题,我们要实现的接口。模拟`@RemoteInterface``@LocalInterface`接口的建模,如下代码所示:
```
```java
class GeometryBean implements GeometryCalculatorBean
{
publicdouble calculateCircleCircumference(Circle circle)
......@@ -316,7 +316,7 @@ class GeometryBean implements GeometryCalculatorBean
这是我们真正的主题,知道如何执行实际的几何计算,如以下代码所示:
```
```java
class GeometryBeanProxy implements GeometryCalculatorBean
{
private GeometryCalculatorBean bean;
......@@ -344,7 +344,7 @@ class GeometryBeanProxy implements GeometryCalculatorBean
这是我们的代理主题。请注意,它没有业务逻辑;它在设法建立对它的句柄之后,将它委托给真正的主题,如以下代码所示:
```
```java
enum GeometryCalculatorBeanFactory
{
LOCAL
......@@ -388,7 +388,7 @@ enum GeometryCalculatorBeanFactory
`JScrollPane`swing 类是 decorator 的一个示例,因为它允许在现有容器周围添加新功能,例如滚动条,并且可以多次执行,如下代码所示:
```
```java
JTextArea textArea = new JTextArea(10, 50);
JScrollPane scrollPane1 = new JScrollPane(textArea);
JScrollPane scrollPane2 = new JScrollPane(scrollPane1);
......@@ -415,7 +415,7 @@ JScrollPane scrollPane2 = new JScrollPane(scrollPane1);
下面的代码显示了如何增强简单的打印 ASCII 文本,以打印输入的十六进制等效字符串,以及实际文本:
```
```java
package gof.structural.decorator;
import java.util.stream.Collectors;
publicclass Main
......@@ -445,7 +445,7 @@ class PrintAsciiText implements PrintText
`PrintASCIIText`是要装饰的构件。注意,它只知道如何打印`ASCII`文本。我们想让它也以十六进制打印;我们可以使用下面的代码
```
```java
class PrintTextHexDecorator implements PrintText
{
private PrintText inner;
......@@ -497,7 +497,7 @@ class PrintTextHexDecorator implements PrintText
下面的代码展示了一个电子邮件客户端,它使用了基于运行平台的实现。可以使用工厂方法模式对其进行增强,以创建特定的平台实现:
```
```java
package gof.structural.bridge;
publicclass Main
{
......@@ -515,7 +515,7 @@ interface PlatformBridge
`PlatformBridge`是我们的实现抽象类。它指定了每个实现需要提供什么—在我们的例子中,是转发文本给出的消息。以下两种实现(Windows 和 POSIX)都知道如何执行此任务:
```
```java
class WindowsImplementation implements PlatformBridge
{
publicvoid forwardMessage(String msg)
......@@ -549,7 +549,7 @@ class MessageSender
抽象`MessageSender`使用特定于平台的实现发送消息。`AllMessageClient`细化抽象向特定组`development_all@abc.com`发送消息。其他可能的精化抽象可以包括特定于平台的代码和对平台实现的调用。代码如下:
```
```java
class AllMessageClient extends MessageSender
{
private String to = "development_all@abc.com";
......@@ -599,7 +599,7 @@ Composite 使用递归组合,其中客户端代码以相同的方式处理每
下面的代码为算术表达式计算器建模。表达式被构造为复合表达式,并且只有一个方法-`getValue`。这将给出当前值;对于叶,它是叶数值,对于组合节点,它是子组合值:
```
```java
package gof.structural.composite;
publicclass Main
{
......@@ -615,7 +615,7 @@ publicclass Main
客户端代码创建一个*(1+4)-2*算术表达式并打印其值,如下代码所示:
```
```java
interface ArithmeticComposite
{
publicint getValue();
......@@ -624,7 +624,7 @@ interface ArithmeticComposite
`ArithmeticComposite`是我们的复合接口,它只知道如何返回一个整数值,表示算术表达式的值(composition-`ArithmeticOperand`)或 hold 值(leaf-`NumericValue`),如下代码所示:
```
```java
class NumericValue implements ArithmeticComposite
{
privateint value;
......@@ -708,7 +708,7 @@ façade 模式需要采用内部子系统接口(多个接口)到客户机代
从下面的代码中你会发现,问题是我们不能得到细磨咖啡(我们必须把咖啡豆磨得再久一点),因为`serveCoffee()`方法只知道如何制作粗磨咖啡。这对一些喝咖啡的人来说是好的,但对所有人来说不是这样:
```
```java
package gof.structural.facade;
publicclass Main
{
......@@ -728,7 +728,7 @@ class CoffeeCup
`GroundCoffee``Water``CoffeeCup`是我们将要使用的项目类:
```
```java
interface CoffeeMachineFacade
{
public CoffeeCup serveCoffee() throws Exception;
......@@ -737,7 +737,7 @@ interface CoffeeMachineFacade
`CoffeeMachineFacade`是我们的正面。它提供了一个方法,返回一个包含`Coffee``CoffeCup`
```
```java
interface CoffeeGrinder
{
publicvoid startGrinding();
......@@ -789,7 +789,7 @@ class SuperstarCoffeeMaker implements CoffeeMaker
为了煮咖啡,我们使用不同的机器,比如咖啡研磨机和咖啡机。它们都是巨星公司的产品。façade 机器是一个虚拟机;它只是我们现有机器的一个接口,并且知道如何使用它们。不幸的是,它不是高度可配置的,但它完成了大多数现有的咖啡饮料者的工作。让我们看看这个代码:
```
```java
class SuperstarCoffeeMachine implements CoffeeMachineFacade
{
public CoffeeCup serveCoffee() throws InterruptedException
......@@ -842,7 +842,7 @@ flyweight 和 façade 的区别在于前者知道如何制作许多小对象,
下面的代码使用附加的物理引擎模拟三维世界。因为创建新的 3D 对象在内存方面是沉重和昂贵的,一旦创建它们就会是相同的,只是从一个地方移动到另一个地方。想象一个有很多岩石、树木、灌木和不同纹理的 3D 世界。只有一种岩石,一棵树,一丛灌木(它们可以共享一些纹理),只要记住它们的位置,我们就节省了大量的内存,我们仍然能够用它们填充相当大的地形:
```
```java
package gof.structural.flyweight;
import java.util.ArrayList;
import java.util.List;
......@@ -871,7 +871,7 @@ enum _3DObjectTypes
我们的 3D 世界目前只由立方体和球体构成。它们可以组合在一起形成更复杂的形式,如以下代码所示:
```
```java
class PhysicsEngine
{
publicvoid animateCollision(_3DObject collider, _3DObject
......@@ -934,7 +934,7 @@ class World
`World`类表示 flyweight 工厂。它知道如何构造它们,并把自己当作一种外在的状态。除了渲染部分外,`World`类还使用了昂贵的物理引擎,它知道如何对碰撞进行建模。让我们看看代码:
```
```java
class _3DObject
{
private World world;
......@@ -981,7 +981,7 @@ class Sphere extends _3DObject
三维物体`Sphere``Cube`是飞锤,它们没有同一性。`World`类知道它们的身份和属性(位置、颜色、纹理和大小)。请看下面的代码:
```
```java
class Location
{
public Location(double x, double y, double z)
......
......@@ -84,14 +84,14 @@ java8 引入了 lambda 表达式(以前通过使用匿名类提供),实现
高阶函数是可以将其他函数作为参数,创建并返回它们的函数。它们通过使用现有的和已经测试过的小函数来促进代码重用。例如,在下面的代码中,我们计算给定温度(华氏度)的平均值(摄氏度):
```
```java
jshell> IntStream.of(70, 75, 80, 90).map(x -> (x - 32)*5/9).average();
$4 ==> OptionalDouble[25.5]
```
注意在高阶 map 函数中使用 lambda 表达式。相同的 lambda 表达式可以在多个地方用于转换温度。
```
```java
jshell> IntUnaryOperator convF2C = x -> (x-32)*5/9;
convF2C ==> $Lambda$27/1938056729@4bec1f0c
jshell> IntStream.of(70, 75, 80, 90).map(convF2C).average();
......@@ -106,7 +106,7 @@ $7 ==> 26Function
为了使函数的组成更加直观,我们可以用`andThen`方法重写转换公式:
```
```java
jshell> IntUnaryOperator convF2C = ((IntUnaryOperator)(x -> x-32)).andThen(x -> x *5).andThen(x -> x / 9);
convF2C ==> java.util.function.IntUnaryOperator$$Lambda$29/1234776885@dc24521
jshell> convF2C.applyAsInt(80);
......@@ -117,7 +117,7 @@ $23 ==> 26
**Curry**是将一个 n 元函数转化为一系列或一元函数的过程,它是以美国数学家 Haskell Curry 的名字命名的。形式`g:: x -> y -> z``f :: (x, y) -> z`的咖喱形式。对于前面给出的平方半径公式,`f(x,y) = x<sup class="calibre33">2</sup> + y<sup class="calibre33">2</sup>`,一个 curried 版本,不使用双函数,将使用 apply 多次。一个函数的单一应用程序只会用一个值替换参数,正如我们前面看到的。下面的代码展示了如何创建一个双参数函数,对于*n*个参数,`Function<X,Y>`类的 apply 函数将有 n 个调用:
```
```java
jshell> Function<Integer, Function<Integer, Integer>> square_radius = x -> y -> x*x + y*y;
square_radius ==> $Lambda$46/1050349584@6c3708b3
jshell> List<Integer> squares = Arrays.asList(new Tuple<Integer, Integer>(1, 5), new Tuple<Integer, Integer>(2, 3)).stream().
......@@ -130,7 +130,7 @@ squares ==> [26, 13]
闭包是实现词汇作用域的一种技术。词法范围允许我们访问内部范围内的外部上下文变量。假设在前面的例子中,*y*变量已经被赋值。lambda 表达式可以保持一元表达式,并且仍然使用*y*作为变量。这可能会导致一些很难找到的 bug,如在下面的代码中,我们希望函数的返回值保持不变。闭包捕获一个对象的当前值,正如我们在下面的代码中看到的,我们的期望是,`add100`函数总是将 100 添加到给定的输入中,但是它没有:
```
```java
jshell> Integer a = 100
a ==> 100
jshell> Function<Integer, Integer> add100 = b -> b + a;
......@@ -153,14 +153,14 @@ $40 ==> 110
函子允许我们对给定的容器应用函数。他们知道如何从包装对象中展开值,应用给定的函数,并返回另一个包含结果/转换包装对象的函子。它们很有用,因为它们抽象了多种习惯用法,如集合、未来(承诺)和选择。下面的代码演示了 Java 中的`Optional`functor 的用法,其中`Optional`可以是一个给定的值,这是将函数应用于现有的包装值(`5``Optional`的结果):
```
```java
jshell> Optional<Integer> a = Optional.of(5);
a ==> Optional[5]
```
现在我们将函数应用于值为 5 的包装整数对象,得到一个新的可选保持值 4.5:
```
```java
jshell> Optional<Float> b = a.map(x -> x * 0.9f);
b ==> Optional[4.5]
jshell> b.get()
......@@ -173,7 +173,7 @@ $7 ==> 4.5
应用程序添加了一个新级别的包装,而不是将函数应用于包装对象,函数也被包装。在下面的代码中,函数被包装在一个可选的。为了证明应用程序的一个用法,我们还提供了一个标识(所有内容都保持不变)选项,以防所需的函数(在我们的例子中是`toUpperCase`)为空。因为没有语法糖来自动应用包装函数,所以我们需要手动执行,请参阅`get().apply()`代码。注意 java9 added 方法`Optional.or()`的用法,如果我们的输入 Optional 为空,它将延迟返回另一个`Optional`
```
```java
jshell> Optional<String> a = Optional.of("Hello Applicatives")
a ==> Optional[Hello Applicatives]
jshell> Optional<Function<String, String>> upper = Optional.of(String::toUpperCase)
......@@ -184,7 +184,7 @@ $3 ==> Optional[HELLO APPLICATIVES]
这是我们的应用程序,它知道如何将给定的字符串大写。让我们看看代码:
```
```java
jshell> Optional<Function<String, String>> identity = Optional.of(Function.identity())
identity ==> Optional[java.util.function.Function$$Lambda$16/1580893732@5c3bd550]
jshell> Optional<Function<String, String>> upper = Optional.empty()
......@@ -199,7 +199,7 @@ $6 ==> Optional[Hello Applicatives]
**单子**应用一个函数,将一个包装值返回给一个包装值。Java 包含了`Stream``CompletableFuture`和已经出现的`Optional`等示例。`flatMap`函数通过将给定的函数应用于邮政编码地图中可能存在或不存在的邮政编码列表来实现这一点,如下代码所示:
```
```java
jshell> Map<Integer, String> codesMapping = Map.of(400500, "Cluj-Napoca", 75001, "Paris", 10115, "Berlin", 10000, "New York")
codesMapping ==> {400500=Cluj-Napoca, 10115=Berlin, 10000=New York, 75001=Paris}
jshell> List<Integer> codes = List.of(400501, 75001, 10115, 10000)
......@@ -232,7 +232,7 @@ Lambda 表达式是用于`java.util.functions`包接口的语法。最重要的
* `BiPredicate<T,U>`:由两个参数(也称为谓词)组成的布尔返回函数,用于调用其`test`方法。
* `Consumer<T>`:使用单个输入参数的操作。就像它的二进制对应项一样,它支持链接,并通过调用它的`apply`方法来应用,如下面的示例所示,其中使用者是`System.out.println`方法:
```
```java
jshell> Consumer<Integer> printToConsole = System.out::println;
print ==> $Lambda$24/117244645@5bcab519
jshell> printToConsole.accept(9)
......@@ -241,7 +241,7 @@ jshell> printToConsole.accept(9)
* `Function<T,R>`:接受一个参数并产生结果的函数。它转换输入,而不是变异。它可以通过调用其 apply 方法直接使用,使用`andThen`链接,使用`compose`方法组合,如下面的示例代码所示。这样,我们的代码就可以通过在现有函数的基础上构造新函数来保持**干燥**(缩写为**不要重复**):
```
```java
jshell> Function<Integer, Integer> square = x -> x*x;
square ==> $Lambda$14/1870647526@47c62251
jshell> Function<Integer, String> toString = x -> "Number : " + x.toString();
......@@ -254,7 +254,7 @@ $4 ==> "Number : 16"
* `Predicate<T>`:一个参数的布尔返回函数。在下面的代码中,我们将测试字符串是否完全小写:
```
```java
jshell> Predicate<String> isLower = x -> x.equals(x.toLowerCase())
isLower ==> $Lambda$25/507084503@490ab905
jshell> isLower.test("lower")
......@@ -265,7 +265,7 @@ $9 ==> false
* `Supplier<T>`:这是一个价值供应商:
```
```java
jshell> String lambda = "Hello Lambda"
lambda ==> "Hello Lambda"
jshell> Supplier<String> closure = () -> lambda
......@@ -290,7 +290,7 @@ Java9 除了前面提到的`Optional`之外,还添加了更多返回流的类
中间流操作是延迟应用的;这意味着只有在终端操作被调用之后才进行实际调用。在下面的代码中,使用在网上使用[随机生成的名称 http://www.behindthename.com/random/?](http://www.behindthename.com/random/?),一旦找到第一个有效名称,搜索将停止(只返回一个`Stream<String>`对象):
```
```java
jshell> Stream<String> stream = Arrays.stream(new String[] {"Benny Gandalf", "Aeliana Taina","Sukhbir Purnima"}).
...> map(x -> { System.out.println("Map " + x); return x; }).
...> filter(x -> x.contains("Aeliana"));
......@@ -306,7 +306,7 @@ $3 ==> Optional[Aeliana Taina]
* `sequential()`:将当前流设置为串行流。
* `parallel()`:将当前流设置为可能的平行流。根据经验,对大型数据集使用并行流,并行化可以提高性能。在我们的代码中,并行操作会导致性能下降,因为并行化的成本大于收益,而且我们正在处理一些否则无法处理的条目:
```
```java
jshell> Stream<String> stream = Arrays.stream(new String[] {"Benny Gandalf", "Aeliana Taina","Sukhbir Purnima"}).
...> parallel().
...> map(x -> { System.out.println("Map " + x); return x; }).
......@@ -322,7 +322,7 @@ $14 ==> Optional[Aeliana Taina]
* `unordered()`:无序处理输入。它使得序列流的输出顺序具有不确定性,并通过允许更有效地实现一些聚合函数(如去重复或`groupBy`),从而提高并行执行的性能。
* `onClose(..)`:使用给定的输入处理程序关闭流使用的资源。`Files.lines(...)`流利用它来关闭输入文件,比如在下面的代码中,它是自动关闭的,但是也可以通过调用`close()`方法手动关闭流:
```
```java
jshell> try (Stream<String> stream = Files.lines(Paths.get("d:/input.txt"))) {
...> stream.forEach(System.out::println);
...> }
......@@ -342,7 +342,7 @@ Sukhbir Purnima
下面的代码显示了`peek``limit``skip`方法的用法。它计算出商务旅行折合成欧元的费用。第一笔和最后一笔费用与业务无关,因此需要过滤掉(也可以使用`filter()`方法)。`peek`方法是打印费用总额中使用的费用:
```
```java
jshell> Map<Currency, Double> exchangeToEur = Map.of(Currency.USD, 0.96, Currency.GBP, 1.56, Currency.EUR, 1.0);
exchangeToEur ==> {USD=0.96, GBP=1.56, EUR=1.0}
jshell> List<Expense> travelExpenses = List.of(new Expense(10, Currency.EUR, "Souvenir from Munchen"), new Expense(10.5, Currency.EUR, "Taxi to Munich airport"), new Expense(20, Currency.USD, "Taxi to San Francisco hotel"), new Expense(30, Currency.USD, "Meal"), new Expense(21.5, Currency.GBP, "Taxi to San Francisco airport"), new Expense(10, Currency.GBP, "Souvenir from London"));
......@@ -360,7 +360,7 @@ $38 ==> 92.03999999999999
除了前面介绍的`Stream<T>.ofNullable`方法外,Java9 还引入了`dropWhile``takeWhile`。它们的目的是让开发人员更好地处理无限流。在下面的代码中,我们将使用它们将打印的数字限制在 5 到 10 之间。移除上限(由`takeWhile`设置)将导致无限大的递增数字打印(在某个点上,它们将溢出,但仍会继续增加–例如,在迭代方法中,使用*x->x+100_*):
```
```java
jshell> IntStream.iterate(1, x-> x + 1).
...> dropWhile(x -> x < 5).takeWhile(x -> x < 7).
...> forEach(System.out::println);
......@@ -388,7 +388,7 @@ jshell> IntStream.iterate(1, x-> x + 1).
使用闭包和`Supplier<T>`可以重新实现单例模式。Java 混合代码可以利用`Supplier<T>`接口,比如在下面的代码中,singleton 是一个 enum(根据函数编程,singleton 类型是那些只有一个值的类型,就像 enum 一样)。以下示例代码与[第 2 章](2.html)*创作模式*中的代码类似:
```
```java
jshell> enum Singleton{
...> INSTANCE;
...> public static Supplier<Singleton> getInstance()
......@@ -409,13 +409,13 @@ Something is Done.
Lombock 库将生成器作为其功能的一部分引入。只要使用`@Builder`注释,任何类都可以自动获得对`builder`方法的访问权,如 Lombock 示例代码在[中所示 https://projectlombok.org/features/Builder](https://projectlombok.org/features/Builder)
```
```java
Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
```
其他 Java8 之前的实现使用反射来创建通用生成器。Java 8+generic builder 版本可以通过利用供应商和`BiConsumer`组合来实现,如下代码所示:
```
```java
jshell> class Person { private String name;
...> public void setName(String name) { this.name = name; }
...> public String getName() { return name; }}
......@@ -438,7 +438,7 @@ $94 ==> "Gandalf"
最好的例子是使用 map 函数,它执行从旧接口到新接口的自适应。我们将重用[第 4 章](4.html)中的示例*结构模式*,稍加改动;映射模拟适配器代码:
```
```java
jshell> class PS2Device {};
| created class PS2Device
jshell> class USBDevice {};
......@@ -453,7 +453,7 @@ decorator 可以通过利用函数组合来实现。例如,如前所示,可
我们的[第 4 章](4.html)*结构模式*,decorator 示例可以用函数式重写;注意 decorator 用于使用与初始 decorated consumer 相同的输入:
```
```java
jshell> Consumer<String> toASCII = x -> System.out.println("Print ASCII: " + x);
toASCII ==> $Lambda$159/1690859824@400cff1a
jshell> Function<String, String> toHex = x -> x.chars().boxed().map(y -> "0x" + Integer.toHexString(y)).collect(Collectors.joining(" "));
......@@ -469,7 +469,7 @@ Print HEX: 0x74 0x65 0x78 0x74
责任链可以实现为处理程序(函数)的列表,每个处理程序执行一个特定的操作。下面的示例代码使用闭包和一系列函数,这些函数一个接一个地应用于给定的文本:
```
```java
jshell> String text = "Text";
text ==> "Text"
jshell> Stream.<Function<String, String>>of(String::toLowerCase, x -> LocalDateTime.now().toString() + " " + x).map(f -> f.apply(text)).collect(Collectors.toList())
......@@ -482,7 +482,7 @@ $55 ==> [text, 2017-08-10T08:41:28.243310800 Text]
在下面的代码中,我们将创建一个命令列表并逐个执行它们:
```
```java
jshell> List<Consumer<String>> tasks = List.of(System.out::println, x -> System.out.println(LocalDateTime.now().toString() + " " + x))
tasks ==> [$Lambda$192/728258269@6107227e, $Lambda$193/1572098393@7c417213]
jshell> tasks.forEach(x -> x.accept(text))
......@@ -494,7 +494,7 @@ Text
解释器的语法可以存储为关键字映射,相应的操作存储为值。在[第二章](2.html)*创作模式*中,我们使用了一个数学表达式求值器,将结果累加成一个堆栈。这可以通过将表达式存储在映射中来实现,并使用 reduce 来累加结果:
```
```java
jshell> Map<String, IntBinaryOperator> operands = Map.of("+", (x, y) -> x + y, "-", (x, y) -> x - y)
operands ==> {-=$Lambda$208/1259652483@65466a6a, +=$Lambda$207/1552978964@4ddced80}
jshell> Arrays.asList("4 5 + 6 -".split(" ")).stream().reduce("0 ",(acc, x) -> {
......@@ -513,7 +513,7 @@ $76 ==> "3"
迭代器部分是通过使用流提供的序列来实现的。Java 8 添加了`forEach`方法,该方法接收消费者作为参数,其行为与前面的循环实现类似,如下面的示例代码所示:
```
```java
jshell> List.of(1, 4).forEach(System.out::println)
jshell> for(Integer i: List.of(1, 4)) System.out.println(i);
```
......@@ -524,7 +524,7 @@ jshell> for(Integer i: List.of(1, 4)) System.out.println(i);
在 Java8 中,观察者模式被 lambda 表达式取代。最明显的例子是`ActionListener`替换。使用匿名类侦听器的旧代码被替换为一个简单的函数调用:
```
```java
JButton button = new Jbutton("Click Here");
button.addActionListener(new ActionListener()
{
......@@ -537,7 +537,7 @@ button.addActionListener(new ActionListener()
新代码只有一行:
```
```java
button.addActionListener(e -> System.out.println("Handled by lambda"));
```
......@@ -545,7 +545,7 @@ button.addActionListener(e -> System.out.println("Handled by lambda"));
这个策略可以被一个函数代替。在下面的代码示例中,我们对所有价格应用 10%的折扣策略:
```
```java
jshell> Function<Double, Double> tenPercentDiscount = x -> x * 0.9;
tenPercentDiscount ==> $Lambda$217/1990160809@4c9f8c13
jshell> List.<Double>of(5.4, 6.27, 3.29).stream().map(tenPercentDiscount).collect(Collectors.toList())
......@@ -556,7 +556,7 @@ $98 ==> [4.86, 5.643, 2.9610000000000003]
当模板提供调用顺序时,可以实现模板方法以允许注入特定的方法调用。在下面的示例中,我们将添加特定的调用并从外部设置它们的内容。它们可能已经插入了特定的内容。通过使用接收所有可运行项的单个方法,可以简化代码:
```
```java
jshell> class TemplateMethod {
...> private Runnable call1 = () -> {};
...> private Runnable call2 = () -> System.out.println("Call2");
......@@ -603,7 +603,7 @@ MapReduce 是 Google 开发的一种用于大规模并行编程的技术,由
我们将通过基于给定的 Sleuth 跨度解析和聚合来自多个 web 服务的日志并计算每个命中端点的总持续时间来演示 MapReduce 模式的用法。日志取自[https://cloud.spring.io/spring-cloud-sleuth/spring-cloud-sleuth.html](https://cloud.spring.io/spring-cloud-sleuth/spring-cloud-sleuth.html)并拆分成相应的服务日志文件。下面的代码并行读取所有日志、映射、排序和过滤相关日志条目,收集并减少(聚合)结果。如果有结果,它将被打印到控制台。导入的日期/时间类用于排序比较。`flatMap`代码需要处理`Exception`,如下代码所示:
```
```java
jshell> import java.time.*
jshell> import java.time.format.*
jshell> DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")
......@@ -645,7 +645,7 @@ Loan 模式确保资源一旦超出范围就被决定性地处置。资源可以
在处理数据库事务时,最常用的模板之一是获取事务、进行适当的调用、确保在异常时提交或回滚并关闭事务。这可以实现为贷款模式,其中移动部分是事务中的调用。以下代码显示了如何实现这一点:
```
```java
jshell> class Connection {
...> public void commit() {};
public void rollback() {};
......@@ -674,7 +674,7 @@ Execute statement...
独眼巨人 react 的维护者 John McClean 演示了 TCO 在 Fibonacci 序列中计算数字的用法 https://gist.github.com/johnmcclean/fb1735b49e6206396bd5792ca11ba7b2。代码简洁易懂,基本上是从初始状态 a 和 b 开始累加斐波那契数,*f(0)=0**f(1)=1-*,应用*f(n)=f(n-1)+f(n-2)*函数:
```
```java
importstatic cyclops.control.Trampoline.done;
importstatic cyclops.control.Trampoline.more;
import cyclops.control.Trampoline;
......@@ -709,7 +709,7 @@ publicclass Main
在下面的示例中,我们将重用 Fibonacci 代码并添加 Guava 缓存。缓存将保存 Fibonacci 的返回值,而键是输入数字。缓存配置为在大小和时间上限制内存占用:
```
```java
importstatic cyclops.control.Trampoline.done;
importstatic cyclops.control.Trampoline.more;
import java.math.BigInteger;
......@@ -765,7 +765,7 @@ publicclass Main
输出如下:
```
```java
Regular version took 19022 ms
Memoized version took 394 ms
......@@ -783,7 +783,7 @@ Memoized version took 394 ms
上一个示例中提到的代码包含重复的代码(代码气味)。我们将应用 executearound 模式来简化代码并使其更易于阅读。可能的重构可以使用 lambda,如我们所见:
```
```java
publicstaticvoid measurePerformance(Runnable runnable)
{
long start = System.currentTimeMillis();
......
......@@ -70,7 +70,7 @@ rxjavajar 是根据 Apache 软件许可证 2.0 版获得许可的,可以在中
为了使用它,在您的`pom.xml`文件中包括这个 maven 依赖项:
```
```java
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.packt.java9</groupId>
......@@ -105,7 +105,7 @@ rxjavajar 是根据 Apache 软件许可证 2.0 版获得许可的,可以在中
我们将在[第 9 章](9.html)*Java 最佳实践*中详细讨论 JShell,现在让我们从 RxJava 的角度来看一下。在 JShell 中安装 RxJava 框架是通过将 classpath 设置为 RxJava 和 reactive streams JAR 文件来完成的。请注意,Linux 上使用冒号,Windows 上使用分号作为文件路径分隔符:
```
```java
"c:Program FilesJavajdk-9binjshell" --class-path D:Kitsrxjavarxjava-2.1.3.jar;D:Kitsrxjavareactive-streams-1.0.1.jar
```
......@@ -533,7 +533,7 @@ rxjava2.0 提供了更多来自`io.reactivex.schedulers.Schedulers`工厂的调
服务器端代码很简单,我们只配置了一个 REST 控制器,将传感器数据输出为 JSON,如下代码所示:
```
```java
@RestController
publicclass SensorController
{
......@@ -555,7 +555,7 @@ publicclass SensorController
传感器数据是在`SensorData`构造函数中随机生成的(注意 Lombock 库的使用,以摆脱 setter/getter 代码):
```
```java
@Data
publicclass SensorData
{
......@@ -578,7 +578,7 @@ publicclass SensorData
客户端代码使用 rxapache http 库:
```
```java
publicclass Main
{
@JsonIgnoreProperties(ignoreUnknown = true)
......@@ -613,7 +613,7 @@ publicclass Main
`SensorTemperature`是我们的客户资料。它是服务器可以提供的内容的快照。其余信息将被 Jackson data binder 忽略:
```
```java
publicstaticvoid main(String[] args) throws Exception
{
final RequestConfig requestConfig = RequestConfig.custom()
......@@ -629,7 +629,7 @@ publicstaticvoid main(String[] args) throws Exception
在前面的代码中,我们通过设置 TCP/IP 超时和允许的连接数来设置并启动 HTTP 客户端:
```
```java
Observable.range(1, 5).map(x ->
Try.withCatch(() -> new URI("http", null, "127.0.0.1", 8080 + x, "/sensor", null, null), URISyntaxException.class).orElse(null))
.flatMap(address -> ObservableHttp.createRequest(HttpAsyncMethods.createGet(address), httpClient)
......@@ -656,7 +656,7 @@ System.out.println(x.toString());
由于客户端永远旋转,部分输出如下:
```
```java
NuclearCell2 temperature=83.92902289170053
Temperature warning for NuclearCell1
Temperature warning for NuclearCell3
......
......@@ -27,7 +27,7 @@
我们将在这里创建一个雇员服务,它将处理`GET``POST`请求:
```
```java
/**
*
* This class is responsible for handling Employee Entity
......@@ -95,7 +95,7 @@ public class EmployeeWebService extends HttpServlet
下面是一个基于 Spring 的快速示例;正如您将看到的,我们可以避免很多样板代码:
```
```java
@RestController
@RequestMapping("/employees")
/**
......@@ -158,7 +158,7 @@ publicclass EmployeeWebService
当您使用 Spring 框架时,您需要告诉它您的服务器。因此,在你的`web.xml`中,添加以下内容:
```
```java
<servlet>
<servlet-name>springapp</servlet-name>
<servlet-class>org.springframework.web.servlet.
......@@ -184,7 +184,7 @@ publicclass EmployeeWebService
下面是一个基于类的配置示例:
```
```java
package com.employee.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
......@@ -201,7 +201,7 @@ public class EmployeeConfig
要运行前面的代码,我们需要为 spring 和其他依赖项包含某些 JAR 文件。可以用不同的方式管理这些依赖关系;例如,人们可能更喜欢将 jar 添加到存储库,或者使用 Maven、Gradle 等等。同样,对这些工具的讨论超出了本书的范围。以下是可以添加到 Maven 中的依赖项:
```
```java
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
......@@ -234,7 +234,7 @@ public class EmployeeConfig
以下代码显示了使用同步类型的方法调用时代码的外观:
```
```java
/**
* This method generates Employee data report and emails it to admin. This also
* returns number of employees in the system currently.
......@@ -262,7 +262,7 @@ public List<Employee> EmployeeReport() throws ServletException, IOException
假设获取数据需要一秒钟,生成报告需要四秒钟,通过电子邮件发送报告需要两秒钟。我们正在让用户等待 7 秒钟以获取他/她的数据。我们可以使报告异步化,以加快通信速度:
```
```java
/**
* This method generates Employee data report and emails it to admin. This also
* returns number of employees in the system currently.
......@@ -300,7 +300,7 @@ public List<Employee> EmployeeReport() throws ServletException, IOException
在本章中,让我们以一个非常简单的示例来了解缓存如何帮助我们提高性能。让我们看一个简单的 Web 服务,它为员工返回数据:
```
```java
/**
* This method fetches a particular employee data.
* @param id
......@@ -324,7 +324,7 @@ public Employee EmployeeDataService(@PathVariable("id") String id) throws Servle
Java 中有许多缓存实现。在本例中,我们创建一个非常简单的缓存机制:
```
```java
/**
* A simple cache class holding data for Employees
*
......@@ -355,7 +355,7 @@ class EmployeeCache
现在让我们更新我们的方法以利用缓存:
```
```java
/**
* This method fetches a particular employee data.
* @param id
......@@ -450,7 +450,7 @@ fail-fast 实现的一个例子是,如果您的服务依赖于另一个服务
为了进一步说明这一点,假设我们有一个名为`updateEmployeeSalaryAndTax`的服务。此服务获取基本工资并使用它计算总工资,包括可变和固定部分,最后计算税金:
```
```java
public void updateEmployeeSalaryAndTax(String employeeId, float baseSalary)
{
/*
......@@ -500,7 +500,7 @@ public void updateEmployeeSalaryAndTax(String employeeId, float baseSalary)
我们先来看看如何创建 JWT 令牌:
```
```java
/**
* This method takes a user object and returns a token.
* @param user
......@@ -528,7 +528,7 @@ public String createAccessJwtToken(User user, String secret)
类似地,我们将编写一个方法来获取令牌并从令牌中获取详细信息:
```
```java
/**
* This method takes a token and returns User Object.
* @param token
......
......@@ -57,7 +57,7 @@
下面是一个简单的 JavaScript 函数,用于获取员工的数据并将其显示在 UI 上:
```
```java
function getEmployeeData()
{
var xhttp = new XMLHttpRequest();
......@@ -77,7 +77,7 @@ function getEmployeeData()
接下来,我们转到 web 服务或控制器层。这一层的职责是确保请求以正确的格式来自正确的源。Java 中有很多可用的框架,比如 springsecurity 和 javawebtoken,它们帮助我们实现每个请求的授权和身份验证。另外,我们可以为此创建拦截器。为了简化本章,我们将重点介绍核心功能,即从下一层获取数据并将其返回给调用函数。请看下面的代码:
```
```java
/**
* This method returns List of all the employees in the system.
*
......@@ -100,7 +100,7 @@ public List<Employee> EmployeeListService() throws ServletException, IOException
类似地,我们有一个服务层:
```
```java
/**
* This methods returns list of Employees
* @return EmployeeList
......@@ -119,7 +119,7 @@ public List<Employee> getEmployeeList()
让我们转到最后一层,数据访问层。在我们的示例中,我们的 DAL 负责获取数据并返回到调用层。请看下面的代码:
```
```java
/**
* This methods fetches employee list and returns to the caller.
* @return EmployeeList
......@@ -187,7 +187,7 @@ public List<Employee> getEmployeeList()
为了进一步澄清问题,让我们看一个示例实现。首先,我们将在`web.xml`中添加以下内容:
```
```java
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.
......@@ -211,7 +211,7 @@ public List<Employee> getEmployeeList()
我们已经告诉我们的`web.xml`,所有具有`/mvc/`模式的请求都应该重定向到我们的前端控制器,即 Spring MVC 的`DispatcherServlet`。我们还提到了配置类文件的位置。这是我们的配置文件:
```
```java
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.employee.*")
......@@ -240,7 +240,7 @@ public class EmployeeConfig
下面是一个示例控制器类:
```
```java
@Controller
@RequestMapping("/employees")
/**
......@@ -273,7 +273,7 @@ public class EmployeeController
控制器被传递给视图,在本例中是员工.jsp:
```
```java
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
......@@ -366,7 +366,7 @@ SOAP 数据包是基于 XML 的,需要采用非常特定的格式。以下是
这就是 SOAP 数据包的外观:
```
```java
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"
......@@ -387,7 +387,7 @@ REST 没有那么多规则和格式。REST 服务可以通过 HTTP 支持`GET`
`POST`请求的示例 JSON REST 负载如下所示:
```
```java
{
"employeeId":"1",
"employeeName":"Dave",
......@@ -506,7 +506,7 @@ Micorservices 将面向服务的体系结构提升到了一个新的层次。SOA
让我们用一个示例问候语函数来创建我们的类:
```
```java
/**
* Class to implement simple hello world example
*
......@@ -577,7 +577,7 @@ public class LambdaMethodHandler implements RequestStreamHandler
最后,单击 Test 按钮将显示如下响应:
```
```java
*{*
*"isBase64Encoded": false,*
*"headers": {},*
......@@ -596,7 +596,7 @@ public class LambdaMethodHandler implements RequestStreamHandler
添加配置后,系统将为您提供一个 API 链接,点击该链接后,将打印所需的 JSON:
```
```java
*{"message":"Hello Guest"}*
```
......
......@@ -42,7 +42,7 @@ Java8 是 Java 历史上另一个重要的里程碑版本。除了许多其他
对于 Lambda 表达式,Java 首次遇到函数式编程。lambda 帮助我们实现功能接口,这些接口只有一个未实现的方法。与以前的版本不同,我们必须创建类或匿名类,现在可以创建 Lambda 函数来实现函数接口。一个典型的例子是可以运行来实现多线程。请看下面的代码:
```
```java
Runnable myrunnable = new Runnable()
{
@Override
......@@ -78,7 +78,7 @@ Java9 带来的最重要和最大的变化是 Jigsaw 项目或 Java 平台模块
首先,让我们看看 Java9 是如何将整个应用程序划分为模块的。您只需运行以下代码:
```
```java
java --list-modules
```
......@@ -92,7 +92,7 @@ java --list-modules
让我们在`provider/com.example/com/example/calc`中创建类:
```
```java
package com.example.calc;
/**
* This class implements calculating functions on integers.
......@@ -118,7 +118,7 @@ public class Calculator
现在我们创建一个模块-`provider/com.example`中的`info.java`
```
```java
module com.example
{
requires java.base;
......@@ -130,19 +130,19 @@ module com.example
现在编译类:
```
```java
javac -d output/classes provider/com.example/module-info.java provider/com.example/com/example/calc/Calculator.java
```
最后,创建 JAR:
```
```java
jar cvf output/lib/example.jar -C output/classes/
```
所以,我们有一个模块,可以提供加法和减法功能。我们来看看如何在`user/com.example.user/com/example/user`中创建一个用户类来使用这个模块:
```
```java
package com.example.user;
import com.example.calc.*;
/**
......@@ -160,7 +160,7 @@ public class User
同样,我们需要在`user/com.example.user`中创建模块-`info.java`
```
```java
module com.example.user
{
requires com.example;
......@@ -169,43 +169,43 @@ module com.example.user
让我们把这些方法编译成`output/userclasses`
```
```java
javac --module-path output/lib -d output/userclasses user/com.example.user/module-info.java user/com.example.user/com/example/user/User.java
```
创建`user.jar`,如下图:
```
```java
jar cvf output/lib/user.jar -C output/userclasses/
```
最后,运行类:
```
```java
java --module-path output/lib -m com.example.user/com.example.user.User
```
前面的代码解释了模块如何在 Java9 中工作。在继续下一个主题之前,让我们先看看 jlink,它为 Java 模块化增加了功能:
```
```java
jlink --module-path output/lib --add-modules com.example,com.example.user --output calculaterjre
```
请注意,您需要将`java.base.mod`添加到`/output/lib`,因为我们的`com.example`依赖于`java.base`模块。创建自定义 JRE 后,可以按以下方式运行它:
```
```java
./calculaterjre/bin/java -m com.example.user/com.example.user.User
```
你可以看到,我们能够创建自己的小 JRE。为了了解我们的小可执行文件有多紧凑和轻量级,让我们再次运行`--list-modules`
```
```java
calculaterjre/bin/java --list-modules w
```
这将返回以下内容:
```
```java
com.example
com.example.user
java.base@9.0.4
......@@ -223,7 +223,7 @@ Jshell 是开始使用 Java 的一种简单方法。您可以编写代码片段
只需键入`jshell`,它将带您进入 jshell 提示符,并显示一条欢迎消息:
```
```java
$ jshell
| Welcome to JShell -- Version 9.0.4
| For an introduction type: /help intro
......@@ -232,14 +232,14 @@ jshell>
让我们尝试几个简单的命令开始:
```
```java
jshell> System.out.println("Hello World")
Hello World
```
一个简单的`Hello World`。无需编写、编译或运行类:
```
```java
jshell> 1+2
$1 ==> 3
jshell> $1
......@@ -248,7 +248,7 @@ $1 ==> 3
当我们在 shell 中输入`1+2`时,我们在一个变量中得到结果:`$1`。请注意,我们可以在以后的命令中使用此变量:
```
```java
jshell> int num1=10
num1 ==> 1
jshell> int num2=20
......@@ -261,7 +261,7 @@ num3 ==> 30
假设我想尝试一段代码,看看它在实际应用程序中是如何工作的。我可以用贝壳做。假设我想编写一个方法并进行试验,以评估它是否返回了预期的结果,以及在某些情况下是否会失败。我可以在 shell 中完成以下操作:
```
```java
jshell> public int sum(int a, int b){
...> return a+b;
...> }
......@@ -281,7 +281,7 @@ jshell> sum("str1",6)
例如,假设我有一个`String str`,我想知道所有可用于此的方法。我只需要写下`str`,然后按*键*
```
```java
jshell> String str = "hello"
str ==> "hello"
jshell> str.
......@@ -293,7 +293,7 @@ jshell> str.
jshell 还提供了其他帮助命令。第一个你可能想用的是`/help`给你所有的命令。另一个有用的命令是`/import`检查所有已经导入的包:
```
```java
jshell> /import
|
import java.io.*
......@@ -321,7 +321,7 @@ jshell> /import
最后,`/exit`将让您关闭外壳:
```
```java
jshell> /exit
| Goodbye
```
......@@ -332,7 +332,7 @@ Java8 允许我们向接口添加默认方法和静态方法,在接口中只
下面的代码显示了 Java 9 中接口的完全有效的实现,它有一个默认方法使用的 helper 私有方法:
```
```java
package com.example;
/**
* An Interface to showcase that private methods are allowed
......@@ -376,7 +376,7 @@ Java8 为我们带来了流的奇妙特性,它帮助我们非常轻松高效
下面的代码展示了返回所有数字的情况,除非满足数字小于 20 的条件。条件满足一次后的所有数据被忽略:
```
```java
jshell> List<Integer> numList = Arrays.asList(10, 13, 14, 19, 22, 19, 12, 13)
numList ==> [10, 13, 14, 19, 22, 19, 12, 13]
jshell> numList.stream().takeWhile(num -> num < 20).forEach(System.out::println)
......@@ -384,7 +384,7 @@ jshell> numList.stream().takeWhile(num -> num < 20).forEach(System.out::println)
输出如下:
```
```java
10
13
14
......@@ -395,7 +395,7 @@ jshell> numList.stream().takeWhile(num -> num < 20).forEach(System.out::println)
让我们以 takewhile 为例来说明问题:
```
```java
jshell> List<Integer> numList = Arrays.asList(10, 13, 14, 19, 22, 19, 12, 13)
numList ==> [10, 13, 14, 19, 22, 19, 12, 13]
jshell> numList.stream().dropWhile(num -> num < 20).forEach(System.out::println)
......@@ -403,7 +403,7 @@ jshell> numList.stream().dropWhile(num -> num < 20).forEach(System.out::println)
输出如下:
```
```java
22
19
12
......@@ -414,13 +414,13 @@ jshell> numList.stream().dropWhile(num -> num < 20).forEach(System.out::println)
下面的代码显示了循环条件的替换,该循环条件将变量初始化为 0,递增 2,并打印到数字小于 10 为止:
```
```java
jshell> IntStream.iterate(0, num -> num<10, num -> num+2).forEach(System.out::println)
```
输出如下:
```
```java
0
2
4
......@@ -432,7 +432,7 @@ jshell> IntStream.iterate(0, num -> num<10, num -> num+2).forEach(System.out::pr
Java9 为我们提供了创建不可变集合的工厂方法。例如,要创建一个不可变列表,我们使用列表:
```
```java
jshell> List immutableList = List.of("This", "is", "a", "List")
immutableList ==> [This, is, a, List]
jshell> immutableList.add("something")
......@@ -448,7 +448,7 @@ jshell> immutableList.add("something")
类似地,我们有`Set.of``Map.of``Map.ofEntries`。我们来看看用法:
```
```java
jshell> Set immutableSet = Set.of(1,2,3,4,5);
immutableSet ==> [1, 5, 4, 3, 2]
jshell> Map immutableMap = Map.of(1,"Val1",2,"Val2",3,"Val3")
......@@ -463,7 +463,7 @@ immutableMap ==> {2=Val2, 1=Val1}
* **不匹配**:尝试匹配两个数组,并返回数组不匹配的第一个元素的索引。如果两个数组相同,则返回`-1`
```
```java
jshell> int[] arr1={1,2,3,4}
arr1 ==> int[4] { 1, 2, 3, 4 }
jshell> Arrays.mismatch(arr1, new int[]{1,2})
......@@ -476,7 +476,7 @@ $15 ==> -1
* **比较**:按字典顺序比较两个数组。还可以指定开始索引和结束索引,这是一个可选参数:
```
```java
jshell> int[] arr1={1,2,3,4}
arr1 ==> int[4] { 1, 2, 3, 4 }
jshell> int[] arr2={1,2,5,6}
......@@ -493,7 +493,7 @@ $20 ==> 0
* **等于**:顾名思义,Equals 方法检查两个数组是否相等。同样,您可以提供开始索引和结束索引:
```
```java
jshell> int[] arr1={1,2,3,4}
arr1 ==> int[4] { 1, 2, 3, 4 }
jshell> int[] arr2={1,2,5,6}
......@@ -510,7 +510,7 @@ Java8 给了我们`java.util.Optional`类来处理空值和空指针异常。Jav
* `ifPresentOrElse`:如果存在`Optional`值,则方法`void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)`执行给定动作;否则执行`emptyAction`。我们来看几个例子:
```
```java
//Example 1
jshell> Optional<String> opt1= Optional.ofNullable("Val")
opt1 ==> Optional[Val]
......@@ -531,7 +531,7 @@ not found
我们来看几个例子:
```
```java
//Example 1
jshell> Optional<String> opt1 = Optional.ofNullable("Val")
opt1 ==> Optional[Val]
......@@ -553,7 +553,7 @@ $42 ==> Optional[AnotherVal]
* **流**:流在 Java8 之后开始流行,Java9 为我们提供了一种将可选对象转换为流的方法。我们来看几个例子:
```
```java
//Example 1
jshell> Optional<List> optList = Optional.of(Arrays.asList(1,2,3,4))
optList ==> Optional[[1, 2, 3, 4]]
......@@ -568,19 +568,19 @@ Java9 带来了一个新的光滑的 HTTP 客户端 API,支持 HTTP/2。让我
要使用`httpclient`,我们需要用`jdk.incubator.httpclient`模块启动 jshell。以下命令告诉 jshell 添加所需的模块:
```
```java
jshell -v --add-modules jdk.incubator.httpclient
```
现在让我们导入 API:
```
```java
jshell> import jdk.incubator.http.*;
```
使用以下代码创建一个`HttpClient`对象:
```
```java
jshell> HttpClient httpClient = HttpClient.newHttpClient();
httpClient ==> jdk.incubator.http.HttpClientImpl@6385cb26
| created variable httpClient : HttpClient
......@@ -588,7 +588,7 @@ httpClient ==> jdk.incubator.http.HttpClientImpl@6385cb26
让我们为 URL[创建一个请求对象 https://www.packtpub.com/](https://www.packtpub.com/)
```
```java
jshell> HttpRequest httpRequest = HttpRequest.newBuilder().uri(new URI("https://www.packtpub.com/")).GET().build();
httpRequest ==> https://www.packtpub.com/ GET
| created variable httpRequest : HttpRequest
......@@ -596,7 +596,7 @@ httpRequest ==> https://www.packtpub.com/ GET
最后,调用 URL。结果将存储在`HttpResponse`对象中:
```
```java
jshell> HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandler.asString());
httpResponse ==> jdk.incubator.http.HttpResponseImpl@70325e14
| created variable httpResponse : HttpResponse<String>
......@@ -604,7 +604,7 @@ httpResponse ==> jdk.incubator.http.HttpResponseImpl@70325e14
我们可以检查响应状态码,甚至打印正文:
```
```java
jshell> System.out.println(httpResponse.statusCode());
200
jshell> System.out.println(httpResponse.body());
......@@ -625,7 +625,7 @@ jshell> System.out.println(httpResponse.body());
让我们看一个小例子来理解我们的意思。以下是在 Java 9 之前编写的代码:
```
```java
jshell> void beforeJava9() throws IOException{
...> BufferedReader reader1 = new BufferedReader(new FileReader("/Users/kamalmeetsingh/test.txt"));
...> try (BufferedReader reader2 = reader1) {
......@@ -637,7 +637,7 @@ jshell> void beforeJava9() throws IOException{
Java 9 之后的代码如下:
```
```java
jshell> void afterJava9() throws IOException{
...> BufferedReader reader1 = new BufferedReader(new FileReader("/Users/kamalmeetsingh/test.txt"));
...> try (reader1) {
......@@ -661,7 +661,7 @@ Java10 是 Java 的最新版本。与以前的版本一样,这也为语言添
举个例子:
```
```java
public static void main(String s[])
{
var num = 10;
......@@ -679,7 +679,7 @@ public static void main(String s[])
不能将类作用域变量声明为`var`。例如,以下代码将显示编译器错误:
```
```java
public class VarExample {
// not allowed
// var classnum=10;
......@@ -688,19 +688,19 @@ public class VarExample {
即使在局部范围内,只有当编译器可以从表达式的右侧推断变量的类型时,才可以使用 var。例如,以下情况很好:
```
```java
int[] arr = {1,2,3};
```
但是,这并不好:
```
```java
var arr = {1,2,3};
```
但是,您可以始终使用以下选项:
```
```java
var arr = new int[]{1,2,3};
```
......@@ -708,7 +708,7 @@ var arr = new int[]{1,2,3};
不允许出现以下情况:
```
```java
public var sum(int num1, int num2)
{
return num1+num2;
......@@ -717,7 +717,7 @@ public var sum(int num1, int num2)
这也不允许:
```
```java
public int sum(var num1, var num2)
{
return num1+num2;
......@@ -726,13 +726,13 @@ public int sum(var num1, var num2)
尽管可以使用 var 来声明变量,但还是需要注意一点。您需要注意如何声明变量以保持代码的可读性。例如,您可能会在代码中遇到以下行:
```
```java
var sample = sample();
```
你能看懂这个变化多端的样品吗?是字符串还是整数?您可能会认为,我们可以在命名变量(如 strSample 或 intSample)时提供适当的命名约定。但是如果你的类型有点复杂呢?看看这个:
```
```java
public static HashMap<Integer, HashMap<String, String>> sample()
{
return new HashMap<Integer, HashMap<String, String>>();
......@@ -743,7 +743,7 @@ public static HashMap<Integer, HashMap<String, String>> sample()
在声明集合时需要小心的另一个领域是`ArrayLists`。例如,这在 Java 中是合法的:
```
```java
var list = new ArrayList<>();
list.add(1);
list.add("str");
......@@ -759,7 +759,7 @@ list.add("str");
让我们仔细看看,让事情更清楚:
```
```java
public static void main(String args[]) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
......
......@@ -57,7 +57,7 @@ JDK 在版本 8 和版本 12 之间的超快发展增加了现代 Java 的学习
代码块设置如下:
```
```java
public Map<Character, Integer> countDuplicateCharacters(String str) {
Map<Character, Integer> result = new HashMap<>();
......@@ -75,7 +75,7 @@ public Map<Character, Integer> countDuplicateCharacters(String str) {
当我们希望提请您注意代码块的特定部分时,相关行或项以粗体显示:
```
```java
for (int i = 0; i < str.length(); i++) {
int cp = str.codePointAt(i);
String ch = String.valueOf(Character.toChars(cp));
......@@ -87,7 +87,7 @@ for (int i = 0; i < str.length(); i++) {
任何命令行输入或输出的编写方式如下:
```
```java
$ mkdir css
$ cd css
```
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -74,7 +74,7 @@
代码块设置如下:
```
```java
private boolean isNotUnique(Color[] guess) {
final var alreadyPresent = new HashSet<Color>();
for (final var color : guess) {
......@@ -89,7 +89,7 @@
当我们希望提请您注意代码块的特定部分时,相关行或项以粗体显示:
```
```java
@Override
public boolean equals(Object o) {
if (this == o) return true;
......@@ -103,7 +103,7 @@
任何命令行输入或输出的编写方式如下:
```
```java
Benchmark (nrThreads) (queueSize) Score Error
playParallel 1 -1 15,636 ± 1,905
playParallel 1 1 15,316 ± 1,237
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -100,7 +100,7 @@
代码块设置如下:
```
```java
void someMethod(String s){
try {
method(s);
......@@ -114,7 +114,7 @@ void someMethod(String s){
当我们希望提请您注意代码块的特定部分时,相关行或项以粗体显示:
```
```java
class TheParentClass {
private int prop;
public TheParentClass(int prop){
......@@ -126,7 +126,7 @@ class TheParentClass {
任何命令行输入或输出的编写方式如下:
```
```java
--module-path /path/JavaFX/lib \
:-add-modules=javafx.controls,javafx.fxml
```
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -83,7 +83,7 @@ Java11 及其新特性增加了语言的丰富性,这是构建健壮软件应
代码块设置如下:
```
```java
try ( Scanner xmlScanner = new Scanner(new File(xmlFile)); {
while (xmlScanner.hasNext()) {
// read the xml document and perform needed operations
......@@ -91,7 +91,7 @@ try ( Scanner xmlScanner = new Scanner(new File(xmlFile)); {
当我们希望提请您注意代码块的特定部分时,相关行或项以粗体显示:
```
```java
public default void fastWalk() {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter desired pacing: ");
......@@ -99,7 +99,7 @@ public default void fastWalk() {
任何命令行输入或输出的编写方式如下:
```
```java
$ java --version
```
......
......@@ -85,7 +85,7 @@ Java 模块系统的其他好处包括增强的安全性和性能。通过将 JD
在 jdk9 中启动交互式 shell 非常简单,只需运行以下命令(假设 jdk9 安装的`bin`目录位于当前路径中):
```
```java
jshell
```
......@@ -138,7 +138,7 @@ Java 10 于 2018 年 3 月发布,除了之前介绍的基于时间的版本控
从 Java10 开始,声明局部变量已经简化。开发人员不再需要包含本地变量类型的清单声明。这是使用新的`var`标识符完成的,如本示例所示:
```
```java
var myList = new ArrayList<String>();
```
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -44,7 +44,7 @@ JShell 的引入是**JDK 增强建议**(**JEP**)222 的结果。以下是本
**JShell**是位于`/bin`文件夹中的命令行工具。此工具的语法如下:
```
```java
jshell <options> <load files>
```
......@@ -252,7 +252,7 @@ JShell 会记住您输入的代码段和命令。它维护此历史记录,以
默认情况下,`DEFAULT`启动脚本由 JShell 使用。如果你想使用不同的启动脚本,你只需要使用`/set start <script>`命令。举个例子:
```
```java
/set start MyStartupScript.jsh
```
......@@ -285,7 +285,7 @@ JShell 的极限是什么?有这么多你可以做这个工具,你几乎只
让我们看看一个高级代码库,它可以用来从 JShell 脚本编译和运行 Java 程序:
```
```java
import java.util.concurrent.*
import java.util.concurrent.*
import java.util.stream.*
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册