Google Code Prettify

2020年10月4日 星期日

Java Stream: Creation

繼上一篇「Java Stream: getting started」後,這裡整理 stream 生成的幾種方式。

  1. of
  2. Stream week = Stream.of("日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日");
    log.debug("count = " + week.count());
    
    如上,使用 of 產生 stream,上面經過 count 方法後,會 output 出 7。
  3. Arrays
  4. Arrays.stream(new String[] { "日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日" }, 2, 4)
    	.forEach(w -> log.debug(w));
    
    這個方法,可以從陣列中截取一段產生 stream,上面會輸出 "火曜日"、"水曜日"。
  5. generate
  6. Stream.generate(Math::random).forEach(s -> log.info("number = " + s));
    
    使用 generate 會生成無限長度的 stream,如上,會一直輸出亂數。所以,通常會配合 limit 使用。
    Stream.iterate(BigInteger.ZERO, n -> n.compareTo(BigInteger.valueOf(10)) < 0, n -> n.add(BigInteger.ONE)).forEach(i -> log.debug("integer = " + i));
    Stream.iterate(BigInteger.ZERO, n -> n.add(BigInteger.ONE)).limit(10).forEach(i -> log.debug("integer = " + i));
    
    上面兩種方法可以得到相同結果,都是輸出 0 ~ 9。

2020年10月3日 星期六

Java Stream: getting started

 stream 是 Java 8 新增的功能,現在 Java 已經到 15 了,但是 ... stream 似乎也沒有很普及,這裡試著整理一些基礎用法。

File resource = new ClassPathResource("data/employee.txt").getFile();
var lines = Files.readAllLines(resource.toPath(), StandardCharsets.UTF_8);
lines.stream().filter(s -> s.compareTo("1000000") > 0).forEach(s -> log.info(s));
【說明】
  1. 在 src/main/resources 目錄裡,我建了一個子目錄 data,裡面放的 employee.txt 只是一些員工編號。
  2. Files.readAllLines 可以將文字檔資料讀入,並以每一行一個 String 的方式,存在 List<String> 裡,在 Java 10 開始提供了 var 這個關鍵字,程式員可以不需要寫明型別由 java 自行判斷,將滑鼠移到 var 上,eclipse 就會顯示出正確的型別了。
  3. 所有資料存於 lines,先以 stream() 將它轉成串流,接著就可以用 stream 提供的一些方法操作。第 3 行是先透過 filter 篩選出員編大於 "1000000" 的資料,再透過 forEach 印出來。
如果資料量很大,上面的 stream() 可以改為 parallelStream(),就會以多執行緒的方式處理。一般寫 stream 的程式,步驟如下:
  1. create 一個 stream
  2. 使用 stream 的一些方法操作 stream 的內容 (可能會有多個方法一連串的操作)
  3. 在最後一個方法中,產生出結果。
感覺上 stream 很像 collection ? 以下是主要的差異:
  1. stream 沒有儲存這些資料,它只是在處理資料,以上面的例子來說,資料儲存在 List<String> 裡,轉換成 stream 並沒有另外存一份。
  2. stream 處理資料的過程不會變更原有資料,如上面,log 顯示出結果後,原本的 lines 裡的資料不會被改變。
  3. 上面的例子比較簡單,常常看到的會是串接好幾個方法,stream 會試圖延遲這些方法的執行,直到最後真的得執行時才全部的方法一次執行,如上例就是在 forEach 才會執行 filter。