前言
Swift是一門(mén)令人驚喜的語(yǔ)言,第一次聽(tīng)說(shuō)Swift,以為它只不過(guò)是OC的一個(gè)語(yǔ)法糖而已??墒?,當(dāng)我真正開(kāi)始了解它的時(shí)候,我開(kāi)始意識(shí)到了自己的錯(cuò)誤。Swift語(yǔ)言是一門(mén)全新設(shè)計(jì),有著漂亮語(yǔ)法的現(xiàn)代語(yǔ)言。而今天,我想站在Swift的角度來(lái)看看最新發(fā)布的Java8,看看Java8給我們帶來(lái)了什么驚喜,亦或是給我們帶來(lái)了什么遺憾。
姍姍來(lái)遲的Java8
從2011年7月底Sun發(fā)布了Java 7正式版后,不久,Sun公司就被Oracle公司收購(gòu)了。Java也因此成為了Oracle公司的獨(dú)家資產(chǎn)。Oracle公司原定于2013年發(fā)布Java8,卻因安全性問(wèn)題一拖再拖,最終在2014年3月18日正式發(fā)布了Java8。雖然從Java6到Java7中間經(jīng)歷了5年多的等待,而從Java7到Java8只經(jīng)歷了不到3年的時(shí)間,卻因Oracle公司的頻繁“跳票”讓開(kāi)發(fā)者感覺(jué)比Java7來(lái)的似乎更漫長(zhǎng)一些。然而,不管怎樣,讓我們充滿(mǎn)期待的Java8終究是來(lái)了...
久違的閉包
Java8語(yǔ)言中被提到最多的名詞恐怕就是Lambda表達(dá)式,這其實(shí)就是閉包。閉包,簡(jiǎn)單來(lái)說(shuō),就是沒(méi)有函數(shù)名的代碼塊。很多現(xiàn)代語(yǔ)言如:Python,Ruby,Go,Objective-C,Swift等都支持閉包。而Java語(yǔ)言支持閉包卻讓我們等了將近20年。今天,我們就和Swift語(yǔ)言的閉包進(jìn)行簡(jiǎn)單的對(duì)比,看看Java8的閉包和Swift閉包在用法上有什么區(qū)別,各有什么優(yōu)缺點(diǎn)。
先來(lái)看看Java8閉包的基本寫(xiě)法:
<pre>
// 例子一 實(shí)現(xiàn)兩個(gè)數(shù)字的相加
// 用幾個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明Java8閉包的基本用法
// 實(shí)現(xiàn)兩個(gè)數(shù)字相加
interface Sum {
int f(int x,int y);
}
// 匿名類(lèi)實(shí)現(xiàn)方式
Sum sum = new Sum() {
@Override
public int f(int x,int y) {
return x + y;
}
};
// 閉包實(shí)現(xiàn)
Sum sum = (int x,int y) -> {
return x + y;
};
// 閉包還支持類(lèi)型推導(dǎo)
Sum sum = (x,y) -> {
return x + y;
};
// 甚至可以省略return關(guān)鍵字
Sum sum = (x,y) -> x + y;
// 例子二 實(shí)現(xiàn)集合的遍歷
List<String> list = new ArrayList<>();
...
// 常規(guī)實(shí)現(xiàn)
for(String s : list) {
System.out.println(s);
};
// 閉包實(shí)現(xiàn)
list.forEach((value) -> System.out.println(value));
// Java8還支持方法引用。上面的表達(dá)式還可以更簡(jiǎn)單
list.forEach(System.out::println);
</pre>
通過(guò)上面兩個(gè)簡(jiǎn)單的例子對(duì)比,是否感覺(jué)閉包在實(shí)現(xiàn)同樣功能上,其表達(dá)方式更加的優(yōu)雅呢?
下面,我們來(lái)看一下用Swift語(yǔ)言實(shí)現(xiàn)同樣功能的閉包寫(xiě)法
<pre>
// 同樣地,實(shí)現(xiàn)兩個(gè)數(shù)字相加
// 完整寫(xiě)法
var sum = {(x:Int,y:Int) -> Int in return x + y }
// Swift同樣可以省略return關(guān)鍵字,甚至返回值
// 因此簡(jiǎn)化后,寫(xiě)法
var sum = {(x:Int,y:Int) in x + y}
// 同樣地,Swift也支持類(lèi)型推導(dǎo),這里我們假設(shè)這個(gè)閉包表達(dá)式作為函數(shù)f的一個(gè)參數(shù)
func f((x:Int,y:Int) -> Int) {
}
// 這里在調(diào)用函數(shù)f的時(shí)候,閉包表達(dá)式就可以簡(jiǎn)寫(xiě)為
f({x,y in x + y})
// Swift還支持參數(shù)索引,因此我們還可以進(jìn)一步簡(jiǎn)化為
f({$0 + $1})
// Swift還支持Trailing閉包,因此可以使用更漂亮的實(shí)現(xiàn)方式
// 這里簡(jiǎn)單地介紹一下Training閉包,所謂的Trailing閉包,就是說(shuō),如果閉包作為函數(shù)的最后一個(gè)參數(shù),就可以將閉包的實(shí)現(xiàn)從括號(hào)中直接剝離出來(lái),像函數(shù)體一樣寫(xiě)在括號(hào)的外面。因此,上面的閉包實(shí)現(xiàn)還可以寫(xiě)成如下形式:
f() {
$0 + $1
}
// 下面來(lái)實(shí)現(xiàn)集合的遍歷
var list = [2,1,4,3]
list.forEach { (a) -> () in
print(a)
}
</pre>
從上面的實(shí)現(xiàn)中,可以看到Swift在實(shí)現(xiàn)閉包的時(shí)候并不需要先定義接口,它可以用一個(gè)變量直接接受閉包表達(dá)式。但這并不能作為Swift閉包設(shè)計(jì)優(yōu)于Java8的證據(jù),這是由于Java天然的面向?qū)ο蠡驔Q定了其在閉包實(shí)現(xiàn)上的短板。不過(guò),Swift的參數(shù)索引以及Trailing閉包相對(duì)于Java8還是具有微弱的優(yōu)勢(shì)。
Optional 讓你告別空指針異常
可能很多人像我一樣第一次看到這個(gè)名稱(chēng)會(huì)感覺(jué)到非常陌生??墒?,當(dāng)我換一種說(shuō)法,大家就會(huì)感覺(jué)到非常熟悉了。NulllPointerException 作為Java程序員,恐怕這個(gè)錯(cuò)誤是再熟悉不過(guò)了吧。沒(méi)錯(cuò),Optional就是為了解決空指針異常而引入的。它為什么可以解決空指針異常呢?且聽(tīng)我慢慢道來(lái)。
看到這里,你不妨先喝杯茶,我們來(lái)簡(jiǎn)單看看NullPointerException的作者怎么評(píng)價(jià)NullPointerException
<pre>
Tony Hoare, the inventor of the null reference apologized in 2009 and denotes this kind of errors as his billion-dollar mistake.
I call it my billion-dollar mistake. It was the invention of the null reference in 1965.
At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W).
My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler.
But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement.
This has led to innumerable errors, vulnerabilities, and system crashes,
which have probably caused a billion dollars of pain and damage in the last forty years.
</pre>
從上面這段話(huà)可以看出,創(chuàng)始人Tony Hoare對(duì)其當(dāng)初的設(shè)計(jì)并不滿(mǎn)意,而且對(duì)NullPointerException給大家?guī)?lái)的問(wèn)題感到抱歉。然而,幸好有了Optional,這個(gè)問(wèn)題開(kāi)始出現(xiàn)好轉(zhuǎn)。
所謂的Optional,顧名思義?,?可選的,即是說(shuō),其里面是否包含值是可選的,這個(gè)變量里面可能包含值,也可能不包含值。下面我們就通過(guò)一個(gè)簡(jiǎn)單的例子,來(lái)看看它到底是怎么用的?以及它是如何避免出現(xiàn)空指針異常的。
<pre>
// 基本用法
// 存值
Optional<String> str = Optional.of("string");
// 取值
System.out.println(str.get());
// 判斷Optional中是否有值
str.isPresent();
// 判斷其是否有值。如果有進(jìn)行括號(hào)中的操作
str.ifPresent(...)
// 我們就利用上面這個(gè)特性來(lái)嘗試解決空指針異常
class Person {
private String name;
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) {
Optional.of(new Person())
.map(Person::getName)
.ifPresent(System.out::println);
}
}
// 上面的寫(xiě)法就能實(shí)現(xiàn),如果name不為空,將name直接打印出來(lái),否則將不進(jìn)行任何操作。這樣,就省去了非空判斷的操作,簡(jiǎn)單明了。
</pre>
第一次接觸Optional這個(gè)名詞是來(lái)自Swift,Swift在實(shí)現(xiàn)這個(gè)功能的時(shí)候更加的優(yōu)雅,美觀。同樣的例子,我們用Swift來(lái)實(shí)現(xiàn)一遍
<pre>
class Person {
var name:String?
func getName() -> String {
return name!
}
}
var p:Person = Person()
print(p.name)
// 上面的代碼將直接打印出nil
// 變量后面添加?表示該對(duì)象是一個(gè)可選值
// 添加!表示獲取可選值里面的對(duì)象,專(zhuān)業(yè)名詞叫做UnWrap(解封裝)
// 上面的例子還不足以看出Swift是如何解決空指針異常的,讓我們通過(guò)另外一個(gè)例子來(lái)看一下它是如何避免出現(xiàn)空指針異常的
class Eye {
var color:String? = "red"
func getColor() -> String {
return color!
}
}
class Fish {
var eye:Eye?
func getEye() -> Eye {
return eye!
}
}
var fish:Fish = Fish()
print(fish.eye?.color)
// 這里依然會(huì)打印出nil字符串
// 可以看到如果Swift發(fā)現(xiàn)可選對(duì)象為空,后面獲取對(duì)象中屬性的方法將不會(huì)執(zhí)行,從而避免了空指針異常的發(fā)生,其解決方案和Java8是一致的,只是實(shí)現(xiàn)方式上更加優(yōu)雅。
</pre>
看了上面的介紹,你更喜歡Java8的實(shí)現(xiàn)方式還是Swift語(yǔ)言呢?不妨在評(píng)論里面告訴我。
更好的interface
Java8以前如果在一個(gè)類(lèi)中既要存在抽象方法,又要存在已實(shí)現(xiàn)方法,必須使用抽象類(lèi)實(shí)現(xiàn)。而Java8終于開(kāi)始在接口中進(jìn)行方法實(shí)現(xiàn)了,它使用default關(guān)鍵字
<pre>
interface Java8 {
void abstractMethod();
default void defaultMethod() {
System.out.print("This is default method in interface");
}
}
// 通過(guò)這種方式,Java語(yǔ)言也可以輕松實(shí)現(xiàn)類(lèi)似C++語(yǔ)言的多重繼承了。But forget it...
</pre>
Stream
stream通過(guò)Stream,結(jié)合閉包。我們可以輕松實(shí)現(xiàn)很多在Java8之前很難實(shí)現(xiàn)的功能。例如:排序,過(guò)濾等
<pre>
List<String> list = Arrays.asList("Java","Swift","Cpp","C#");
// 排序,字母長(zhǎng)度由長(zhǎng)到短
list.stream().sorted((a1,a2) -> a2.length() - a1.length()).forEach(System.out::println);
// 過(guò)濾,保留包含字母C的所有元素
list.stream().filter(value -> value.contains("C")).forEach(System.out::println);
</pre>
more
Java8提供的新特性還遠(yuǎn)不止這些,以上特性是我認(rèn)為最值得跟大家分享,也最值得為人所稱(chēng)道的。如果你想了解更多的Java8新特性,請(qǐng)參考Oracle官方Java8文檔。如果你對(duì)這篇文章有任何自己的見(jiàn)解,請(qǐng)?jiān)谖恼孪路搅粞裕窒砟銓?duì)Java8語(yǔ)言的看法,我在這里期待你的發(fā)言哦!
總結(jié)
從Java7到Java8,從Sun到Oracle,我們看到了Java語(yǔ)言的巨變。它開(kāi)始接受新語(yǔ)言新思想的洗禮,開(kāi)始融入Swift等現(xiàn)代編程語(yǔ)言的大家庭;它開(kāi)始變得謙虛起來(lái),不再高高在上;它開(kāi)始變得更加美麗,更加讓人愛(ài)不釋手。不管,Java語(yǔ)言的過(guò)去如何,也不管Java語(yǔ)言花落誰(shuí)家,至少我們知道它在進(jìn)步。這也讓我對(duì)Java9抱有更大的期待,我期待著它給Java程序員們帶來(lái)更大的驚喜。
交流
如果你喜歡Swift語(yǔ)言,請(qǐng)加入iOS交流群:468167089,和更多的朋友一起玩轉(zhuǎn)Swift。