談一談JAVA語法糖
上週在聽大牛分享JVM編譯優化時,提到了在編譯階段會進行的一個步驟:解語法糖。他提出了一個問題是:JAVA裏有哪些語法糖,聽到這個問題,似乎很容易回答,因爲我們都知道java有很多語法糖,但話到嘴邊,也就只能想起字符串拼接和foreach來,果然,沒有經過系統的梳理,一些聽起來簡單的知識點也會難倒你,所以我來梳理一下,看java裏到底有哪些語法糖。
概述
在搜狗百科中,語法糖含義解釋如下:語法糖(Syntactic sugar),也譯爲糖衣語法,是由英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語,指計算機語言中添加的某種語法,這種語法對語言的功能並沒有影響,但是更方便程序員使用。通常來說使用語法糖能夠增加程序的可讀性,從而減少程序代碼出錯的機會。
從概念上可以看出來,簡單地說就是通過更簡單的語法實現原有功能,對語言功能沒有影響。以java來說就是某個語法可能JVM不支持,但是編譯器可以將語法轉換成基礎語法以實現功能。相當於快捷方式。
有哪些語法糖
下面我們寫一些語法糖使用,通過反編譯看看他們是怎麼實現的。
增強for循環
/**
* 增強for循環
*/
public void forTest() {
List<String> stringList = Arrays.asList("A", "B");
for (String str :stringList) {
System.out.println(str);
}
}
反編譯class文件後
public void forTest() {
List<String> stringList = Arrays.asList("A", "B");
Iterator var2 = stringList.iterator();
while(var2.hasNext()) {
String str = (String)var2.next();
System.out.println(str);
}
}
通過Iterator實現,這裏在分析fail-fast機制時提過,不能在增強for循環中進行集合的增刪操作,否則會拋異常。
switch(String)
/**
* switch(String)
*/
public int switchString(String str) {
switch (str){
case "A":
return 1;
case "B":
return 2;
default:
return 0;
}
}
public int switchString(String str) {
byte var3 = -1;
switch(str.hashCode()) {
case 65:
if (str.equals("A")) {
var3 = 0;
}
break;
case 66:
if (str.equals("B")) {
var3 = 1;
}
}
switch(var3) {
case 0:
return 1;
case 1:
return 2;
default:
return 0;
}
}
可以看到switch(String)是轉爲了switch(byte),之前單獨分析過這裏的機制。
條件編譯
/**
* 條件編譯
*/
public void ifTest() {
if (true) {
System.out.println("1");
} else {
System.out.println("2");
}
}
public void ifTest() {
System.out.println("1");
}
當條件爲常量時,一定不會執行的分支會自動清除。
可變參數
/**
* 可變參數
* @param strings
*/
public void strings(String... strings) {
for (String s : strings) {
System.out.println(s);
}
}
public void strings(String... strings) {
String[] var2 = strings;
int var3 = strings.length;
for(int var4 = 0; var4 < var3; ++var4) {
String s = var2[var4];
System.out.println(s);
}
}
可變參數實際是變長數組
泛型
/**
* 泛型
*/
public void listTest() {
List<String> list = new ArrayList<String>();
int i = list.size();
}
public void listTest() {
List<String> list = new ArrayList();
int i = list.size();
}
可以看到,泛型參數已經被擦除了。
lambda表達式
/**
* lambda表達式
*/
public void lambdaTest() {
List<String> list = new ArrayList<>();
list = list.stream().distinct().collect(Collectors.toCollection(LinkedList::new));
}
try with resource
/**
* try with resource
*/
public void tryResourceTest() throws IOException {
try(StringWriter writer = new StringWriter()) {
writer.write(1);
}
}
public void tryResourceTest() throws IOException {
StringWriter writer = new StringWriter();
Throwable var2 = null;
try {
writer.write(1);
} catch (Throwable var11) {
var2 = var11;
throw var11;
} finally {
if (writer != null) {
if (var2 != null) {
try {
writer.close();
} catch (Throwable var10) {
var2.addSuppressed(var10);
}
} else {
writer.close();
}
}
}
}
Try with resource是自動幫你加上finally,並且調用closeable接口裏的close方法。