一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java中Lambda表達式并行與組合行為

Java中Lambda表達式并行與組合行為

2020-08-18 11:24hwding Java教程

這篇文章主要介紹了Java中Lambda表達式并行與組合行為,非常不錯,具有參考借鑒價值,需要的朋友可以參考下

從串行到并行

串行指一個步驟一個步驟地處理,也就是通常情況下,代碼一行一行地執行。

如果將我們常用的迭代器式的循環展開的話,就是串行執行了循環體內所定義的操作:

?
1
2
3
4
sum += arr.get(0);
sum += arr.get(1);
sum += arr.get(2);
//...

在書的一開始,就提到Java需要支持集合的并行計算(而Lambda為這個需求提供了可能)。

這些功能將全部被實現于庫代碼中,對于我們使用者,實現并行的復雜性被大大降低(最低程度上只需要調用相關方法)。

另外,關于并發與并行這兩個概念,其實是不同的,如果不明白的話請自行了解,在此只引用一句非常流行的話:

一個是關于代碼結構,一個是關于代碼執行。

如果我們想將一個計算任務均勻地分配給CPU的四個內核,我們會給每個核分配一個用于計算的線程,每個線程上進行整個任務的子任務。

書上有一段非常形象的偽代碼:

?
1
2
3
4
5
6
7
8
9
10
11
if the task list contains more than N/4 elements {
 leftTask = task.getLeftHalf()
 rightTask = task.getRightHalf()
 doInparallel {
 leftResult = leftTask.solve()
 rightResult = rightTask.solve()
 }
 result = combine(leftResult, rightResult)
} else {
 result = task.solveSequentially()
}

代碼中,將每四個任務元素分為一組,用四個內核對其進行并行處理,然后每兩組進行一次結果的合并,最終得到整個任務隊列的最終結果。

從整體處理流程上看,先將任務隊列遞歸地進行分組,并行處理每一組,然后將結果遞歸地進行合并(合并通過管道終止操作實現)。

Java8之前,開發者們使用一種針對集合的fork/join框架來實現該模式。

然而現在,想對代碼進行性能優化,就是一件非常容易的事了。

還記得我們上一節中所得出的最終代碼:

?
1
2
3
4
long validContactCounter = contactList.stream()
 .map(s -> new Contact().setName(s))
 .filter(Contact::call)
 .count();

稍加改動:

?
1
2
3
4
long validContactCounter = contactList.parallelStream()
 .map(s -> new Contact().setName(s))
 .filter(Contact::call)
 .count();

注意stream()變為parallelStream()

同時下圖將展示如何根據四個核對上述任務進行分解處理,最終合并結果并終止管道。

注意遞歸分解的目的是使子任務們足夠小來串行執行。

組合行為

Java寫手應該知道,Java中并不存在純粹的“函數”,只存在“方法”。也就是說,Java中的函數必須依賴于某一個類,或者作為類的某種行為存在。

而在其他語言中,存在純函數,以CoffeeScript的語法,聲明一個函數:

?
1
2
eat = (x) ->
 alert("#{x} has been eatten!")

這種寫法與Lambda表達式的語法非常相近,也就是說,相比于匿名內部類,Lambda表達式看上去更像是一種函數表達式。

對于函數,一個核心操作便是組合。如果要求一元二次函數的其中一個解sqrt(sqr(b) - 4 * a * c),便是對多個子函數進行了組合。

對于面向對象,我們通過解耦的方式來分解它,同樣,我們也希望以此種方式分解一個函數行為。

首先,沿用上兩節中使用的例子,對Contact類稍作修改,將name屬性分拆為名和姓:

?
1
2
private String firstName;
private String lastName;

假設我們現在想要對聯系人們進行排序,創建自定義排序的Java標準方式是創建一個Comparator:

?
1
2
3
4
public interface Comparator<T> {
 int compare(T o1, T o2);
 //...
}

我們想通過比較名的首字母來為聯系人排序:

?
1
2
3
4
5
6
Comparator<Contact> byFirstName = new Comparator<Contact>() {
 @Override
 public int compare(Contact o1, Contact o2) {
 return Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));
 }
};

Lambda寫法:

?
1
2
Comparator<Contact> byFirstNameLambdaForm = (o1, o2) ->
 Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));

寫完這段代碼后,IDEA立即提醒我代碼可以替換為Comparator.comparingInt(...),不過這是后話,暫且不表。

在上面的代碼中,我們發現了組合行為,即Comparator<Contact>的compare(...)方法里面還套用了o.getFirstName()與Character.compare(...)這兩個方法(為了簡潔,這里暫不考慮charAt(...)),在java.util.function中,我們找到了這種函數的原型:

?
1
2
3
4
public interface Function<T, R> {
 R apply(T t);
 //...
}

接收一個T類型的參數,返回一個R類型的結果。

現在我們將“比較名的首字母”這個比較鍵的提取行為抽成一個函數對象的實例:

?
1
Function<Contact, Character> keyExtractor = o -> o.getFirstName().charAt(0);

再將“比較首字母”這個具體的比較行為抽出來:

?
1
Comparator<Character> keyComparator = (c1, c2) -> Character.compare(c1, c2);

有了keyExtractor和keyComparator,我們再來重新裝配一下Comparator:

?
1
2
Comparator<Contact> byFirstNameAdvanced = (o1, o2) ->
 keyComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2));

到了這一步,我們犧牲了簡潔性,但獲得了相應的靈活性,也就是說,如果我們改變比較鍵為姓而非名,只需改動keyExtractor為:

?
1
Function<Contact, Character> keyExtractor = o -> o.getLastName().charAt(0);

值得慶幸的是,庫的設計者考慮到了這一自然比較的需求的普遍性,因此為Comparator接口提供了靜態方法comparing(...),只需傳入比較鍵的提取規則,就能針對該鍵生成相應的Comparator,是不是非常神奇:

?
1
Comparator<Contact> compareByFirstName = Comparator.comparing(keyExtractor);

即使我們想改變比較的規則,比如比較聯系人姓與名的長度,也只需做些許改動:

?
1
Comparator<Contact> compareByNameLength = Comparator.comparing(p -> (p.getFirstName() + p.getLastName()).length());

這是一個重大的改進,它將我們所關注的焦點真正集中在了比較的規則上面,而不是大量地構建所必須的膠水代碼。

comparing(...)通過接收一個簡單的行為,進而基于這個行為構造出更加復雜的行為。

贊!

然而更贊的是,對于流和管道,我們所需要的改動甚至更少:

?
1
2
3
contacts.stream()
 .sorted(compareByNameLength)
 .forEach(c -> System.out.println(c.getFirstName() + " " + c.getLastName()));

小結

本章的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
public class Bar {
 public static void main(String[] args) {
//    long validContactCounter = contactList.parallelStream()
//    .map(s -> new Contact().setFirstName(s))
//    .filter(Contact::call)
//    .count();
  List<Contact> contacts = new ArrayList<Contact>() {{
   add(new Contact().setFirstName("Foo").setLastName("Jack"));
   add(new Contact().setFirstName("Bar").setLastName("Ma"));
   add(new Contact().setFirstName("Olala").setLastName("Awesome"));
  }};
  Comparator<Contact> byFirstName = new Comparator<Contact>() {
   @Override
   public int compare(Contact o1, Contact o2) {
    return Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));
   }
  };
  //--- Using Lambda form ---//
  Comparator<Contact> byFirstNameLambdaForm = (o1, o2) ->
    Character.compare(o1.getFirstName().charAt(0), o2.getFirstName().charAt(0));
  Function<Contact, Character> keyExtractor = o -> o.getFirstName().charAt(0);
  Comparator<Character> keyComparator = (c1, c2) ->
    Character.compare(c1, c2);
  Comparator<Contact> byFirstNameAdvanced = (o1, o2) ->
    keyComparator.compare(keyExtractor.apply(o1), keyExtractor.apply(o2));
  Comparator<Contact> compareByFirstName = Comparator.comparing(keyExtractor);
  Comparator<Contact> compareByNameLength = Comparator.comparing(p -> (p.getFirstName() + p.getLastName()).length());
  contacts.stream()
    .sorted(compareByNameLength)
    .forEach(c -> System.out.println(c.getFirstName() + " " + c.getLastName()));
 }
}

以及運行結果:

?
1
2
3
Bar Ma
Foo Jack
Olala Awesome

以上所述是小編給大家介紹的Java中Lambda表達式并行與組合行為,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:http://www.cnblogs.com/hwding/p/6398361.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 脱jk裙的美女露小内内无遮挡 | 免费港剧在线观看港剧 | 无码人妻99久久密AV | 末代皇帝无删减版在线观看 | 欧美一区二区视频 | 91外围 | 三年片韩国在线观看 | 香蕉国产人午夜视频在线观看 | 91精品国产综合久久精品 | 欧美日本一道高清二区三区 | 91噜噜噜噜色 | 99re在线视频观看 | 久久精品亚洲热综合一本 | 99久久精品无码一区二区毛片 | 亚洲天堂免费 | 国产日日操 | 美女18隐私羞羞视频网站 | 婷婷99视频精品全部在线观看 | 日韩国产成人精品视频人 | 久久免费观看视频 | 日本熟hdx | 99热这里只有精品国产在热久久 | 精品人伦一区二区三区潘金莲 | 男人日女人的b | 四虎影院com | 欧美日韩亚洲国内综合网俺 | 国产一卡二卡3卡4卡四卡在线 | 91国产在线播放 | 爽好舒服快想要免费看 | 国产成人高清视频 | 大香焦在线观看 | 我年轻漂亮的继坶2中字在线播放 | 欧美日韩亚洲一区二区三区在线观看 | 色综合 成人 | 色综久久天天综合绕视看 | 91尤物在线视频 | 青青草国产免费国产是公开 | 成人在线免费观看视频 | 精品一区二区三区色花堂 | 色综合久久六月婷婷中文字幕 | 农夫成人网 |