java的奇技淫巧--意外行為與特性(譯文)
Java是一種非常成熟的程式語言 - 事實上,它已經走過21年了,如果它是一個人,它可以在美國隨便混!隨著年齡的增長,智慧也在增長,而至少有時候,有些東西會變得很怪異。在本文中,我將介Java語言的一些奇技淫巧的行為和特徵。
在這裡,沒有特別的順序去介紹一系列Java的奇技淫巧,僅供娛樂,或者你向朋友們推介它吧。
Java有goto和const關鍵字
雖然Java沒有goto,但它確實作為保留關鍵字。const也是這樣。這意味著您無法這兩個名稱定義變數:
int goto = 0;
int const = 0;
這樣的定義是非法的,無法正常編譯!
用“_”符號定義數字
Java允許您使用“_”符號定義數字。因此,您可以像這樣編寫數值:
int thousand = 1_000;
double bigValue = 1_000_000.456_555;
long thisIsSilly = 3______4__3;
Double.MIN_VALUE不是許多人所假設的
為了展示Double.MAX_VALUE結果比預期的效果要完美,提供以下這樣的數值:1.7976931348623157E308。您認為Double.MIN_VALUE會為您帶來什麼?4.9E-324!好,執行開始 – 結果這個值大於0!
Double.MIN_VALUE是返回大於0的最小Double值(最小正數)。如果您想要最小的Double值,則需要使用:-Double.MAX_VALUE。他們實際上可以更好地命名這些東西,我想知道這樣的做法引起了多少人為的錯誤!
有趣的整數相等問題
談到這個錯誤......讓我告訴你一些迷惑不解的事情:
Integer ten = Integer.parseInt("10");
System.out.println(ten == Integer.valueOf(10));
//this is true
Integer thousand = Integer.parseInt("1000");
System.out.println(thousand == Integer.valueOf(1000));
//this is false
Integer物件的快取值的大小範圍是在[-128 127]區間。這意味著當我們在此數值範圍內操作時,“==”比較能正常返回結果。但當數值不在此範圍,物件相等的比較是否正常返回結果就很難說了!
想象一下,你可以編寫單元測試,且一切都正常執行,只要你沒有使用足夠大的數字,但這可能會導致嚴重的錯誤,所以為了安全 - 提醒:當你經常使用物件數值比較相等時,請使用“.equals()”,而不是依賴於“==”比較相等,除非你非常肯定這種做法沒有錯誤。
反射可以(大多數情況)做任何事情
這不應該作為一個Java奇技淫巧的內容,但通過反射,你可以重寫final值(大多數時間)並可訪問私有欄位......但不一定經常是這樣。
在我寫How to write horrible Java的文章時,當我重寫final值得時候,我發現了無法與預期結果一致的問題。Java中的常量,當final被內聯時(通指行內函數),即使你的程式碼看起來可以正常執行—沒有數值情況也會改變,這太不可思議了(檢視我的文章瞭解詳情和Stack Overflow答案)。
如果你需要,這是重寫final的數值程式碼例子:
public static void notSoFinal() throws NoSuchFieldException, IllegalAccessException, InterruptedException {
ExampleClass example = new ExampleClass(10);
System.out.println("Final value was: "+ example.finalValue);
Field f = example.getClass().getDeclaredField("finalValue");
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
f.setInt(example, 77);
System.out.println("Final value was: "+ example.finalValue);
}
你知道Java標籤是什麼玩意嗎?
好吧,我們離開上面調皮的話題,回到Java正規上來。你知不知道Java迴圈標籤?看一下這個迴圈語句:
outerLoop:
while (true) {
System.out.println("I'm the outer loop");
while(true){
System.out.println("I am the inner loop");
break outerLoop;
}
}
使用標籤可以讓你在處理巢狀迴圈的時候,繼續或中斷一個特定的迴圈……在不同語言環境下,這個有點類似goto,
現在讓我們編寫一個編譯好了的,形跡可疑的程式碼:
int i = 3;
http://www.e4developer.com
while(i > 0){
System.out.println("http://www.e4developer.com");
i--;
}
可以正常編譯並且正常執行,因為它只是一個附加註釋的標記為http的迴圈。這會讓那些不熟悉標籤的人,使得它變得特別有趣!
列舉類
好吧,你可能知道這一點,但我還是想重複提一下。列舉是具有有限數量例項的特殊類。這意味著列舉可以:
實現介面
具有建構函式
實現不同方法
對於Scott Logic部落格,我寫了一篇名為 Java Enums – how to use them smarter 的文章,我展示了一些其他的使用方法。
For迴圈的靈活性
迴圈的標準,我相信你使用它們的次數,比你記憶中的還要多:
for(int i = 0; i < 100; i++){
//...
}
您知不知道里面所有條件是可選的嗎?你不需要初始化一個變數,你也不需要一個條件停止,你也不需要增加任何東西......如果省略所有內容,你最終會得到一個有趣的無限迴圈語法:
for(;;){
//Infinite loop!
}
Java有初始化程式......以防萬一...
這是一個非常通用的特性,但是我還是依然會遇到一些具有經驗的Java開發人員,他們並不會真正意識到它的存在。在Java中,您可以寫類載入(靜態初始化程式)或建構函式(標準初始化程式)之前執行的程式碼塊。它是這樣的。
標準初始化程式:
int sum = 0;
{
for(int i = 0; i < 1; i++){
sum += 1;
}
}
靜態初始化程式:
static double value = 0;
static {
for(int i = 0; i < 1; i++){
value += 1;
}
}
只需要將這些程式碼塊放在類中,不要放在任何方法或建構函式中。
雙括號初始化集合
關於初始化的話題,我會向你展示Java初始化集合的奇技淫巧:
Map<String, String> map = new HashMap<String, String>() {{
put("it", "really");
put("works", "!");
}};
Set<String> set = new HashSet<String>() {{
add("It");
add("works");
add("with");
add("other");
add("collections");
add("too");
}};
它在Java中被稱為雙括號初始化,我從未見過這樣的寫法,被任何人使用過……難道是因為沒有人知道使用它嗎?
在發表這篇文章之後,很多讀者很快告訴我,這是我們應該避免的一個危險行為!比如應當使用輔助方法List.of()代替。(注意,雙括號初始化會派生匿名類。派生的類this可以指向外部的類。通常這不是什麼大問題,但在某些情況下使用不當會引起悲劇的問題,例如在序列化或垃圾回收時,應當注意這個問題)
Final值的可以放在後面初始化
這是一個小事情,但有些人認為,你在定義它們時時候,必須初始化常量值。實際情況不是這樣,您只需要初始化它們一次就夠了,你可以使用以下有效程式碼核對一下:
final int a;
if(someCondition){
a = 1;
} else {
a = 2;
}
System.out.println(a);
當我們混合初始化程式碼塊和其他建構函式時,這麼做會變得棘手。
泛型擴充套件的橋接
儘管存在可疑的實現(型別擦除),但泛型在Java中還是非常強大。我吃驚的是,我們可以允許定義我們需要的泛型型別。看看這個例子:
public class SomeClass<T extends ClassA & InterfaceB & InterfaceC>
{}
你特別需要注意你定義的T,這特性會對你非常有用!
你還有更多嗎?
我希望你喜歡我分享的Java奇技淫巧。如果你還知道其他的Java特性和行為,並值得分享,請務必在評論或Twitter上告訴我!
原文:https://www.e4developer.com/2018/10/28/java-surprises-unexpected-behaviours-and-features/