java8-Stream流【轉】

Stream是Java 8中引入的一個新的抽象層。 Stream 是對集合(Collection)對象功能的加強,它專一於對集合對象進行各類很是便利、高效的聚合操做(aggregate operation),或者大批量數據操做 (bulk data operation)。 Stream API 藉助於一樣新出現的 Lambda 表達式,極大的提升編程效率和程序可讀性。同時它提供串行和並行兩種模式進行匯聚操做,併發模式可以充分利用多核處理器的優點 Stream 不是集合元素,它不是數據結構並不保存數據,它是有關算法和計算的,它更像一個高級版本的 Iterator。獲取一個數據源(source)→ 數據轉換→執行操做獲取想要的結果,每次轉換原有 Stream 對象不改變,返回一個新的 Stream 對象(能夠有多 使用流,能夠以相似於SQL語句的聲明方式來處理數據。例如,如下SQL語句 SELECT max(salary),employee_id,employee_name FROM Employee 上述SQL表達式自動返回最高受薪僱員的詳細信息,而不須要客戶端作任何事情。在Java中使用集合框架,開發人員必須使用循環並進行重複檢查。 另外一個問題是效率;因爲如今的電腦基本都是多核處理器,所以Java開發人員能夠編寫並行代碼處理,可是每每會出錯 爲了解決這些問題,Java 8引入了流的概念,讓開發人員以聲明方式處理數據,並利用多核架構,而無需爲其編寫任何特定的代碼。 (代碼簡潔+多核處理) stream並非某種數據結構並不保存數據,它是有關算法和計算的,它更像一個高級版本的 Iterator。獲取一個數據源(source)→ 數據轉換→執行操做獲取想要的結果,每次轉換原有 Stream 對象不改變,返回一個新的 Stream 對象(能夠有屢次轉換),這就容許對其操做能夠像鏈條同樣排列,變成一個管道,它只是數據源的一種視圖。這裏的數據源能夠是一個數組,Java容器或I/O channel等。正因如此要獲得一個stream一般不會手動建立,而是調用對應的工具方法,好比:
  • 調用Collection.stream()或者Collection.parallelStream()方法
  • 調用Arrays.stream(T[] array)方法
經常使用的四種stream接口繼承關係以下圖: 圖中4種stream接口繼承自 BaseStream,其中 IntStream, LongStream, DoubleStream對應三種基本類型( int, long, double,注意不是包裝類型), Stream對應全部剩餘類型的stream視圖。爲不一樣數據類型設置不一樣stream接口,能夠1.提升性能,2.增長特定接口函數 你可能會奇怪爲何不把 IntStream等設計成 Stream的子接口?畢竟這接口中的方法名大部分是同樣的。答案是這些方法的名字雖然相同,可是返回類型不一樣,若是設計成父子接口關係,這些方法將不能共存,由於Java不容許只有返回類型不一樣的方法重載。 雖然大部分狀況下stream是容器調用 Collection.stream()方法獲得的,但stream和collections有如下不一樣:
  • 無存儲。stream不是一種數據結構,它只是某種數據源的一個視圖,數據源能夠是一個數組,Java容器或I/O channel等。
  • 爲函數式編程而生。對stream的任何修改都不會修改背後的數據源,好比對stream執行過濾操做並不會刪除被過濾的元素,而是會產生一個不包含被過濾元素的新stream。(從新生成+副本)
  • 惰式執行。stream上的操做並不會當即執行,只有等到用戶真正須要結果的時候纔會執行。(中間操做和結束操做)
  • 可消費性。stream只能被「消費」一次,一旦遍歷過就會失效,就像容器的迭代器那樣,想要再次遍歷必須從新生成。
count = strings.stream().filter(string -> string.isEmpty()).count();//filter裏面是定義好的規則 其參數就是predicate
System.out.println("Empty Strings: " + count);
 
count = strings.stream().filter(string -> string.length() == 3).count();
System.out.println("Strings of length 3: " + count);
每次使用都是從新調用stream() 對stream的操做分爲爲兩類,中間操做(intermediate operations)和結束操做(terminal operations),兩者特色是:
  1. 中間操做老是會惰式執行,調用中間操做只會生成一個標記了該操做的新stream,僅此而已。
  2. 結束操做會觸發實際計算,計算髮生時會把全部中間操做積攢的操做以pipeline的方式執行,這樣能夠減小迭代次數。計算完成以後stream就會失效。下表彙總了Stream接口的部分常見方法:
操做類型 接口方法
中間操做 concat() distinct() filter() flatMap() limit() map() peek() skip() sorted() parallel() sequential() unordered()
結束操做 allMatch() anyMatch() collect() count() findAny() findFirst() forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()
  爲何不在集合類實現這些操做,而是定義了全新的Stream API?Oracle官方給出了幾個重要緣由: 一是集合類持有的全部元素都是存儲在內存中的,很是巨大的集合類會佔用大量的內存,而Stream的元素倒是在訪問的時候才被計算出來,這種「延遲計算」的特性有點相似Clojure的lazy-seq,佔用內存不多。 二是集合類的迭代邏輯是調用者負責,一般是 for循環,而Stream的迭代是隱含在對Stream的各類操做中,例如 map()。 對於基本數值型,目前有三種對應的包裝類型 Stream:IntStream、LongStream、DoubleStream。 關鍵字: filter:是一箇中間操做,接受一個predicate接口類型的變量,並將全部流對象中的元素進行過濾。filter(s -> s.getState()==State.pay) map:是一個對於流對象的中間操做,經過給定的方法,它可以把流對象中的每個元素對應到另一個對象上。map(s -> s.getPlanNo()) / map(s -> Plan::planNo)  /  價格變成    10倍 map(s -> s.getPrice().multiply(BigDecimal.valueOf(10))) reduce:把 Stream 元素組合起來。它提供一個起始值(種子),而後依照運算規則(BinaryOperator),返回單個的結果值,而且reduce操做每處理一個元素老是建立一個新值 BigDecimal total = stream().reduce(BigDecimal.zero, (a,b) -> a.add(b));   或 BigDecimal total = stream().reduce(BigDecimal.ZERO, BigDecimal::add) limit : 返回 Stream 的前面 n 個元素;skip 則是扔掉前 n 個元素 sorted: 一箇中間操做,可以返回一個排過序的流對象的視圖。流對象中的元素會默認按照天然順序進行排序,除非你本身指定一個Comparator接口來改變排序規則. collect: 修改現存的值 Collectors 類的主要做用就是輔助進行各種有用的 reduction 操做 groupingBy  按規則分組:stream().collect(Collectors.groupingBy(p->p.getState())) partitioningBy 是一種特殊的 groupingBy,它依照條件測試的是否兩種結果來構造返回的數據結構,get(true) 和 get(false) 能即爲所有的元素對象。 Stream 有三個 match 方法,從語義上說: allMatch:Stream 中所有元素符合傳入的 predicate,返回 true anyMatch:Stream 中只要有一個元素符合傳入的 predicate,返回 true noneMatch:Stream 中沒有一個元素符合傳入的 predicate,返回 true
相關文章
相關標籤/搜索