Java 10新特性:類型推斷

0x01 Java 10簡介

  • 自從有了校內的下載網站,不多上Oracle官網下載JDK了,結果前兩天聽鍾神說Java 10都出來了2333。幹IT這行還真是要與時俱進啊,那就來看一下Java 10吧。
  • Java 10實際上並未引入太多新特性,不過有一個新特性最引人注目:
JEP 286: Local-Variable Type Inference
  • 等了這麼久Java終於支持類型推斷了,那麼今天就來看一看Java 10的類型推斷,和其餘語言相比有哪些異同吧。

0x02 類型推斷概述

  • 類型推斷是新型的高級語言提供的一類功能,容許根據編譯上下文來推斷變量的類型,不須要本身手動寫類型,使得代碼更加簡潔。
  • 目前我接觸的編程語言中,JavaScript、Swift和Python都支持這種語法。本次Java 10更新也支持了類型推斷,對於Java這種重量級語言來講仍是一件值得高興的事。

0x03 體驗Java 10的類型推斷功能

  • 讓咱們寫一段Base64編碼的代碼,體驗一下Java 10的類型推斷功能:
//Java代碼
import java.util.Base64;
class Untitled {
    public static void main(String[] args) {
        var b64encoder = Base64.getEncoder();
        var encodeString = b64encoder.encodeToString("Hello World".getBytes());
        System.out.println(encodeString);
    }
}
  • 初步體驗仍是不錯的,只是個人IDE尚未升級,還不支持自動提示這種語法。甚至Eclipse還不能正常編譯Java 10的代碼,我只能手動經過javac來編譯。總體而言Java 10的類型推斷功能是相似於Swift/JavaScript的,須要寫var關鍵字,並不像是Python那樣的使用方式。

0x04 Java 10類型推斷的不足

  • 上面的用法看起來很友好,那麼有沒有更自由的寫法呢?很快的我就收到了編譯器錯誤:
//Java代碼
import java.util.Base64;
class Untitled {
    public static void main(String[] args) {
        var b64encoder = Base64.getEncoder();
        var encodeString = b64encoder.encodeToString("Hello World".getBytes());
        System.out.println(encodeString);
        var a = 1,b = 2;
    }
}
錯誤: 'var' 不容許在複合聲明中使用
        var a = 1,b = 2;
            ^
1 個錯誤
  • 看來Java 10的類型推斷仍是有諸多限制和不便,不像其餘語言那般好用,對比一下Swift語言:
//Swift代碼
import Foundation
let string = "Hello World"
let data = string.data(using: String.Encoding.utf8)!
let encodeString = data.base64EncodedString()
print(encodeString)
var a = 1, b = 2;
  • 好比說Java 10並無let關鍵字,也就是說,並不能快速的使用類型推判定義常量。同時也不能一次用var定義多個變量,當同類型變量較多的時候,我以爲還不如把類型寫出來。
  • 同時,根據官方的說明,你也不能將var用於成員變量,只能用於局部變量,例以下面的例子會出現編譯錯誤:
//Java代碼
import java.util.Base64;
class Untitled {
    class Student {
        var name = "";
        Student(String name) {
            this.name = name;
        }
    }
    
    public static void main(String[] args) {
        var b64encoder = Base64.getEncoder();
        var encodeString = b64encoder.encodeToString("Hello World".getBytes());
        System.out.println(encodeString);
    }
}
錯誤: 此處不容許使用 'var'
        var name = "";
        ^
1 個錯誤
  • 而在其餘語言中,你能夠更自由的使用var,在任何你想要的地方,只要不引發歧義:
//Swift代碼
import Foundation
class Student {
    var name = "";
    init(name: String) {
        self.name = name;
    }
}
var string = "Hello World"
let data = string.data(using: String.Encoding.utf8)!
let encodeString = data.base64EncodedString()
print(encodeString)
  • 做爲對比,Swift比Java 10在類型推斷方面更加靈活,同時兩者也有共同點——它們都是強類型語言,任何變量必須具備某種類型,所謂的類型推斷只是一種語法上的精簡。例如你不能像Python同樣在形參列表中也不使用參數類型,或者直接省略返回值類型,這些類型還都是必須的:
#Python代碼
def printNumber(num):
    print(num)
    return 1

retCode = printNumber(4)
print(retCode)
//Swift代碼
func printNumber(num: Int) -> Int {
    print(num)
    return 1
}
let retCode = printNumber(num: 2)
print(retCode)
//Java代碼
import java.util.Base64;
class Untitled {
    public static int printNumber(int num) {
        System.out.println(num);
        return 1;
    }
    public static void main(String[] args) {
        var retCode = printNumber(3);
        System.out.println(retCode);
    }
}

0x05 總結

  • 通過簡單的體驗,基本清楚了Java 10的類型推斷功能。之後在局部範圍定義對象,能夠有了更簡略的寫法:
//Before Java 9
MessageDigest md = MessageDigest.getInstance("SHA-512");
//Java 10
var md = MessageDigest.getInstance("SHA-512");
  • 顯然這種代碼不兼容早期版本的Java,即便你將Java 10的代碼編譯爲字節碼,也不能在低版本的JVM上運行。這種新語法也不能用於Android開發等用途。好比我使用OpenJDK 1.8來測試咱們前面編碼base64的代碼,就出現了異常:
$ java -version
java version "10" 2018-03-20
Java(TM) SE Runtime Environment 18.3 (build 10+46)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)
$ java Main
SGVsbG8gV29ybGQ=
# java -version
openjdk version "1.8.0_111"
OpenJDK Runtime Environment (IcedTea 3.2.0) (suse-33.1-x86_64)
OpenJDK 64-Bit Server VM (build 25.111-b14, mixed mode)
# java Main
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 54.0), this version of the Java Runtime only recognizes class file versions up to 52.0
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
  • 因此說這種新語法仍是不夠靈活,同時兼容性也堪憂,可是聊勝於無。同時也會必定程度上減小Java代碼的長度,讓編程更加優雅一些。同窗們若是想體驗一下新語法,能夠升級到Java 10,不過好多Java應用都不兼容,因此升級仍是需慎重啊!
相關文章
相關標籤/搜索