勘误
本书的勘误将第一时间在这个页面进行同步。并按照章节和页码的升序进行排列。本书原著的勘误也会进行第一时间的合并, 在本书中文版出版时,我们已经合并了原著到2018年三月份的勘误。外版勘误地址
勘误的模板为
### 章节
#### 版次
#### 页码
#### 原文
#### 修正
#### 说明
--- 分隔符
全书代码清单更新
版次
第一次印刷
页码
所有涉及到case class
的代码清单
原文
case class
修正
final case class
说明
case class
如果不带 final
标识符,在 Java 中依然是可以继承的,造成非常不好的体验。通常来说,对于需要和 Java 进行交互的库来说,在编写时 case class
需要定义为 final case class
从而限定他们在 Java
中的可继承性。而对于 case object
来说,因为天然等于加了final
,所以不需要了。
—-
译者序1
第一次印刷
页码
VI
原文
欧宁猫
修正
欧林猫
说明
弄错了 OlingCat大小姐的中文网名
—-
第一章
第一次印刷
页码
9
原文
而且不如就近保存有答案可靠
修正
而且不如在就近就保存有答案可靠
说明
这里微调语序,添加译者注:
这里的含义有多重,比如应用相应的缓存,以及就近建设数据中心,一般来说,大型的互联网服务提供商一般都会选择多地多中心的方式来架设并提供他们的服务。
第二章
第一次印刷
页码
15
原文
public Images cache;
public Images database;
修正
private Images cache;
private Images database;
说明
这里暴露了ImageServiceController
的内部成员,需要将可见性设置为private
.
第一次印刷
页码
19
原文
ReplyA a = computeA();
ReplyB b = computeB();
ReplyC c = computeC();
Result r = aggregate(a, b, c);
修正
final ReplyA a = computeA();
final ReplyB b = computeB();
final ReplyC c = computeC();
final Result r = aggregate(a, b, c);
说明
在反应式编程中,我们应该尽可能地利用不可变,类似于在 Scala 中,我们需要尽可能地使用 val
而不是 var
,并且保持和 2.2.2 小节的 Scala 代码清单对齐(其中使用的是val
)。
第一次印刷
页码
20
原文
Future<ReplyA> a = taskA();
Future<ReplyB> b = taskB();
Future<ReplyC> c = taskC();
Result r = aggregate(a.get(), b.get(), c.get());
修正
final Future<ReplyA> a = taskA();
final Future<ReplyB> b = taskB();
final Future<ReplyC> c = taskC();
final Result r = aggregate(a.get(), b.get(), c.get());
说明
在反应式编程中,我们应该尽可能地利用不可变,类似于在 Scala 中,我们需要尽可能地使用 val
而不是 var
,并且保持和 2.2.2 小节的 Scala 代码清单对齐(其中使用的是val
)。
第一次印刷
页码
23
原文
为了充分利用….,也要运行成百上千的线程。
修正
为了充分利用(榨干)CPU可被利用到的性能,意味着,我们就算在最普通的硬件上也要运行成百上千的线程。 //TODO 继续微调
说明
这里的断句原来有点问题。
第一次印刷
页码
23
原文
CompletionStage<Response> future =
ask(actorRef, request, timeout).thenApply(Response.class::cast);
future.thenAccept(AskActorWithJava8::processIt);
修正
final CompletionStage<Response> future =
ask(actorRef, request, timeout).thenApply(Response.class::cast);
future.thenAccept(AskActorWithJava8::processIt);
说明
在反应式编程中,我们应该尽可能地利用不可变,类似于在 Scala 中,我们需要尽可能地使用 val
而不是 var
。
第一次印刷
页码
27
原文
成为昂贵的门挡。
修正
这里需要添加一个译者注: 这里的门挡
即门碰
,作者这里指的是硬盘坏了,废物利用用来挡门。可以理解为使用不再感兴趣的书本来垫显示器。
说明
在反应式编程中,我们应该尽可能地利用不可变,类似于在 Scala 中,我们需要尽可能地使用 val
而不是 var
。
第一次印刷
页码
32
原文
传统的数据存储是关系型数据库,它提供了非常高水平的一致性保证。数据库供应商的客户已习惯于这种操作模式——不仅是因为要提升数据库的效率,而且还要保证提供ACID事务语义的需求;已经为此付出大量努力,做了深入研究。为此,分布式系统目前都聚焦在提供了强一致性的关键组件上。
修正
传统的数据存储是有着非常高水平的强一致性保证的关系型数据库。数据库厂商们在过去投入了大量努力和研究来提升产品效率,与此同时,也坚持着保证ACID的事务性语义,而他们的客户也习惯了这种产品运营模式。为此,目前不少分布式系统也集中精力在其关键组件上提供某种程度的强一致性。
说明
这里原文的倒装比较严重,中间夹了一句,我们重新调整下翻译的结构使得原文的表意更加突出。
第一次印刷
页码
33
原文
那么这两个事件的观察顺序…
修正
那么这两个事件受观察的顺序…
说明
这里讲的是狭义相对论。
第三章
第一次印刷
页码
47
原文
>>> def addOne(x):
... return x+1
修正
>>> def addOne(x):
... return x+1
说明
第二行应该有个缩进,tab
。
第一次印刷
页码
48
原文
STM
修正
应该是:STW
说明
翻译的时候想着软件事务内存
了,Typo。
第一次印刷
页码
48
原文
吞吐量从而提升为将近原来的3倍
修正
从而将吞吐量提升为将近原来的3倍
说明
语序调整
第一次印刷
页码
49
原文
我们都将会评估它是如何…的。
修正
删除掉最后的的
字。
我们都将会评估它是….的原则。
说明
第一次印刷
页码
49
原文
所以它们的
在容错性方面比较欠缺。
修正
删除掉中间的的
字。
所以它们在容错性方面比较欠缺。
说明
第一次印刷
页码
53
原文
译者注 26 :Java 8 并未内置… ,参见 vavr.io …
修正
Java 8 并未内置类名类似于“Promise”的实现,不过在 Netty 等流行的异步网络编程库中都有名为“Promise”的定义和实现。—— 译者注
说明
在本书出版的时候,译者使用的是 vavr 的0.9.2
版本,在这个版本中的确有 Promise
的定义和对应的实现,见: io.vavr.concurrent.Promise
,不过在目前的主干和接下来的1.0.0版本中,vavr的作者已经删除对应的实现, 所以这里的描述已经过时。
—
第一次印刷
页码
55
原文
代码清单3-5 supplyAsync
后面少了括号
修正
public class ParallelRetrievalExample {
private final CacheRetriever cacheRetriever;
private final DBRetriever dbRetriever;
ParallelRetrievalExample(CacheRetriever cacheRetriever, DBRetriever dbRetriever) {
this.cacheRetriever = cacheRetriever;
this.dbRetriever = dbRetriever;
}
public Object retrieveCustomer(final long id) {
final CompletableFuture<Object> cacheFuture =
CompletableFuture.supplyAsync(() -> cacheRetriever.getCustomer(id));
final CompletableFuture<Object> dbFuture =
CompletableFuture.supplyAsync(() -> dbRetriever.getCustomer(id));
return CompletableFuture.anyOf(cacheFuture, dbFuture);
}
}
说明
排版过程中引入错误,typo。
第一次印刷
页码
58
原文
译者注 37:在 RXJava 2.x 的版本中….
修正
在 RxJava 2.x 的版本中….
说明
这里的RxJava
的第二个 x
需要小写,属于 typo。
第一次印刷
页码
59
原文
private static final RxJavaExample rxJavaExample = new RxJavaExample();
和
rxJavaExample.observe(strings);
修正
private static final RxJavaExample RX_JAVA_EXAMPLE = new RxJavaExample();
和
RX_JAVA_EXAMPLE.observe(strings);
说明
静态的成员变量,应该推荐使用大写加下划线的形式。
第一次印刷
页码
59
原文
代码清单中 Observable.fromArray(strings).subscribe(s)
少了括号
修正
package chapter03.rxjava;
import io.reactivex.Observable;
public class RxJavaExample {
public void observe(String[] strings) {
Observable.fromArray(strings).subscribe((s) -> System.out.println("Received " + s));
}
}
说明
排版过程中引入错误,typo。
第一次印刷
页码
60
原文
Erlang的开放电信平台……定义了对于Acotr
的…
修正
Acotr 改为 Actor.
说明
排版过程中引入错误,typo。
第四章
第一次印刷
页码
77
原文
Actor模型的实现通常提供…..“至多一次保证”,
修正
Actor模型的实现通常提供…..“至多一次送达”,
说明
保证
应该改为送达
第二次印刷
页码
78
原文
套接口
上有数据可用
修正
套接字
上有数据可用
说明
应与前文翻译保持一致。
第二次印刷
页码
85
原文
当你将指针
悬停在电子邮件的发件人上方时
修正
当你将鼠标指针
悬停在电子邮件的发件人上方时
说明
应与前文翻译保持一致。
第二次印刷
页码
98
原文
用测试存根代码来替换掉层级结构中的同级、子代
以及上级模块。
修正
用测试存根代码来替换掉层级结构中的同级、下级
以及上级模块。
说明
翻译应与上下文保持一致。
第二次印刷
页码
98
原文
可将它们被部署
到
修正
可将它们部署
到
说明
typo
第八章
第一次印刷
页码
111
原文
因为模块之前是完全独立且彼此隔离的。
修正
因为模块在之前是完全独立且彼此隔离的。
说明
原文是:
because the modules previously were completely independent and isolated from each other.
这里用的副词 previously,表示「之前」、「先前」。在模块后就要断句,因此这句话要这么读:
因为模块 | 之前是完全独立且彼此隔离的。
不过确实容易产生误解。经讨论,我们觉得可以加个「在」字,变成:
因为模块**在之前**是完全独立且彼此隔离的。
第二次印刷
页码
112
原文
在Gmail在
例子中,
修正
在Gmail例子中,
说明
typo
第十一章
第一次印刷
页码
108
原文
脚注 3:在领域驱动设计的上下文中,这些将称为聚合根源;…
修正
脚注 3:在领域驱动设计的上下文中,这些被称为聚合根;…
说明
原文是:In the context of domain-driven design, these would be called aggregate roots;
aggregate roots 应该译为「聚合根」,而不是「聚合根源」。另外,这里没也必要使用将来时,直接译作「被称为」即可。
第二次印刷
页码
114
原文
这导致了添加组件结构的新方面;
修正
这导致了添加组件结构的新方面:
说明
typo
第二次印刷
页码
119
原文
空白
们的执行顺序
修正
们的执行顺序
说明
排版错误,行首有多余空白。
第二次印刷
页码
123
原文
都尽快地把它向前
推送给下一站
修正
都尽快地把它向后
推送给下一站
说明
typo
第二次印刷
页码
125
原文
后一种形式,我们将竭力保持推论的技术性,而以前的形式
却允许我们
修正
后一种形式,我们将竭力保持推论的技术性,而前一种形式
却允许我们
说明
应与上一句相呼应。
—
第一次印刷
页码
143
原文
val echo = echoService("keepSLAfuture")
修正
val echo = echoService("keepSLAWithFuture")
说明
typo
第一次印刷
页码
144
原文
val echo = echoService("keepSLAparallel")
和
val controller = system.actorOf(
Props[ParallelSLATester],
"keepSLAparallelController")
修正
val echo = echoService("keepSLAInParallel")
和
val controller = system.actorOf(
Props[ParallelSLATester],
"keepSLAInParallelController")
说明
typo
第一次印刷
页码
147
原文
例如:在Akka中给一个Actor发消息:actor!message。
修正
例如:在Akka中给一个Actor发消息:actor ! message。
说明
注13最后一句(页面底部)。
第一次印刷
页码
149
原文
val controller = system.actorOf(
Props[ParallelSLATester],
"keepSLAparallelController")
修正
val controller = system.actorOf(
Props[ParallelSLATester],
"keepSLAInParallelAndAsyncController")
说明
- typo
- 因为在
ParallelSLATester
中,对应的context.stop(self)
是一个异步动作,所以在快速运行多个测试的时候, 会出现偶发的:akka.actor.InvalidActorNameException
,所以进行改名对当前的用例来说是比较直接安全的一种做法。 感兴趣的读者可以看下下面的错误信息:
[info] - must keep its SLA when used in parallel and handling responses asynchronously *** FAILED ***
[info] akka.actor.InvalidActorNameException: actor name [keepSLAparallelController] is not unique!
[info] at akka.actor.dungeon.ChildrenContainer$NormalChildrenContainer.reserve(ChildrenContainer.scala:129)
[info] at akka.actor.dungeon.Children.reserveChild(Children.scala:134)
[info] at akka.actor.dungeon.Children.reserveChild$(Children.scala:132)
[info] at akka.actor.ActorCell.reserveChild(ActorCell.scala:431)
[info] at akka.actor.dungeon.Children.makeChild(Children.scala:272)
[info] at akka.actor.dungeon.Children.attachChild(Children.scala:48)
[info] at akka.actor.dungeon.Children.attachChild$(Children.scala:47)
[info] at akka.actor.ActorCell.attachChild(ActorCell.scala:431)
[info] at akka.actor.ActorSystemImpl.actorOf(ActorSystem.scala:753)
[info] at chapter11.EchoServiceSpec.$anonfun$new$10(EchoServiceSpec.scala:242)
第一次印刷
页码
162
原文
这可能是非常有用的
修正
这可能非常有用
说明
语气调整,删除是
和的
第一次印刷
页码
162
原文
证明你的应用程序具备回弹性的是一个良好开端
修正
证明你的应用程序具备回弹性是一个良好开端
说明
语气调整,删除的
。
第十二章
第二次印刷
页码
173
原文
只需要通过终止旧运行时间实例的并启动新的运行时实例
修正
只需要通过终止旧的运行时实例并启动新的运行时实例
说明
原译文语句不通顺
第二次印刷
页码
174
原文
到目前为止,你都认为执行的是一个原子组件,
修正
到目前为止,你都认为“执行”是一个原子组件。
说明
执行在这里是名词,所有不应该加的
第十三章
第一次印刷
页码
220
原文
代码清单 13-15:
case SeqResult(_, res, replica, _) if res != right ⇒ replica
修正
case SeqResult(_, result, replica, _) if res != right ⇒ replica
说明
代码清单中的这个部分,因为res
shallow 了外面的 add
方法中的res
参数,所以 实际上比较的类型是不相关的,会造成状态无法收敛到Known
。通过重新命名解决了这个问题。
第十四章
第一次印刷
页码
231
原文
代码清单 14-1:
AmazonEC2 amazonEC2Client = new AmazonEC2Client(credentials);
修正
final AmazonEC2 amazonEC2Client =
AmazonEC2ClientBuilder.standard()
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
说明
切换到新版本客户端的推荐写法,旧版本写法已经废弃。其他包括代码清单中添加了final
关键字。
第一次印刷
页码
235
原文
代码清单 14-5:
public WorkerNode(final InetAddress address, final FiniteDuration checkInterval) {
checkTimer =
getContext()
.system()
.scheduler()
.schedule(
checkInterval,
checkInterval,
self(),
DoHealthCheck.instance,
getContext().dispatcher(),
self());
}
修正
public WorkerNode(final InetAddress address, final Duration checkInterval) {
checkTimer =
getContext()
.getSystem()
.getScheduler()
.schedule(
checkInterval,
checkInterval,
self(),
DoHealthCheck.INSTANCE,
getContext().dispatcher(),
self());
}
说明
切换到新版本 Akka 中更加 Java native 的写法。并且针对静态类成员 DoHealthCheck.instance
应用大写格式。
第一次印刷
页码
235
原文
代码清单 14-5:
private PartialFunction<Object, BoxedUnit> initialized()
修正
private Receive initialized()
说明
切换到新版本 Akka 中更加 Java native 的写法。更加直接地是用 AbstractActor
提供的基础设施。
240
原文
代码清单 14-5:
private PartialFunction<Object, BoxedUnit> initialized()
修正
private Receive initialized()
说明
切换到新版本 Akka 中更加 Java native 的写法。更加直接地是用 AbstractActor
提供的基础设施。
第一次印刷
页码
247
原文
代码清单 14-8:
private static final ScriptEngine engine =
修正
private static final ScriptEngine ENGINE =
说明
对于类的静态成员,切换为使用全大写的格式。其他包含一些final
关键字的增加。