1.3 Lambda中的streamhtml
所謂 「Lambda 表達式」(lambda expression)它是一個匿名函數,Lambda表達式基於數學中的λ演算得名,直接對應於其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。Lambda表達式能夠表示閉包(注意和數學傳統意義上的不一樣)。若是想深刻能夠去這位仁兄的博客看看 點我進去 這裏作個瞭解。java
認準 " - > " Lambad 老字號算法
可選類型聲明:不須要聲明參數類型,編譯器能夠統一識別參數值。 express
可選的參數圓括號:一個參數無需定義圓括號,但多個參數須要定義圓括號。數組
可選的大括號:若是主體包含了一個語句,就不須要使用大括號。 數據結構
可選的返回關鍵字:若是主體只有一個表達式返回值則編譯器會自動返回值,大括號須要指定明表達式返回了一個數值。閉包
在 Lambda 表達式當中不容許聲明一個與局部變量同名的參數或者局部變量。框架
String first = "";
Comparator<String> comparator = (first, second) -> Integer.compare(first.length(), second.length()); //編譯會出錯
從語法特徵分析出的傻白甜代碼片斷 ide
// 1. 不須要參數,返回值爲 5
() -> 5
// 2. 接收一個參數(數字類型),返回其2倍的值
x -> 2 * x
// 3. 接受2個參數(數字),並返回他們的差值
(x, y) -> x – y
// 4. 接收2個int型整數,返回他們的和
(int x, int y) -> x + y
// 5. 接受一個 string 對象,並在控制檯打印,不返回任何值(看起來像是返回void)
(String s) -> System.out.print(s)
public class Java8Tester {
public static void main(String args[]){
Java8Tester tester = new Java8Tester();
// 類型聲明
MathOperation addition = (int a, int b) -> a + b;
// 不用類型聲明
MathOperation subtraction = (a, b) -> a - b;
// 大括號中的返回語句
MathOperation multiplication = (int a, int b) -> { return a * b; };
// 沒有大括號及返回語句
MathOperation division = (int a, int b) -> a / b;
System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
System.out.println("10 / 5 = " + tester.operate(10, 5, division));
// 不用括號
GreetingService greetService1 = message ->
System.out.println("Hello " + message);
// 用括號
GreetingService greetService2 = (message) ->
System.out.println("Hello " + message);
greetService1.sayMessage("Runoob");
greetService2.sayMessage("Google");
}
interface MathOperation {
int operation(int a, int b);
}
interface GreetingService {
void sayMessage(String message);
}
private int operate(int a, int b, MathOperation mathOperation){
return mathOperation.operation(a, b);
}
}
使用 ( ) - { } 來代替匿名類 代碼來自這位仁兄 點我進去
//未使用Lambda
Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println("no use lambda"); } });
//使用以後 Thread t2 = new Thread(() -> System.out.println("use lambda"));
咱們看到相對而言Lambda表達式要比匿名類要優雅簡潔不少~。
List<Integer> integers = Arrays.asList(4, 5, 6,1, 2, 3,7, 8,8,9,10);
List<Integer> evens = integers.stream().filter(i -> i % 2 == 0)
.collect(Collectors.toList()); //過濾出偶數列表 [4,6,8,8,10]<br>
List<Integer> sortIntegers = integers.stream().sorted()
.limit(5).collect(Collectors.toList());//排序而且提取出前5個元素 [1,2,3,4,5]
List<Integer> squareList = integers.stream().map(i -> i * i).collect(Collectors.toList());//轉成平方列表
int sum = integers.stream().mapToInt(Integer::intValue).sum();//求和
Set<Integer> integersSet = integers.stream().collect(Collectors.toSet());//轉成其它數據結構好比set
Map<Boolean, List<Integer>> listMap = integers.stream().collect(Collectors.groupingBy(i -> i % 2 == 0)); //根據奇偶性分組
List<Integer> list = integers.stream().filter(i -> i % 2 == 0).map(i -> i * i).distinct().collect(Collectors.toList());//複合操做
在java 8 中 Stream 不是集合元素,它不保存數據,它是有關算法和計算的,它更像一個高級版本的 Iterator。原始版本的 Iterator,用戶只能顯式地一個一個遍歷元素並對其執行某些操做;高級版本的 Stream,用戶只要給出須要對其包含的元素執行什麼操做,好比 「過濾掉長度大於 10 的字符串」、「獲取每一個字符串的首字母」等,Stream 會隱式地在內部進行遍歷,作出相應的數據轉換。
Stream 就如同一個迭代器(Iterator),單向,不可往復,數據只能遍歷一次,遍歷過一次後即用盡了,就比如流水從面前流過,一去不復返。而和迭代器又不一樣的是,Stream 能夠並行化操做,迭代器只能命令式地、串行化操做。顧名思義,當使用串行方式去遍歷時,每一個 item 讀完後再讀下一個 item。而使用並行去遍歷時,數據會被分紅多個段,其中每個都在不一樣的線程中處理,而後將結果一塊兒輸出。Stream 的並行操做依賴於 Java7 中引入的 Fork/Join 框架(JSR166y)來拆分任務和加速處理過程。
甚至函數 由值建立流:
Stream<String> stream = Stream.of("Java 8 ", "Lambdas ", "In ", "Action");
由數組建立流:
int[] numbers = {2, 3, 5, 7, 11, 13}; int sum = Arrays.stream(numbers).sum();
外部迭代:描述怎麼幹,代碼裏嵌套2個以上的for循環的都比較難讀懂;只能順序處理List中的元素;
內部迭代:描述要幹什麼,而不是怎麼幹;不必定須要順序處理List中的元素
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
System.out.println(feature); //外部迭代
}
List features = Arrays.asList("Lambdas", "Default Method", "Stream API",
"Date and Time API");
features.stream.forEach(n -> System.out.println(n)); //內部迭代
Lambda的並行流雖好,但也要注意使用場景。若是日常的業務處理好比過濾,提取數據,沒有涉及特別大的數據和耗時操做,則真的不須要開啓並行流。我在工做中看到有些人一個只有幾十個元素的列表的過濾操做也開啓了並行流,其實這樣作會更慢。由於多行線程的開啓和同步這些花費的時間每每比你真實的處理時間要多不少。但一些耗時的操做好比I/O訪問,DB查詢,遠程調用,這些若是能夠並行的話,則開啓並行流是可提高很大性能的。由於並行流的底層原理是fork/join,若是你的數據分塊不是很好切分,也不建議開啓並行流。舉個例子ArrayList的Stream能夠開啓並行流,而LinkedList則不建議,由於LinkedList每次作數據切分要遍歷整個鏈表,這自己就已經很浪費性能,而ArrayList則不會。
有篇來自 發佈在 jaxenter 的調查報告 《How misusing Streams can make your code 5 times slower》
原文地址 點我進去 中文翻譯版 點我進去 此文用代碼實驗得出了一個結論 若是你要進行stream操做 使用 iterators and for-each 效率更高