Hussachai Puripunpinyo認為java是一門靜態的強類型語言,因此雖然在Java 8 中函數已經成了一等公民,可以作為函數的參數或者返回值來傳遞,但是它必須要有一個類型,那就是接口,而Lambda表達式就是實現了Functional接口的對象。雖然開發人員不需要為函數對象的創建而擔心,因為編譯器會做這些事情,但是Java并沒有Scala那么出色的類型推理機制,在Java中聲明Lambda表達式必須要指定目標類型。考慮到Java必須維持向后兼容性,這樣做也是可以讓人接受和理解的,事實上在兼容性方面Java已經做的足夠好了,例如Thread.stop()在JDK 1.0中就已經有了,雖然被標記為“已廢棄”數十年,但是現在依然存在,因而不應該因為其他語言有更好的語法就期望Java快速地改變自己的語法。
為了支持Lambda表達式Java引入了函數式接口,該接口只有一個抽象方法。@FunctionalInterface是一個注解,用來表明被注解的接口是一個函數式接口,該注解是可選的,只有需要對接口是否符合契約做檢查的時候才需要使用。
在Java中,Lambda表達式必須要有一個類型,而且類型必須有且僅有一個抽象方法,而大部分已有的回調接口已經滿足這一需求,因此用戶不需要對它們做出任何改變就能夠重用這些接口。例如:
//在Java 8之前Runnable r = new Runnable(){ public void run(){ System.out.PRintln(“This should be run in another thread”); }};//Java 8Runnable r = () -> System.out.println(“This should be run in another thread”);
對于有一個參數并且有返回值的函數,Java 8提供了一組通用的函數式接口,這些接口在java.util.function包中,使用方式如下:
//Java 8Function<string, integer=""> parseInt = (String s) -> Integer.parseInt(s);
因為參數類型可以從Function對象的類型聲明中推斷出來,所以類型和小括號都可以省略:
//Java 8Function<string, integer=""> parseInt = s -> Integer.parseInt(s);
對于需要兩個參數的函數,Java 8提供了BiFunction:
//Java 8BiFunction<integer, integer="" integer,=""> multiplier = (i1, i2) -> i1 * i2; //you can’t omit parenthesis here!
對于需要3個及以上參數的接口,Java 8并沒有提供相應的TriFunction、QuadFunction等定義,但是用戶可以定義自己的TriFunction,如下:
//Java 8@FunctionalInterfaceinterface TriFunction<a, r="" c,="" b,=""> { public R apply(A a, B b, C c);}
在引入了之前定義好的接口之后就可以這樣聲明Lambda表達式:
//Java 8TriFunction<integer, integer="" integer,=""> sumOfThree = (i1, i2, i3) -> i1 + i2 + i3;
對于語言的設計者為什么會止步于BiFunction,Hussachai Puripunpinyo認為TriFunction、QuadFunction等需要更多參數的接口需要太多的類型聲明,接口的定義變得非常長,同時又怎么決定定義到哪一個才最合適呢,總不能一直定義到包含9個參數和一個返回值類型的EnnFunction吧!
以上示例顯示參數越多,類型定義越冗長,甚至可能整整一行都是類型聲明,那么必須要聲明類型么?答案是在Java中必須如此,但是在Scala中就簡單的多了。
Scala也是一門靜態強類型的語言,但是它從誕生開始就是一門函數式語言,完美融合了面向對象范式和函數式語言范式。Scala中的Lambda表達式也有一個類型,但是語言的設計者采用了數字而不是拉丁語來命名,Scala為開發者提供了0到22個參數的接口定義(Function0、Function1、… Function22),如果需要更多的參數,那么或許是開發者在設計上就存在問題。在Scala中Function的類型是特性(trait),類似于Java中的抽象類。
Scala中的Runnable示例與Java中的實現方式不同:
//ScalaFuture(println{“This should be run in another thread”})//以上代碼等同于//Java 8//assume that you have instantiated ExecutorService beforehand.Runnable r = () -> System.out.println(“This should be run in another thread”);executorService.submit(r);
在Scala中聲明一個Lambda表達式不必像Java那樣必須顯式指定類型,而且方式也有很多:
//Java 8Function<string, integer=""> parseInt = s -> Integer.parseInt(s);//Scalaval parseInt = (s: String) => s.toInt//orval parseInt:String => Int = s => s.toInt//orval parseInt:Function1[String, Int] = s => s.toInt
如果需要更多的參數:
//Java 8PentFunction<integer, integer="" integer,=""> sumOfFive = (i1, i2, i3, i4, i5) -> i1 + i2 + i3 + i4 + i5;//Scalaval sumOfFive = (i1: Int, i2: Int, i3: Int, i4: Int, i5: Int) => i1 + i2 + i3 + i4 + i5;
可以看到,Scala的語法更簡潔,可讀性更好,開發者不需要聲明接口類型,通過參數列表中的類型就能看出對象的類型。
//Java 8PentFunction<string, integer,="" string="" string,="" boolean,="" double,=""> sumOfFive = (i1, i2, i3, i4, i5) -> i1 + i2 + i3 + i4 + i5;//Scalaval sumOfFive = (i1: String, i2: Int, i3: Double, i4: Boolean, i5: String) => i1 + i2 + i3 + i4 + i5;
對于上面這段代碼,開發者一打眼就能看出i3是Double類型的,但是在Java 8中開發者必須要數一數才能看出來,如果要在Java 8中達到這種效果,那只有從格式上來做文章了:
//Java 8 PentFunction sumOfFive = (Integer i1, String i2, Integer i3, Double i4, Boolean i5) -> i1 + i2 + i3 + i4 + i5;
但是這真是非常糟糕,開發者必須一次次地鍵入類型,另外,Java 8并沒有定義PentFunction,你還必須自己定義:
//Java 8@FunctionalInterfaceinterface PentFunction<a, r="" c,="" b,="" e,="" d,=""> { public R apply(A a, B b, C c, D d, E e);}
Hussachai Puripunpinyo認為Scala在函數式方面做的更好,一方面是因為Scala本身就是一門函數式語言,另一方面是因為Java語言的設計者在引入新東西的時候必須要考慮兼容性,因而有很多約束。但是即使如此,Java 8依然引入了一些非常酷的特性,例如方法引用,該特性就能夠讓Lambda表達式的聲明更加簡短:
//Java 8Function<string, integer=""> parseInt = s -> Integer.parseInt(s);//使用方法引用可以簡寫為://Java 8Function<string, integer=""> parseInt = Integer::parseInt;
在Java 8中,方法引用的構建規則有3種:
Function<integer, string=""> intToStr = String::valueOf;
BiFunction<string, integer="" string,=""> indexOf = String::indexOf;
Function<string, integer=""> indexOf = new String()::indexOf;
流API就大量使用了這種語法來簡化代碼的編寫:
pets.stream().map(Pet::getName).collect(toList());// The signature of map() function can be derived as// Stream map(Function mapper)
前兩天在一群里看見有人推薦一個app叫問啊,就可以發題答題那種的,感覺就跟uber滴滴打車似的,一般這種軟件一上來就砸錢給紅包啥的,哥之前刷過uber的單有經驗!試驗了幾次應該可以刷,把注冊紅包和之前領的紅包錢套現,目前我提了五十多,目測還能刷更多。ps,但是盡量要問技術相關的問題,不然容易被封。
有技術的可以自己試,不會的可以q我QQ群290551701
新聞熱點
疑難解答