天天看點

Java 10 實戰第 1 篇:局部變量類型推斷

現在 Java 9 被遺棄了直接更新到了 Java 10,之前也發過 Java 10 新特性的文章,現在是開始實戰 Java 10 的時候了。

今天要實戰的是 Java 10 中最重要的特性:局部變量類型推斷,大家都知道是 var 關鍵字,但具體怎麼使用,及要注意什麼要點呢?

我們通過幾個例子來講解局部變量類型推斷這個新特性!

什麼是局部變量類型推斷

var javastack = "javastack";
System.out.println(javastack);      

大家看出來了,局部變量類型推斷就是左邊的類型直接使用

var

定義,而不用寫具體的類型,編譯器能根據右邊的表達式自動推斷類型,如上面的

String

var javastack = "javastack";      

就等于:

String javastack = "javastack";      

局部變量類型推斷使用示例

既然叫局部變量類型推斷,以隻能用在局部變量中,下面給出更多使用示例。

1、字面量定義局部變量

private static void testVar() {
    var javastack = "javastack";
    System.out.println(javastack);
}      

2、接收方法傳回值定義局部變量

private static void testMethod() {
    var javastack = getJavastack();
    System.out.println(javastack);
}

public static String getJavastack() {
    return "javastack";
}      

3、循環中定義局部變量

private static void testLoop() {
    for (var i = 0; i < 3; i++) {
        for (var m = 10; m < 15; m++) {
            System.out.println(i + m);
        }
    }
}      

4、泛型結合局部變量

private static void testGeneric() {
    // 表達式1
    List<String> list1 = new ArrayList<>();
    list1.add("javastack");

    // 表達式2
    var list2 = new ArrayList<>();
    list2.add(2018);

    // 表達式3
    var list3 = new ArrayList<String>();
    list3.add("javastack");
}      

表達式1後面 <> 裡面 jdk 1.7+開始是不用帶具體類型的,在接口中指明就行了。

表達式2中如果使用 var 的話,<> 裡面預設會是 Object 的,是以可以添加任意類型。

表達式3中在 <> 強制使用了 String 來指定泛型。

局部變量類型推斷不能用在以下場景

1、類成員變量類型

// 編譯報錯
private var javastack = "Java技術棧";      

2、方法傳回類型

/**
 * 編譯報錯
 * @return
 */
public static var getJavastack(){
    return "Java技術棧";
}      

3、Lambda 表達式

private static void testLambda() {
    Runnable runnable = () -> System.out.println("javastack");

    // 編譯報錯
    // var runnable = () -> System.out.println("javastack");
}      

以上 3 種場景是肯定不能使用

var

的,其他場合有待驗證。

局部變量類型推斷優缺點

優點:簡化代碼

CopyOnWriteArrayList list1 = new CopyOnWriteArrayList();
ConcurrentModificationException cme1 = new ConcurrentModificationException();
DefaultServiceUnavailableRetryStrategy strategy1 = new
        DefaultServiceUnavailableRetryStrategy();

var list2 = new CopyOnWriteArrayList<>();
var cme2 = new ConcurrentModificationException();
var strategy2 = new DefaultServiceUnavailableRetryStrategy();      

從以上代碼可以看出,很長的定義類型會顯得代碼很冗長,使用 var 大大簡化了代碼編寫,同時類型統一顯得代碼很對齊。

缺點:掩蓋類型

var token = new JsonParserDelegate(parser).currentToken();      

看以上代碼,不進去看傳回結果類型,誰知道傳回的類型是什麼?是以這種情況最好别使用 var,而使用具體的抽象類、接口或者執行個體類型。

var關鍵字原理

var其實就是 Java 10 增加的一種文法糖而已,在編譯期間會自動推斷實際類型,其編譯後的位元組碼和實際類型一緻,如以下例子所示。

private static void testByteCode() {
    String javastack1 = "javastack";
    var javastack2 = "javastack";
}• 1
• 2
• 3
• 4      

編譯成位元組碼後:

private static testByteCode()V
L0
LINENUMBER 22 L0
LDC "javastack"
ASTORE 0
L1
LINENUMBER 23 L1
LDC "javastack"
ASTORE 1
L2
LINENUMBER 24 L2
RETURN
L3
LOCALVARIABLE javastack1 Ljava/lang/String; L1 L3 0
LOCALVARIABLE javastack2 Ljava/lang/String; L2 L3 1
MAXSTACK = 1
MAXLOCALS = 2      

可以看出 

javastack1

 和 

javastack2

 都是虛拟機所認識的的本地變量類型:

java.lang.String

,虛拟機并不認識 var, 是以 

var

 并不神奇。