国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Java 8 vs. Scala(一): Lambda表達式

yuanxin / 1702人閱讀

摘要:編程語言將函數作為一等公民,函數可以被作為參數或者返回值傳遞,因為它被視為對象。是表示已注釋接口是函數接口的注釋。如果一個函數有一個或多個參數并且有返回值呢為了解決這個問題,提供了一系列通用函數接口,在包里。

【編者按】雖然 Java 深得大量開發者喜愛,但是對比其他現代編程語言,其語法確實略顯冗長。但是通過 Java8,直接利用 lambda 表達式就能編寫出既可讀又簡潔的代碼。作者 Hussachai Puripunpinyo 的軟件工程師,作者通過對比 Java 8和 Scala,對性能和表達方面的差異進行了分析,并且深入討論關于 Stream API 的區別,本文由 OneAPM 工程師編譯整理。

數年等待,Java 8 終于添加了高階函數這個特性。本人很喜歡 Java,但不得不承認,相比其他現代編程語言,Java 語法非常冗長。然而通過 Java8,直接利用 lambda 表達式就能編寫出既可讀又簡潔的代碼(有時甚至比傳統方法更具可讀性)。

Java 8于2014年3月3日發布,但筆者最近才有機會接觸。因為筆者也很熟悉 Scala,所以就產生了對比 Java 8和Scala 在表達性和性能方面的差異,比較將圍繞 Stream API 展開,同時也會介紹如何使用 Stream API 來操作集合。

由于文章太長,所以分以下三個部分詳細敘述。

Part 1.Lambda 表達式

Part 2. Stream API vs Scala collection API

Part 3. Trust no one, bench everything(引用自sbt-jmh)

首先,我們來了解下 Java 8的 lambda 表達式,雖然不知道即使表達式部分是可替代的,他們卻稱之為 lambda 表達式。這里完全可以用聲明來代替表達式,然后說 Java 8還支持 lambda 聲明。編程語言將函數作為一等公民,函數可以被作為參數或者返回值傳遞,因為它被視為對象。Java是一種靜態的強類型語言。所以,函數必須有類型,因此它也是一個接口。

另一方面,lambda 函數就是實現了函數接口的一個類。無需創建這個函數的類,編譯器會直接實現。不幸的是,Java 沒有 Scala 那樣高級的類型接口。如果你想聲明一個 lambda 表達式,就必須指定目標類型。實際上,由于 Java 必須保持向后兼容性,這也是可理解的,而且就目前來說 Java 完成得很好。例如,Thread.stop() 在 JDK 1.0版時發布,已過時了十多年,但即便到今天仍然還在使用。所以,不要因為語言 XYZ 的語法(或方法)更好,就指望 Java 從根本上改變語法結構。

所以,Java 8的語言設計師們奇思妙想,做成函數接口!函數接口是只有一個抽象方法的接口。要知道,大多數回調接口已經滿足這一要求。因此,我們可以不做任何修改重用這些接口。@FunctionalInterface 是表示已注釋接口是函數接口的注釋。此注釋是可選的,除非有檢查要求,否則不用再進行處理。

請記住,lambda 表達式必須定義類型,而該類型必須只有一個抽象方法。

</>復制代碼

  1. //Before Java 8
  2. Runnable r = new Runnable(){
  3. public void run(){
  4. System.out.println(“This should be run in another thread”);
  5. }
  6. };
  7. //Java 8
  8. Runnable r = () -> System.out.println(“This should be run in another thread”);

如果一個函數有一個或多個參數并且有返回值呢?為了解決這個問題,Java 8提供了一系列通用函數接口,在java.util.function包里。

</>復制代碼

  1. //Java 8
  2. Function parseInt = (String s) -> Integer.parseInt(s);

該參數類型可以從函數中推斷,就像 Java7中的diamond operator,所以可以省略。我們可以重寫該函數,如下所示:

</>復制代碼

  1. //Java 8
  2. Function parseInt = s -> Integer.parseInt(s);

如果一個函數有兩個參數呢?無需擔心,Java 8 中有 BiFunction。

</>復制代碼

  1. //Java 8
  2. BiFunction multiplier =
  3. (i1, i2) -> i1 * i2; //you can’t omit parenthesis here!

如果一個函數接口有三個參數呢?TriFunction?語言設計者止步于 BiFunction。否則,可能真會有 TriFunction、quadfunction、pentfunction 等。解釋一下,筆者是采用 IUPAC 規則來命名函數的。然后,可以按如下所示定義 TriFunction。

</>復制代碼

  1. //Java 8
  2. @FunctionalInterface
  3. interface TriFunction {
  4. public R apply(A a, B b, C c);
  5. }

然后導入接口,并把它當作 lambda 表達式類型使用。

</>復制代碼

  1. //Java 8
  2. TriFunction sumOfThree
  3. = (i1, i2, i3) -> i1 + i2 + i3;

這里你應該能理解為什么設計者止步于 BiFunction。

如果還沒明白,不妨看看 PentFunction,假設我們在其他地方已經定義了 PentFunction。

</>復制代碼

  1. //Java 8
  2. PentFunction
  3. sumOfFive = (i1, i2, i3, i4, i5) -> i1 + i2 + i3 + i4 + i5;

你知道 Ennfunction 是多長嗎?(拉丁語中,enn 表示9)你必須申報 10 種類型(前 9 個是參數,最后一個是返回類型),大概整行都只有類型了。那么聲明一個類型是否有必要呢?答案是肯定的。(這也是為什么筆者認為 Scala 的類型接口比 Java 的更好)

Scala 也有其 lambda 表達式類型。在 Scala 中,你可以創建有22個參數的 lambda 表達式,意味著 Scala 有每個函數的類型(Function0、Function1、……Function22)。函數類型在 Scala 函數中是一個 Trait,Trait 就像 Java 中的抽象類,但可以當做混合類型使用。如果還需要22個以上的參數,那大概是你函數的設計有問題。必須要考慮所傳遞的一組參數的類型。在此,筆者將不再贅述關于 Lambda 表達式的細節。

下面來看看Scala的其他內容。Scala 也是類似 Java 的靜態強類型語言,但它一開始就是函數語言。因此,它能很好地融合面向對象和函數編程。由于 Scala 和 Java 所采用的方法不同,這里不能給出 Runnable 的 Scala 實例。Scala 有自己解決問題的方法,所以接下來會詳細探討。

//Scala
Future(println{“This should be run in another thread”})

與以下 Java8 的代碼等效。

//Java 8
//assume that you have instantiated ExecutorService beforehand.
Runnable r = () -> System.out.println(“This should be run in another thread”);
executorService.submit(r);

如果你想聲明一個 lambda 表達式,可以不用像 Java 那樣聲明一個顯式類型。

</>復制代碼

  1. //Java 8
  2. Function parseInt = s -> Integer.parseInt(s);
  3. //Scala
  4. val parseInt = (s: String) => s.toInt
  5. //or
  6. val parseInt:String => Int = s => s.toInt
  7. //or
  8. val parseInt:Function1[String, Int] = s => s.toInt

所以,在 Scala 中的確有多種辦法來聲明類型。讓編譯器來執行。那么 PentFunction 呢?

</>復制代碼

  1. //Java 8
  2. PentFunction sumOfFive
  3. = (i1, i2, i3, i4, i5) -> i1 + i2 + i3 + i4 + i5;
  4. //Scala
  5. val sumOfFive = (i1: Int, i2: Int, i3: Int, i4: Int, i5: Int) =>
  6. i1 + i2 + i3 + i4 + i5;

Scala 更短,因為不需要聲明接口類型,而整數類型在 Scala 中是 int。短不總意味著更好。Scala 的方法更好,不是因為短,而是因為更具可讀性。類型的上下文在參數列表中,可以很快找出參數類型。如果還不確定,可以再參考以下代碼。

</>復制代碼

  1. //Java 8
  2. PentFunction
  3. sumOfFive = (i1, i2, i3, i4, i5) -> i1 + i2 + i3 + i4 + i5;
  4. //Scala
  5. val sumOfFive = (i1: String, i2: Int, i3: Double, i4: Boolean, i5: String)
  6. => i1 + i2 + i3 + i4 + i5;

在 Scala 中,可以很明確地說出 i3 類型是 Double 型,但在 Java 8 中,還需要算算它是什么類型。你可能爭辯說 Java 也可以,但出現這樣的狀況:

</>復制代碼

  1. //Java 8
  2. PentFunction sumOfFive
  3. = (Integer i1, String i2, Integer i3, Double i4, Boolean i5)
  4. -> i1 + i2 + i3 + i4 + i5;

你必須一遍又一遍的重復下去。

除此之外,Java8 并沒有 PentFunction,需要自己定義。

</>復制代碼

  1. //Java 8
  2. @FunctionalInterface
  3. interface PentFunction {
  4. public R apply(A a, B b, C c, D d, E e);
  5. }

是不是意味著 Scala 就更好呢?在某些方面的確是。但也有很多地方 Scala 不如 Java。所以很難說到底哪種更好,我之所以對兩者進行比較,是因為 Scala 是一種函數語言,而 Java 8 支持一些函數特點,所以得找函數語言來比較。由于 Scala 可以運行在 JVM 上,用它來對比再好不過。可能你會在使用函數時,Scala 有更簡潔的語法和方法,這是因為它本來就是函數語言,而 Java 的設計者在不破壞之前的基礎上拓展設計,顯然會有更多限制。

盡管 Java在語法上與 lambda 表達式相比有一定局限性,但 Java8 也引進了一些很酷的功能。例如,利用方法引用的特性通過重用現有方法使得編寫 lambda 表達式更簡潔。更簡潔嗎???

</>復制代碼

  1. //Java 8
  2. Function parseInt = s -> Integer.parseInt(s);

可以使用方法引用來重寫函數,如下所示

</>復制代碼

  1. //Java 8
  2. Function parseInt = Integer::parseInt;

還可以通過實例方法來使用方法引用。之后會在第二部分的 Stream API 中指出這種方法的可用性。

方法引用的構造規則

1.(args) -> ClassName.staticMethod(args);

可以像這樣重寫ClassName::staticMethod;

Function intToStr = String::valueOf;

2.(instance, args) -> instance.instanceMethod(args);

可以像這樣重寫 ClassName::instanceMethod;

BiFunction indexOf = String::indexOf;

3.(args) -> expression.instanceMethod(args);

可以像這樣重寫 expression::instanceMethod;

FunctionindexOf = new String()::indexOf;

你有沒有注意到規則2有點奇怪?有點混亂?盡管 indexOf 函數只需要1個參數,但 BiFunction 的目標類型是需要2個參數。其實,這種用法通常在 Stream API 中使用,當看不到類型名時才有意義。

</>復制代碼

  1. pets.stream().map(Pet::getName).collect(toList());
  2. // The signature of map() function can be derived as
  3. // Stream map(Function mapper)

從規則3中,你可能會好奇能否用 lambda 表達式替換 new String()?

你可以用這種方法構造一個對象

Supplier str =String::new;

那么可以這樣做嗎?

Function,Integer> indexOf = (String::new)::indexOf;

不能。它不能編譯,編譯器會提示The target type of this expression must be a functional interface。錯誤信息很容易引起誤解,而且似乎 Java 8通過泛型參數并不支持類型接口。即使使用一個 Functionalinterface 的實例(如前面提到的「STR」),也會出現另一個錯誤The type Supplier does not define indexOf(Supplier) that is applicable here。String::new 的函數接口是 Supplier,而且它只有方法命名為 get()。indexOf 是一個屬于 String 對象的實例方法。因此,必須重寫這段代碼,如下所示。

</>復制代碼

  1. //Java
  2. Function indexOf = ((Supplier)String::new).get()::indexOf;

Java 8 是否支持 currying (partial function)?

的確可行,但你不能使用方法引用。你可以認為是一個 partial 函數,但是它返回的是函數而不是結果。接著將要介紹使用 currying 的簡單實例,但這個例子也可能行不通。在傳遞到函數之前,我們通常進行參數處理。但無論如何,先看看如何利用 lambda 表達式實現 partial 函數。假設你需要利用 currying 實現兩個整數相加的函數。

</>復制代碼

  1. //Java
  2. IntFunctionadd = a -> b -> a + b;
  3. add.apply(2).applyAsInt(3);//the result is 4! I"m kidding it"s 5.

該函數可以同時采用兩個參數。

</>復制代碼

  1. //Java
  2. Supplier> add = () -> (a, b) -> a + b;
  3. add.get().apply(2, 3);

現在,可以看看 Scala 方法。

</>復制代碼

  1. //Scala
  2. val add = (a: Int) => (b:Int) => a + b
  3. add(1)(2)
  4. //Scala
  5. val add = () => (a: Int,b: Int) => a + b
  6. add2()(1,2)

因為類型引用和語法糖,Scala 的方法比 Java 更簡短。在 Scala 中,你不需要在 Function trait 上調用 apply 方法,編譯器會即時地將()轉換為 apply 方法。

原文鏈接: https://dzone.com/articles/java-8-λe-vs-scalapart-i

OneAPM for Java 能夠深入到所有 Java 應用內部完成應用性能管理和監控,包括代碼級別性能問題的可見性、性能瓶頸的快速識別與追溯、真實用戶體驗監控、服務器監控和端到端的應用性能管理。想閱讀更多技術文章,請訪問 OneAPM 官方博客。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/64768.html

相關文章

  • 轉 | Java8初體驗(lambda達式語法

    摘要:初體驗下面進入本文的正題表達式。接下來展示表達式和其好基友的配合。吐槽一下方法引用表面上看起來方法引用和構造器引用進一步簡化了表達式的書寫,但是個人覺得這方面沒有的下劃線語法更加通用。 感謝同事【天錦】的投稿。投稿請聯系 tengfei@ifeve.com 本文主要記錄自己學習Java8的歷程,方便大家一起探討和自己的備忘。因為本人也是剛剛開始學習Java8,所以文中肯定有錯誤和理解偏...

    Lucky_Boy 評論0 收藏0
  • Java 8 vs. Scala(二):Stream vs. Collection

    摘要:比如對一個數據流進行過濾映射以及求和運算,通過使用延后機制,那么所有操作只要遍歷一次,從而減少中間調用。這里需知道中的元素都是延遲計算的,正因為此,能夠計算無限數據流。 【編者按】在之前文章中,我們介紹了 Java 8和Scala的Lambda表達式對比。在本文,將進行 Hussachai Puripunpinyo Java 和 Scala 對比三部曲的第二部分,主要關注 Stream...

    GeekGhc 評論0 收藏0
  • JVM 平臺上的各種語言的開發指南[z]

    摘要:我們的目標是建立對每一種語言的認識,它們是如何進化的,未來將走向何方。有點的味道是堅持使用動態類型,但唯一還收到合理擁泵的編程語言,然而一些在企業的大型團隊中工作的開發者擇認為這會是的一個缺陷。 為什么我們需要如此多的JVM語言? 在2013年你可以有50中JVM語言的選擇來用于你的下一個項目。盡管你可以說出一大打的名字,你會準備為你的下一個項目選擇一種新的JVM語言么? 如今借助來自...

    phodal 評論0 收藏0
  • Java 8函數式編程》作者Richard Warbourton:Java的亮點不是語言本身

    摘要:根據對社區和新特性的深刻理解,他創作了函數式編程一書。問你在倫敦社區的經歷是否幫助你創作了函數式編程這本書絕對是這樣。我認為引入函數式編程會為很多編程任務提供方便。問之前的是面向對象的,現在全面支持函數式編程。 非商業轉載請注明作譯者、出處,并保留本文的原始鏈接:http://www.ituring.com.cn/article/199271 Richard Warburto...

    mzlogin 評論0 收藏0
  • vavr:讓你像寫Scala樣寫Java

    摘要:是在嘗試讓擁有跟類似的語法。在中使用,需要顯示得將集合轉成的步驟,而在中則免去了這樣的步驟。中的語句只能針對常量起作用,而使用模式匹配則可以對另一個函數的返回結果起作用,功能非常搶到。 Hystrix是Netflix開源的限流、熔斷降級組件,去年發現Hystrix已經不再更新了,而在github主頁上將我引導到了另一個替代項目——resilience4j,這個項目是基于Java 8開發...

    andycall 評論0 收藏0

發表評論

0條評論

yuanxin

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<