我的上一次 Java programming 經驗已經是將近六年前的事了,JDK 那時才剛從 1.0 版升級至 1.1,後來因為工作內容的關係,C++ 才變成是我最常使用的程式語言。

前一陣子逛書店時瞄到了 Joshua Bloch 的《Effective Java Programming Language Guide》居然有中文版,原文的版本我是聞名已久卻沒空拜讀。我一看是侯捷翻譯的作品,二話不說便掏錢買下這本書,直到最近,我一時興起才把它讀完。

就內容而言,這本書絕對有資格跟《Effective C++》享有一樣的經典地位,不僅 Java programmer 要看,.NET programmer 也應該人手一本,因為其中的許多物件導向編程的道理是同時適用於 Java 與 .NET。中文版裡不通順或是有錯誤的地方倒是比我期待的數目多了一點,不過我想侯捷應該是不介意別人用高標準來檢驗他的作品。

下面是我發現的一些翻譯問題:

原文: Not only can the class of an object returned by a public static factory method be nonpublic, but the class can vary from invocation to invocation depending on the values of the parameters to the static factory.

譯文 p7: public static factory method 傳回的物件不僅可以是個 nonpublic class 物件,而且視 static factory 函式參數的不同,還可以涉及不同的 nonpublic class …

這一句翻得有點繞口,不是讓人一看就明白,我自己試著翻譯為 “public static factory method  返回物件的 class 不僅可以是 nonpublic,而且視函式參數的不同,還可以返回不同的 class …”

原文: In particular, the hash function may, in practice, be confronted with a large collection of instances that differ largely in the regions that you’ve chosen to ignore.

譯文 p40: 更具體地說,實際應用時 hash 函式可能會面臨大量「在你刻意忽略的領域中仍有很大差異」的物件實體。

我想「領域」直接翻成「部份」會比較容易懂。

原文: Note that string names are used only by the toString method; they are not used for equality comparisons, as the equals implementation, which is inherited from Object, performs a reference identity
comparison.

譯文 p106: 注意:字串名稱只由 toString() 使用,並不用於「相等比較」,也就是說並不用於繼承自 Object 的 equals() (該函式執行的是 reference 的比較)。

譯文似乎有點誤導,我認為應該譯為 “字串名稱只由 toString() 使用,並不用於「相等比較」,因為繼承自 Object 的 equals() 執行的正是預期的 reference 比較。”

原文: Second, it is possible to return the same zero-length array from every invocation that returns no items …

譯文 p134: 第二,對於「不傳回任何 array 元素」的呼叫,傳回同一個「長度為 0 的array」是可能的

正確的翻譯為: 對於數次「沒有任何 array 元素可傳回」的呼叫,傳回同一個「長度為 0 的array」是適切的

原文: By convention, the word “this”always refers to the object on which the method is invoked when it is used in the doc comment for an instance method.

譯文 p138: 習慣上當 “this” 出現於一個 instance 函式的 doc comment 時,總是用來表示該函式的呼叫者(某物件)

正確的翻譯為: “習慣上當 this 出現於一個 instance 函式的 doc comment 時,總是用來表示該函式所屬的 instance。”

原文: This could be construed as an IllegalArgumentException (the handSize parameter value is too high) or an IllegalStateException (the deck object contains too few cards for the request). In this case the IllegalArgumentException feels right, but there are no hard-and-fast rules.

譯文 p177: 這種情形可被解釋為 IllegalArgumentException (…) 或被解釋為 IllegalStateException (…),或者使用 IllegalArgumentException 也適當;是的,這其中並沒有嚴格的規定。

我覺得比較容易懂的翻譯為: 這種情形可被解釋為 IllegalArgumentException 或 IllegalStateException。在這個例子,似乎使用 IllegalArgumentException 是比較適當的,但這並不是唯一的標準答案。

原文: It makes it easy for the programmer throwing an exception to capture the failure. In fact, it makes it hard for the programmer not to capture the failure!

譯文 p184: 這種作法使得程式員可輕易「藉由拋出異常來捕獲失敗」。事實上這種手法使得程式員不捕捉失敗都很困難。

我想原文的 capture the failure 指的是「記錄失敗情況下的資訊」,比較正確的翻譯應該是:  “這種作法使得程式員可輕易「藉由拋出異常來記錄失敗情況下的資訊」。換句話說,這種手法也使得程式員不得不記錄失敗情況下的資訊。”

原文: A closely related approach to achieving failure atomicity is to order the computation

譯文 p185: 另一個實現 failure atomocity 的辦法是「對運算排序

排序一般指的是 sort,這句譯成「更動運算的次序」比較符合原義。

原文: The newly created thread might then try to acquire the same lock held by the original thread, which would cause the newly created thread to block.

譯文 p196: 新建執行緒可能獲得原執行緒持有的鎖件,這便造成新建執行緒被阻塞。

正確的翻譯為: “新建執行緒可能嘗試獲得已被原執行緒持有的鎖件,這便造成新建執行緒被阻塞。”

原文: Because locks in the Java programming language are recursive, such calls won’t deadlock as they would if they were made by another thread.

譯文 p199: 由於 Java 編程中的鎖件是遞迴的,如果這些呼叫由其他執行緒產生,並不會造成死結。

正確的翻譯為: 由於 Java 編程中的鎖件是遞迴的,這些呼叫並不像「由其他執行緒產生的呼叫」會產生死結。

原文: A second approach, suitable for classes that are not designed to be extended or reimplemented …

譯文 p200: 第二種辦法適用於那些不是並非為了擴展或重新實作而設計的class

正確的翻譯為: “第二種辦法適用於那些非設計為可擴展或可重新實作的class”。