對於java8 新規範中Stream的瞭解

  • [摘要]

java8已經推出很久時間了,其中最令人振奮的要數lambda表達式和stream這兩個特性了。這篇文章主要講一下關於java8中Stream的相關內容。
首先,流是java8的一大亮點,它用來專注於對容器對象進行各種便利的、高效的聚合操作,或者大批量的數據操作。Stream API
結合一起出現的lambda表達式,極大地提升了編程效率和可讀性。

  • [ 聚合操作的概念]
  • 什麼是聚合操作?

有過java開發經驗的童鞋就非常清楚,我們平時在傳統的j2ee應用中,java代碼通常要通過關係型數據庫的聚合操作來完成一些事情。如: 總金額計算,平均值計算,最大值最小值,本週或者本月完成的有效訂單等等。
這類操作在現今數據爆炸的社會,我們如果總是要通過數據庫來完成(java代碼中往往是通過遍歷,或者iterator,顯然顯得很笨重),所以stream的出現,也可以說是應運而生。
在Java7中,如果要發現type爲grocery的所有交易,然後返回以交易值降序排序好的交易ID集合,我們需要這樣寫:

List<Transaction> groceryTransactions = new Arraylist<>();
   for(Transaction t: transactions){  if(t.getType() ==
   Transaction.GROCERY){  groceryTransactions.add(t);  } }
   
   Collections.sort(groceryTransactions, new Comparator(){  public int
   compare(Transaction t1, Transaction t2){  return
   t2.getValue().compareTo(t1.getValue());  } });
   
   List<Integer> transactionIds = new ArrayList<>(); for(Transaction t:
   groceryTransactions){  transactionsIds.add(t.getId()); }

可是在java8中,我們可以使用Stream,代碼將會變得更加簡單易讀,甚至可以使用併發模式,提高程序運行效率。如下:

List<Integer> transactionsIds = transactions.parallelStream()
.filter(t -> t.getType() == Transaction.GROCERY)
.sorted(comparing(Transaction::getValue).reversed())
.map(Transaction::getId).collect(toList());

怎麼樣?是不是很簡單?
這正是java官方推出的新模式。大家都知道,java是一門強邏輯語言,要求語法嚴密,細節到位,這往往會帶來語言本身上的一些劣勢,比如代碼繁多,瑣碎,不利於長期發展。尤其是如今python、php等等語言異軍突起。相比而言,java的門檻和難度都相對較高。stream和lambda表達式、以及函數接口,函數式變成等思想,都是從別的語言中借鑑而來的。java是一個時代的產物,自然也要與時俱進。而在這樣的背景下,我們所要做的,也是順應時代的發展,好好去學習這些新東西。
言歸正傳,讓我們來簡單瞭解一下,java8一些比較典型的專注聚合操作的api。

  • [ Stream API]

anyMatch()、allMatch()、noneMatch()操作,從字面上,我們可以猜出,他們大概是match——匹配的意思,然而事實上,也確實是如此。這三個都是函數式接口,返回值是boolean。這也是java的新特性之一,如果瞭解函數式接口的定義,請參看這一篇大神的博客—https://blog.csdn.net/qq_28410283/article/details/80601495
那麼,這裏說下具體用途:

anyMatch——表示集合中的所有元素,只要有任意一個符合要求的,那麼就返回true。
allMatch—— 表示集合中所有的元素,都要滿足要求,纔會返回true,否則返回false。
noneMatch——這個就跟allMatch剛好相反,集合裏面的元素,剛好全部都不滿足條件,返回true,否則則返回false。舉例子如下:

List<String> strs = Arrays.asList("a", "a", "a", "a", "b");
boolean aa = strs.stream().anyMatch(str -> str.equals("a"));
boolean bb = strs.stream().allMatch(str -> str.equals("a"));
boolean cc = strs.stream().noneMatch(str -> str.equals("a"));
long count = strs.stream().filter(str -> str.equals("a")).count();
System.out.println(aa);// TRUE
System.out.println(bb);// FALSE
System.out.println(cc);// FALSE
System.out.println(count);// 4

② distinct(),empty()方法,這兩個方法也能從字面上瞭解意思。distinct()用戶對集合去重。empty()則是創建一個空流。

String[] strings = {"a", "a", "b", "c", "d", "d"};
List<String> list = Arrays.asList(strings);
String collect = list.stream().distinct().collect(Collectors.joining(","));
//空流 ,一個空的順序Stream,該Stream裏面不包含元素項
Stream<Object> empty = Stream.empty();//emmmmm,至於空Stream有啥作用,從api上我也看不出來,希望有高手點撥

③filter()、map()方法,這兩個方法是中間處理過程的方法。
filter()是在對集合每個元素之間進行一道邏輯處理程序(可以看做是一個過濾器,事實上通常的運用也就是來做元素過濾的)。
而map()方法則是一個映射方法,這個方法經常會在兩個不同對象集合中進行對象的轉換和組裝的時候用到。比如,講一個List 轉化爲 List 中。person肯定包含women,但是在轉化爲women的時候,也要進行一道工序。這個時候就可以使用map()方法。此方法的好處是可以針對一個集合直接進行轉化,而不需要遍歷。

//person類list中,去掉年齡超過50歲的,可以使用filter()方法輕鬆實現
 List<Person>  youngPersonList = allPersonList.Stream().filter(item -> item.getAge()<50).collect(Collectors.toList());
 
//convertPersonToWomen是Person轉化爲Women的業務方法
List<Women> womens=person.stream().map(StreamMap::convertPersonToWomen)
.collect(Collectors.toList())

④mapToInt(),mapTolong(),mapToDouble() ,這三個方法是屬於同一性質的。用戶將list中的元素的對應類型的屬性值聚集成某種特定的類型的stream。在這個基礎上,我們可以對這個stream進行自己想要的操作。比如求平均值,求和等等。

//對people的年齡屬性求和
  int sum = people.stream()
                  .mapToInt(p -> p.getAge())
                  .sum();
        System.out.println("Total of ages " + sum);
        
//對people的年齡屬性求平均數
OptionalDouble avg = people.stream()
                .mapToInt(p -> p.getAge())
                .average();
if (avg.isPresent()) {
    System.out.println("Average: " + avg);
} else {
    System.out.println("average wasn't calculated");
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章