三種很難學到的Java踩坑教訓 - Miloš

banq發表於2021-07-29

學習Java很難。經驗是最好的老師。經驗教你克服錯誤。我從錯誤中吸取了教訓。你可以從我的錯誤中吸取教訓。
這是我透過艱苦的方式學到的東西,而您不必這樣做。

1. Lambdas 可能會給你帶來困難
Lambda通常超過 4 行程式碼。做的比應該做的多。更多的責任——你的工作記憶更難。更多行——多重責任 lambda。
您是否需要更改 lambda 中的變數? 你不能那樣做。 為什麼?如果 lambda 可以訪問呼叫跨界變數,則可能會出現多執行緒問題。您不能從 lambda 內部更改呼叫變數。
lambda 中的快樂路徑效果很好。執行時崩潰後,您會收到以下響應:

at [CLASS].lambda$null$2([CLASS].java:85)
at [CLASS]$$Lambda$64/730559617.accept(Unknown Source)


Lambda 堆疊跟蹤令人痛苦。名稱被混淆、難以跟蹤且難以除錯。
除錯 lambda 的更好方法是什麼? 使用中間結果。

map(elem -> {
 int result = elem.getResult();
 return result;
});


更好的方法是使用高階 IntelliJ 除錯技巧。使用TAB來選擇要除錯的程式碼。將此與中間結果相結合以獲得更好的體驗。
“當我們在包含 lambda 的行處停止時,如果我們按 F7(步入),那麼 IntelliJ 將突出顯示要除錯的程式碼段。我們可以使用 Tab 切換要除錯的塊,一旦我們決定,然後我們再次單擊 F7。”
如何從 lambda 訪問呼叫跨界變數? 您只能訪問 final 或有效的 final 變數。您需要包裝呼叫變數。無論是AtomicType或您自己的型別。您可以從 lambda 更改包裝的變數。
如何解決堆疊跟蹤問題? 使用命名函式。您現在可以找到負責任的程式碼、審查邏輯並更快地解決問題。使用命名函式來減少神秘的堆疊跟蹤。
相同的 lambda 重複? 把它放在一個命名函式中。您將有一個參考點。每個 lambda 都有一個生成的函式,這使得跟蹤變得更加困難。

lambda$yourNamedFunction
lambda$0

命名函式解決了另一個問題。命名函式會劃分大lambdas,建立更小的程式碼塊,並建立可插入的函式。

.map(this::namedFunc1).filter(this::namedFilter1).map(this::namedFunc2)

 

2. 你會遇到列表List問題
您需要使用 Lists。您需要 HashMaps 來獲取類似字典的資料。您需要 TreeMap 角色。您不可能不使用集合。
你如何構建一個列表?你需要什麼清單?你需要一個不可變或可變的列表嗎?答案會影響程式碼的未來。早點選擇正確的清單,否則就會受苦。
Arrays::asList建立“直寫”列表。你不能用這個列表做什麼?您無法更改已建立列表的大小。大小是不可變的。你可以做什麼?設定元素、排序或其他不影響大小的操作。Arrays::asList小心使用,因為它的大小是不可變的,但內容不是。
new ArrayList()建立一個新的“可變”列表。
建立的列表支援哪些操作?這就是要謹慎的原因。
List::of 建立一個“不可變的”集合。大小是不變的,但是內容在某些條件下是不可變的,如果內容是原始值,即 int,則列表是不可變的。看下面的例子。

@Test
public void testListOfBuilders() {
  System.out.println("### TESTING listOF with mutable content ###");

  StringBuilder one = new StringBuilder();
  one.append("a");

  StringBuilder two = new StringBuilder();
  two.append("a");

  List<StringBuilder> asList = List.of(one, two);

  asList.get(0).append("123");

  System.out.println(asList.get(0).toString());
}
輸出:
### TESTING listOF with mutable content ###
a123


您需要建立不可變物件並將它們放入List::of才能真正保證不可變, List::of不保證不變性。

 

3. 註釋讓你慢下來
你使用註解嗎?你瞭解他們嗎?你知道他們做什麼嗎?
自定義Logged註釋 是否適用於每種方法?錯誤的。我已經使用 ourLogged來記錄方法的引數。令我驚訝的是,它不起作用。您盲目地使用自定義註釋。

@Transaction
@Method("GET")
@PathElement("time")
@PathElement("date")
@Autowired
@Secure("ROLE_ADMIN")
public void manage(@Qualifier('time')int time) {
...
}

這段程式碼有什麼不愉快的地方?有很多配置摘要。你會經常遇到這種情況。配置與常規程式碼混合在一起。本身還不錯,但很難看。
註釋是有代價的。讀者為閱讀付出的代價。我們為了更快的開發而交易冗長。
註釋是為了減少樣板程式碼。您不需要為每個端點編寫日誌邏輯。您不需要配置事務,使用@Transactional. 註釋透過提取程式碼來減少樣板。
好的,我們應該回到 XML 嗎?不。我正在使用基於 Spring 的應用程式,並且使用 XML 進行配置是輕而易舉的。我們確實有註釋,但大部分配置都是在XML 中。模式指導配置,學習曲線並不陡峭。註釋很方便。註釋優勢在於方便,XML 優勢在於冗長。
這裡沒有明確的贏家,因為兩者都在發揮作用。直到今天,我仍然使用 XML 和註釋。當您發現重複的樣板檔案時,最好將註釋背後的邏輯移動。例如,日誌記錄是一個很好的註釋候選者。這個故事的寓意是:不要濫用註釋,不要忘記 XML
 

相關文章