1. 程式人生 > 程式設計 >java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作

java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作

java lambda迴圈

對於每個經常需要在Java 8(或更高版本)中使用多維陣列的人來說,這只是一個快速技巧。

在這種情況下,您可能經常會以類似於以下程式碼的結尾:

float[][] values = ...
for (int i = 0; i < values.length; i++) {
 for (int k = 0; k < values[i].length; k++) {
 float value = values[i][k];
 // do something with i,k and value
 }
}

如果幸運的話,可以用for-each迴圈替換迴圈。 但是,迴圈內的計算通常需要索引。

在這種情況下,您可以提出一個簡單的實用程式方法,如下所示:

private void loop(float[][] values,BiConsumer<Integer,Integer> consumer) {
 for (int i = 0; i < values.length; i++) {
 for (int k = 0; k < values[i].length; k++) {
 consumer.accept(i,k);
 }
 }
}

現在,我們可以像這樣迴圈遍歷陣列索引:

float[][] values = ...
loop(values,(i,k) -> {
 float value = values[i][k];
 // do something with i,k and value
});

這樣,您可以使迴圈程式碼脫離主要邏輯。

當然,您應該更改所示的loop()方法,使其適合您的個人需求。

翻譯自: https://www.javacodegeeks.com/2016/04/simplifying-nested-loops-java-8-lambdas.html

補充知識:JAVA8-lambda表示式-並行流,提升效率的利器?

寫在前面的話

在前面我們已經看過了一些流的處理,那麼Lambda除了在寫法上的不同,還有其它什麼作用呢?當然有,就是資料並行化處理!

它在某些場景下可以提高程式的效能。我們先看一個前面的例子,查詢所有的男同學

// 流方式

List<Person> newBoys = personList.stream().filter(p -> 1 == p.getSex()).collect(Collectors.toList());

現在用並行流改寫一下

// 流方式:找出所有男同學

List<Person> newBoys = personList.parallelStream().filter(p -> 1 == p.getSex()).collect(Collectors.toList());

細心的同學已經發現區別了,stream與parallelStream,是的,要用並行流parallelStream,就是這麼簡單!

什麼是並行

有必要嘗試解釋一下,什麼是資料並行化

Java支援多執行緒,可以同時開啟多個任務。引入多執行緒的原因在於,執行緒可能會阻塞,CPU會主動切分時間片,只有分配到時間片的執行緒才會執行。而現代的處理器,幾乎都是多核的,即多個CPU,如何才能更高效的利用硬體呢,多執行緒。

並行和多執行緒是有區別的,比如運送一堆貨物,如果只有一輛車(單執行緒),肯定慢,平時如果貨少,那還能應付過來 ,如果比如某寶的"雙十一",那就肯定快遞像垃圾一樣如山,怎麼辦呢?我們可以增加車輛(多執行緒),那麼肯定能加快運送速度。但是有一個前提,必須是多條道(多核CPU)。而在有些只有單個出口的地方,還必須排隊(併發,執行緒安全)

而並行的針對同一個任務的。比如還是一輛車的貨,10000件,全部放在A車上,要跑N個小時。現在取出一半放到B車上,理論上A,B2車同時跑,是不是會理快呢?嘿嘿嘿,這就是說的資料並行化,這裡不會涉及併發。而這一切,Java8的並行流都在底層幫我們實現了

一定會更快?

紙上得來終覺淺,絕知此事要躬行!我們來看下,前面2個程式碼的分別執行時間

@Test
 public void test() {
 
 // 資料並行化處理
 // 學生集合
 Person kobe = new Person("kobe",40,1);
 Person jordan = new Person("jordan",50,1);
 Person mess = new Person("mess",20,2);
 List<Person> personList = Arrays.asList(kobe,jordan,mess);
 
 long beginTime = System.currentTimeMillis();
 
 // 原來的方式
 List<Person> oldBoys = new ArrayList<>(personList.size());
 for (Person p : personList) {
  // 性別男
  if (p.getSex() == 1) {
  oldBoys.add(p);
  }
 }
 long endTime = System.currentTimeMillis();
 log.info("原來的方式 take time:" + (endTime - beginTime));
 
 beginTime = System.currentTimeMillis();
 // 流方式:找出所有男同學
 List<Person> newBoys = personList.stream()
 .filter(p -> 1 == p.getSex())
 .collect(Collectors.toList());
 
 endTime = System.currentTimeMillis();
 log.info("流方式 take time:" + (endTime - beginTime));
 
 
 beginTime = System.currentTimeMillis();
 // 流方式:找出所有男同學
 List<Person> parallelBoys = personList.parallelStream()
 .filter(p -> 1 == p.getSex())
 .collect(Collectors.toList());
 
 endTime = System.currentTimeMillis();
 log.info("並行流方式 take time:" + (endTime - beginTime));
 }

java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作

咦,是不是很奇怪,原來的for迴圈方式最快?多執行幾次,發現結果也是這樣的,那真是這樣嗎,我們把資料量擴大試試

java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作

還是更慢,換個方法試試

@Test
	public void test() {
 
		// 學生集合
		List<Person> personList = new ArrayList<>(1000000);
		for (int i = 0,j = 1000000; i < j; i++) {
			int sex = i % 2;
			Person p = new Person(String.valueOf(i),i,sex);
			personList.add(p);
		}
 
		long beginTime2 = System.currentTimeMillis();
		// 流方式:年齡之和
		int parallelAges = personList.parallelStream().mapToInt(p -> p.getAge()).sum();
 
		long endTime2 = System.currentTimeMillis();
		log.info("並行流方式 take time:" + (endTime2 - beginTime2));
		log.info("parallelAges:" + parallelAges);
 
		long beginTime = System.currentTimeMillis();
 
		// 原來的方式
		int totalAge = 0;
		for (Person p : personList) {
			// 年齡之和
			totalAge = totalAge + p.getAge();
		}
		long endTime = System.currentTimeMillis();
		log.info("原來的方式 take time:" + (endTime - beginTime));
		log.info("totalAge:" + totalAge);
 
	}

看看結果,還是更慢。。。這倒很出我意外,崩潰了,

java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作

可能跟我機器有關吧。所以還是需要找地方驗證,如果哪位同學能解答一下,歡迎指教

這裡引用一下《java8函數語言程式設計》的結論

java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作

一些條件

輸入資料的大小。

理論上輸入的資料越大,操作越複雜,並行流的效果越好。因為拆分資料處理,最後合併結果都會帶來額外的開銷。我們可以通過修改前面的例子,personList的大小來觀察

java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作

可以看到,資料越大,並行效果越好。當然,真實專案中的處理遠比上面複雜,而超過1000w的資料,我本地機器就OOM了尷尬

資料結構

我們通常是操作集合。一般來說,越好分割的並行速度越快。比如ArrayList,陣列等支援隨機讀取的,效果較好。

HashSet,TreeSet,這類不容易公平的分解。而LinkedList,Stream.iterator等分解就比較困難的,效果是比較差的

裝箱

處理包裝類比基本型別花的時間多,肉眼可見

核的數量

當然,如果核的數量越多,獲得潛在並行提升速度的趕快。比如4核一般比雙核快,對吧

以上這篇java lambda迴圈_使用Java 8 Lambda簡化巢狀迴圈操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。