Google Code Prettify

2020年11月2日 星期一

Java Stream: operation

 本篇參見【Modern Java in Action】 2nd-edition


Stream 提供了如上表的 operation,要怎麼使用呢? 直接看例子吧~

假設一個場景,客戶進行證券交易,這裡記錄下客戶在某年交易的金額及客戶的基本資料 (姓名、年齡、居住城市),資料如下:

Customer steven = new Customer("Steven", 50, "New Taipei");
Customer shelley = new Customer("Shelley", 48, "Taichung");
Customer mark = new Customer("Mark", 53, "Taipei");
Customer kfc = new Customer("KFC", 38, "Taipei");
Customer clair = new Customer("Clair", 26, "Yunlin");
	
List<Trade> trades = Arrays.asList(
		new Trade(steven, 2018, 350000),
		new Trade(shelley, 2018, 535000),
		new Trade(mark, 2018, 1005000),
		new Trade(kfc, 2018, 810000),
		new Trade(clair, 2018, 559000),
		new Trade(steven, 2019, 67000),
		new Trade(mark, 2019, 890100),
		new Trade(clair, 2019, 90900)
	);
  1. 2018年的所有交易,按交易額排序:
  2. trades.stream()
    	.filter(t -> t.getYear() == 2018)
    	.sorted(comparing(Trade::getAmount))
    	.forEach(t -> log.info(t.toString()));
    
    得到如下結果,filter 過濾出 2018 年的交易 (Trade),以 amount 排序,從結果可以看到這些交易是那個客戶交易的。
    Trade(cTrade(cstm=Customer(name=Steven, age=50, city=New Taipei), year=2018, amount=350000) Trade(cstm=Customer(name=Shelley, age=48, city=Taichung), year=2018, amount=535000) Trade(cstm=Customer(name=Clair, age=26, city=Yunlin), year=2018, amount=559000) Trade(cstm=Customer(name=KFC, age=38, city=Taipei), year=2018, amount=810000) Trade(cstm=Customer(name=Mark, age=53, city=Taipei), year=2018, amount=1005000)
  3. 所有客戶分布於那些城市?
  4. trades.stream()
    	.map(t -> t.getCstm().getCity())
    	.distinct()
    	.forEach(t -> log.info(t.toString()));
    
    用 map 指出要保留的欄位,distinct() 表示重複的只會列出一筆。
    New Taipei
    Taichung
    Taipei
    Yunlin
  5. 列出住台北市的客戶,並以年齡排序:
  6. trades.stream()
    	.filter(t -> t.getCstm().getCity().equals("Taipei"))
    	.map(t -> t.getCstm())
    	.distinct()
    	.sorted(comparing(Customer::getAge))
    	.forEach(t -> log.info(t.toString()));
    
    Customer(name=KFC, age=38, city=Taipei)
    Customer(name=Mark, age=53, city=Taipei)
  7. 住台北市的客戶的交易量總和?
  8. int total = trades.stream()
    	.filter(t -> t.getCstm().getCity().equals("Taipei"))
    	.map(t -> t.getAmount())
    	.reduce(0, Integer::sum);
    log.info("total = " + total);
    
    total = 2705100
    上面的寫法會有個「封裝」的成本,int 被封裝成 Integer,或 Integer 拆裝成 int 都會需要一點點時間。為了解決這個問題,Stream 提供了 IntStream、DoubleStream、LongStream 三個原始型別的串流,那麼上面的程式可以改寫成如下:
    int total = trades.stream()
    	.filter(t -> t.getCstm().getCity().equals("Taipei"))
    	.mapToInt(Trade::getAmount)
    	.sum();
    
  9. 歷年來所有交易中,最大的一筆交易的交易量?
  10. Optional<Integer> optTotal = trades.stream()
    	.map(t -> t.getAmount())
    	.reduce(Integer::max);
    	
    if (optTotal.isPresent()) {
    	int total = optTotal.get();
    	log.info("total = " + total);
    }
    else {
    	log.info("data not found");
    }
    
    使用 reduce() 可以將資料歸納,這裡指出要資料中最大的。
    total = 1005000

【番外篇】
Arrays.asList(...) 產生的 List 會是固定大小,上面的 trades 中的元素可以更改,但是,如果要加入新元素,例如: trades.add(new Trade()); 會拋出 UnsupportedModificationException

沒有留言:

張貼留言