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