Java8 新特性之集合操做Stream

Java8 新特性之集合操做Streamjava

 

 

Stream簡介

 

  • Java 8引入了全新的Stream API。這裏的Stream和I/O流不一樣,它更像具備Iterable的集合類,但行爲和集合類又有所不一樣。
  • stream是對集合對象功能的加強,它專一於對集合對象進行各類很是便利、高效的聚合操做,或者大批量數據操做。

爲何要使用Stream

  • 函數式編程帶來的好處尤其明顯。這種代碼更多地表達了業務邏輯的意圖,而不是它的實現機制。易讀的代碼也易於維護、更可靠、更不容易出錯。
  • 高端

 

使用實例:編程

測試數據:

public class Data { private static List<PersonModel> list = null; static { PersonModel wu = new PersonModel("wu qi", 18, "男"); PersonModel zhang = new PersonModel("zhang san", 19, "男"); PersonModel wang = new PersonModel("wang si", 20, "女"); PersonModel zhao = new PersonModel("zhao wu", 20, "男"); PersonModel chen = new PersonModel("chen liu", 21, "男"); list = Arrays.asList(wu, zhang, wang, zhao, chen); } public static List<PersonModel> getData() { return list; } } 

 

Filter

  • 遍歷數據並檢查其中的元素時使用。
  • filter接受一個函數做爲參數,該函數用Lambda表達式表示。
保留年齡爲 20 的 person 元素 list = list.stream() .filter(person -> person.getAge() == 20) .collect(toList()); 打印輸出 [Person{name='jack', age=20}]

 

/** * 過濾全部的男性 */
    public static void fiterSex(){ List<PersonModel> data = Data.getData(); //old
        List<PersonModel> temp=new ArrayList<>(); for (PersonModel person:data) { if ("男".equals(person.getSex())){ temp.add(person); } } System.out.println(temp); //new
        List<PersonModel> collect = data .stream() .filter(person -> "男".equals(person.getSex())) .collect(toList()); System.out.println(collect); } /** * 過濾全部的男性 而且小於20歲 */
    public static void fiterSexAndAge(){ List<PersonModel> data = Data.getData(); //old
        List<PersonModel> temp=new ArrayList<>(); for (PersonModel person:data) { if ("男".equals(person.getSex())&&person.getAge()<20){ temp.add(person); } } //new 1
        List<PersonModel> collect = data .stream() .filter(person -> { if ("男".equals(person.getSex())&&person.getAge()<20){ return true; } return false; }) .collect(toList()); //new 2
        List<PersonModel> collect1 = data .stream() .filter(person -> ("男".equals(person.getSex())&&person.getAge()<20)) .collect(toList()); }

 distinct()

去除重複元素,這個方法是經過類的 equals 方法來判斷兩個元素是否相等的api

如例子中的 Person 類,須要先定義好 equals 方法,否則相似[Person{name='jack', age=20}, Person{name='jack', age=20}] 這樣的狀況是不會處理的數據結構

 參考:https://blog.csdn.net/haiyoung/article/details/80934467

 

 

limit(long n)

 limit: 對一個Stream進行截斷操做,獲取其前N個元素,若是原Stream中包含的元素個數小於N,那就獲取其全部的元素;app

返回前 n 個元素 list = list.stream() .limit(2) .collect(toList()); 打印輸出 [Person{name='jack', age=20}, Person{name='mike', age=25}]

 

skip方法 :
skip: 返回一個丟棄原Stream的前N個元素後剩下元素組成的新Stream,若是原Stream中包含的元素個數小於N,那麼返回空Stream;ide

 

Map

  • map生成的是個一對一映射,for的做用
  • 比較經常使用

 

/** * 取出全部的用戶名字 */
    public static void getUserNameList(){ List<PersonModel> data = Data.getData(); //old
        List<String> list=new ArrayList<>(); for (PersonModel persion:data) { list.add(persion.getName()); } System.out.println(list); //new 1
        List<String> collect = data.stream().map(person -> person.getName()).collect(toList()); System.out.println(collect); //new 2
        List<String> collect1 = data.stream().map(PersonModel::getName).collect(toList()); System.out.println(collect1); //new 3
        List<String> collect2 = data.stream().map(person -> { System.out.println(person.getName()); return person.getName(); }).collect(toList()); }

 

filter 與 map 同時使用: 函數式編程

List<String> collect = users.stream().filter(item -> { if (!StringUtils.isEmpty(item.getUserName())) { return true; } return false; }).map(item -> item.getUserName()).collect(Collectors.toList());

 

 

FlatMap

  • 顧名思義,跟map差很少,更深層次的操做函數

  • 但仍是有區別的測試

  • map和flat返回值不一樣spa

  • Map 每一個輸入元素,都按照規則轉換成爲另一個元素。
    還有一些場景,是一對多映射關係的,這時須要 flatMap。

  • Map一對一

  • Flatmap一對多

  • map和flatMap的方法聲明是不同的

    • <r> Stream<r> map(Function mapper);
    • <r> Stream<r> flatMap(Function> mapper);
  • map和flatMap的區別:我我的認爲,flatMap的能夠處理更深層次的數據,入參爲多個list,結果能夠返回爲一個list,而map是一對一的,入參是多個list,結果返回必須是多個list。通俗的說,若是入參都是對象,那麼flatMap能夠操做對象裏面的對象,而map只能操做第一層。

 
public static void flatMapString() { List<PersonModel> data = Data.getData(); //返回類型不同
        List<String> collect = data.stream() .flatMap(person -> Arrays.stream(person.getName().split(" "))).collect(toList()); List<Stream<String>> collect1 = data.stream() .map(person -> Arrays.stream(person.getName().split(" "))).collect(toList()); //用map實現
        List<String> collect2 = data.stream() .map(person -> person.getName().split(" ")) .flatMap(Arrays::stream).collect(toList()); //另外一種方式
        List<String> collect3 = data.stream() .map(person -> person.getName().split(" ")) .flatMap(str -> Arrays.asList(str).stream()).collect(toList()); }

 map轉list:

Map<String, List<ProgrammeResult>> projectGroups = programmeResults.stream().collect(Collectors.groupingBy(ProgrammeResult::getProjectId)); List<ProgrammeResult> fhSuccessResult = projectGroups.entrySet().stream().flatMap(item -> item.getValue().stream()).collect(Collectors.toList());

 

 

Collect

  • collect在流中生成列表,map,等經常使用的數據結構
  • toList()
  • toSet()
  • toMap()

/** * toList */
    public static void toListTest(){ List<PersonModel> data = Data.getData(); List<String> collect = data.stream() .map(PersonModel::getName) .collect(Collectors.toList()); } /** * toSet */
    public static void toSetTest(){ List<PersonModel> data = Data.getData(); Set<String> collect = data.stream() .map(PersonModel::getName) .collect(Collectors.toSet()); } /** * toMap */
    public static void toMapTest(){ List<PersonModel> data = Data.getData(); Map<String, Integer> collect = data.stream() .collect( Collectors.toMap(PersonModel::getName, PersonModel::getAge) ); data.stream() .collect(Collectors.toMap(per->per.getName(), value->{ return value+"1"; })); } /** * 指定類型 */
    public static void toTreeSetTest(){ List<PersonModel> data = Data.getData(); TreeSet<PersonModel> collect = data.stream() .collect(Collectors.toCollection(TreeSet::new)); System.out.println(collect); } /** * 分組 */
    public static void toGroupTest(){ List<PersonModel> data = Data.getData(); Map<Boolean, List<PersonModel>> collect = data.stream() .collect(Collectors.groupingBy(per -> "男".equals(per.getSex()))); System.out.println(collect); } /** * 分隔 */
    public static void toJoiningTest(){ List<PersonModel> data = Data.getData(); String collect = data.stream() .map(personModel -> personModel.getName()) .collect(Collectors.joining(",", "{", "}")); System.out.println(collect); }

 

groupingBy 分組

groupingBy 用於將數據分組,最終返回一個 Map 類型

Map<Integer, List<Person>> map = list.stream().collect(groupingBy(Person::getAge));

 

例子中咱們按照年齡 age 分組,每個 Person 對象中年齡相同的歸爲一組

另外能夠看出,Person::getAge 決定 Map 的鍵(Integer 類型),list 類型決定 Map 的值(List)

 

2.收集對象實體自己
- 在開發過程當中咱們也須要有時候對本身的list中的實體按照其中的一個字段進行分組(好比 id ->List),這時候要設置map的value值是實體自己。

 

public Map<Long, Account> getIdAccountMap(List<Account> accounts) { return accounts.stream().collect(Collectors.toMap(Account::getId, account -> account)); }

 

account -> account是一個返回自己的lambda表達式,其實還可使用Function接口中的一個默認方法 Function.identity(),這個方法返回自身對象,更加簡潔

重複key的狀況。
在list轉爲map時,做爲key的值有可能重複,這時候流的處理會拋出個異常:Java.lang.IllegalStateException:Duplicate key。這時候就要在toMap方法中指定當key衝突時key的選擇。(這裏是選擇第二個key覆蓋第一個key)

public Map<String, Account> getNameAccountMap(List<Account> accounts) { return accounts.stream().collect(Collectors.toMap(Account::getUsername, Function.identity(), (key1, key2) -> key2)); }

 

分組後統計每一個組的數量:

Map<Integer, Long> items = list.stream().collect(Collectors.groupingBy(User::getUserName,Collectors.counting())); 

  

 

多級分組

groupingBy 能夠接受一個第二參數實現多級分組:

 

Map<Integer, Map<T, List<Person>>> map = list.stream().collect(groupingBy(Person::getAge, groupBy(...)));

 

partitioningBy 分區

分區與分組的區別在於,分區是按照 true 和 false 來分的,所以partitioningBy 接受的參數的 lambda 也是 T -> boolean

根據年齡是否小於等於20來分區 Map<Boolean, List<Person>> map = list.stream() .collect(partitioningBy(p -> p.getAge() <= 20)); 打印輸出 { false=[Person{name='mike', age=25}, Person{name='tom', age=30}], true=[Person{name='jack', age=20}] }

 

【統計】

 List<User> users = User.getUsers(); int sum = users.stream().mapToInt(User::getUserAge).sum();//求和 System.out.println("sum==" + sum); int max = users.stream().mapToInt(User::getUserAge).max().getAsInt();//最大 System.out.println("max==" + max); int min = users.stream().mapToInt(User::getUserAge).min().getAsInt();//最小 System.out.println("min==" + min); Double average = users.stream().mapToInt(User::getUserAge).average().getAsDouble();//平均值 System.out.println("average==" + average); long count = users.stream().mapToInt(User::getUserAge).count(); // 獲得元素個數 System.out.println("count===" + count);

 

【參數匹配】

 // allMatch 檢測是否所有知足指定的參數行爲 boolean b = users.stream().allMatch(User->User.getUserAge()>5); System.out.println("allMatch,檢測是否所有都知足指定的參數行爲:"+b); // anyMatch 檢測是否存在一個或者多個知足指定的參數行爲 boolean any = users.stream().anyMatch(User->User.getUserAge()>5); System.out.println("anyMatch,檢測是否存在一個或多個知足指定的參數行爲:"+any); // nonMatch 檢測是否不存在知足指定行爲的元素 boolean non = users.stream().noneMatch(User->User.getUserAge()>5); System.out.println("檢測是否不存在知足指定行爲的元素:"+non);
 
 

 







 

參考博客:

https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

https://www.jianshu.com/p/9fe8632d0bc2

https://cloud.tencent.com/developer/article/1187833

https://www.concretepage.com/java/jdk-8/java-8-distinct-example

相關文章
相關標籤/搜索