java8 stream流操作


 

 

Stream

  在對流進行處理時,不同的流操作以級聯的方式形成處理流水線。一個流水線由一個源(source),0 到多個中間操作(intermediate operation)和一個終結操作(terminal operation)完成。

  • 源:源是流中元素的來源。Java 提供了很多內置的源,包括數組、集合、生成函數和 I/O 通道等。
  • 中間操作:中間操作在一個流上進行操作,返回結果是一個新的流。這些操作是延遲執行的。
  • 終結操作:終結操作遍歷流來產生一個結果或是副作用。在一個流上執行終結操作之后,該流被消費,無法再次被消費

     Java 8 支持從不同的源中創建流。

中間操作

流中間操作在應用到流上,返回一個新的流。下面列出了常用的流中間操作:

  • map:通過一個 Function 把一個元素類型為 T 的流轉換成元素類型為 R 的流。
  • flatMap:通過一個 Function 把一個元素類型為 T 的流中的每個元素轉換成一個元素類型為 R 的流,再把這些轉換之后的流合並。
  • filter:過濾流中的元素,只保留滿足由 Predicate 所指定的條件的元素。
  • distinct:使用 equals 方法來刪除流中的重復元素。
  • limit:截斷流使其最多只包含指定數量的元素。
  • skip:返回一個新的流,並跳過原始流中的前 N 個元素。
  • sorted:對流進行排序。
  • peek:返回的流與原始流相同。當原始流中的元素被消費時,會首先調用 peek 方法中指定的 Consumer 實現對元素進行處理。
  • dropWhile:從原始流起始位置開始刪除滿足指定 Predicate 的元素,直到遇到第一個不滿足 Predicate 的元素。
  • takeWhile:從原始流起始位置開始保留滿足指定 Predicate 的元素,直到遇到第一個不滿足 Predicate 的元素。

終結操作

  終結操作產生最終的結果。

  1.forEach 和 forEachOrdered 對流中的每個元素執行由 Consumer 給定的實現。在使用 forEach 時,並沒有確定的處理元素的順序;forEachOrdered 則按照流的相遇順序來處理元素,如果流有確定的相遇順序的話。

  2.reduce進行遞歸計算

  3.collect生成新的數據結構

  4.......

部分圖解:(摘抄)

  

  

   

   

    

   

    

 

下面是示例代碼

package com.gc.study.java8.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

import com.gc.study.java8.lambda.User;
import com.gc.study.java8.lambda.User.Status;

/**
 * @author gc
 * 一、Stream的三個操作步驟 (同一個流stream只能消費一次)
 * 1.創建stream
 * 2.中間操作
 *         多個中間操作可以連接起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理
 *         而在終止操作時一次性全部處理,稱為惰性求值
 * 3.終止操作
 */
public class TestStream {
    //創建Stream
    @Test
    public void test() {
        List<String> list = new ArrayList<String>();
        //1.可以通過Collection系列集合提供的stream() 或 parallelStream()
        Stream<String> stream1 = list.stream();
        
        User[] users = new User[10];
        //2.通過Arrays中的靜態方法stream() 獲取數組流
        Stream<User> stream2 = Arrays.stream(users);
        
        //3.通過Stream類中的靜態方法of()
        Stream<String> stream3 = Stream.of("aa","bb","cc");
        
        //4.創建無限流
        Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
        stream3.forEach(System.out::println);
        stream4.limit(10).forEach(x -> System.out.println(x));
    }
    
    
    List<User> users = Arrays.asList(
            new User("gc1", 24, 7500, Status.BUSY),
            new User("gc2", 25, 13000, Status.FREE),
            new User("gc3", 26, 20000, Status.VOCATION),
            new User("gc4", 23, 2000, Status.BUSY),
            new User("gc5", 22, 0, Status.FREE));
    /*
     * 中間操作:(1.返回結果依然是流  2.中間操作是延遲的,遇到終結操作才會觸發執行  3.中間操作是流水線形式的)
     *     篩選與切片
     *         filter:接收流中的元素,從流中排除某些元素
     *         limit:截斷流,使元素不超過給定數量
     *         skip(n): 跳過前n個元素,返回剩余的元素,若流中元素不足n個,則返回空流
     *       distinct:篩選,通過流所生成元素的hashCode和equals去除重復元素
     *   映射:
     *       map:接收lambda,將元素轉換成其它形式或提取信息。接收一個函數作為參數,該函數會被應用到每個元素上,並將其映射成一個新的元素
     *       flatMap:接收一個函數作為參數,將流中的每個值都換成另一個流,然后把所有流連城一個流
     *   排序:
     *       sorted():自然排序(Comparable)
     *       sorted(Comparator com):定制排序(Comparator)
     */
    //內部迭代:迭代操作部由Stream API完成
    @Test
    public void testMid() {
        //中間操作filter的作用是過濾年齡大於24的User,返回新的流
        Stream<User> s = users.stream().filter(u -> {
            //u.setName("test");
            System.out.println("filter mid ge:"+u.getAge());
            return u.getAge() > 24;
        });
        //打印流,這里才會實際執行上面的filter函數
        /*
         * 輸出結果如下:
         *  filter mid ge:24
            filter mid ge:25
            foreach end age:25
            filter mid ge:26
            foreach end age:26
            filter mid ge:23
            filter mid ge:22
         */
        s.forEach(x -> System.out.println("foreach end age:" + x.getAge()));
        
        //這里是去除list中的重復元素
        users.stream().distinct().forEach(System.out::println);
        
        
    }
    
    //下面測試中間操作的作用關系
    //    1.中間操作是流水線形式的,即不是中間操作完成才進行終結操作,而是執行完一條中間操作接着執行一條終結操作。以此循環。
    @Test
    public void testMid2() {
        users.stream().limit(1).filter(u -> {
            System.out.println("age:" + u.getAge());
            return (u.getAge() > 24);
        }).forEach(System.out::println);

        System.out.println("-------------------------");
        /*  下面輸出結果如下
         *  age:24
            age:25
            User [name=gc2, age=25, salary=13000, status=FREE]
         */
        users.stream().filter(u -> {
            System.out.println("age:" + u.getAge());
            return (u.getAge() > 24);
        }).limit(1).forEach(System.out::println);

    }
    
    @Test
    public void testMap() {
        List<String> list = Arrays.asList("aa","bb","cc");
        //中間操作map傳遞的是函數式接口Function,其作用是進行數據轉換。
        //這里str -> str.toUpperCase()即為Function接口中apply方法的實現,所以其作用就是轉為大寫。
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
        //這個同上,是lambda的簡寫
        list.stream().map(String::toUpperCase).forEach(System.out::println);
        
        //使用Function接口的功能轉換,提取User的用戶名,執行完中間操作map后,相當於生成了一個List<String> userNames.(中間操作有延遲性,所以這里不是准確描述)
        users.stream().map(User::getName).forEach(System.out::println);
        users.stream().map(u -> u.getName()).forEach(System.out::println);
        
        System.out.println("----------------------map,類似於list.add(list2),保留list2的數據結構");
        Stream<Stream<Character>> stream = list.stream().map(TestStream::filterCharacter);
        stream.forEach(sm -> {
            sm.forEach(System.out::println);
        });
        System.out.println("----------------------flatmap, 類似於list.addall(),兩個list合並為一個");
        Stream<Character> stream2 = list.stream().flatMap(TestStream::filterCharacter);
        stream2.forEach(System.out::println);
    }
    
    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<Character>();
        
        for(Character ch : str.toCharArray()) {
            list.add(ch);
        }
        return list.stream();
    }
    
    @Test
    public void testSort() {
        System.out.println("------自然排序,依賴對象自身實現Comparable");
        List<String> list = Arrays.asList("aa","bb","cc");
        list.stream().sorted().forEach(System.out::println);
        System.out.println("-----定制排序,需要復寫Comparator");
        
        //sorted的入參是Comparator接口,所以(u1,u2) -> {return u1.getAge() - u2.getAge();}成了Comparator接口的匿名實現
        users.stream().sorted((u1,u2) -> {
            return u1.getAge() - u2.getAge();
        }).forEach(System.out::println);;
    }
    
    /*
     * 查找與匹配
     *     allMatch:檢查是否匹配所有元素
     *     anyMatch:檢查是否至少匹配一個元素
     *     noneMatch:檢查是否沒有任何元素匹配
     *     findFirst:返回第一個元素
     *     findAny:返回當前流中的任意元素
     *  count:返回流中元素的總個數
     *  max:返回流中最大值
     *  min:返回流中最小值
     * 
     */
    @Test
    public void testMatch() {
        boolean b1 = users.stream().allMatch(u -> u.getStatus().equals(Status.BUSY));
        System.out.println("all busy:"+b1);
        
        boolean b2 = users.stream().anyMatch(u -> u.getStatus().equals(Status.BUSY));
        System.out.println("any busy:"+b2);
        
        boolean b3 = users.stream().noneMatch(u -> u.getStatus().equals(Status.BUSY));
        System.out.println("none busy:"+b3);
        
        Optional<User> user1 = users.stream().findFirst();
        System.out.println("findFirst:"+user1.get());
        
        Optional<User> findAny = users.stream().filter(u -> u.getStatus().equals(Status.FREE)).findAny();
        System.out.println("findAny:"+findAny.get());
        
        long count = users.stream().count();
        System.out.println("count:"+count);
        Optional<User> max = users.stream().max((u1, u2) -> {
            return u1.getAge()-u2.getAge();
        });
        System.out.println("max:"+max.get());
        
        Optional<User> min = users.stream().min((u1, u2) -> {
            return u1.getAge()-u2.getAge();
        });
        System.out.println("min:"+min.get());
        
    }
    
    /*
     * 歸約:(可以理解為遞歸,也是終止操作)
     *     reduce 進行反復計算,如求和
     */
    @Test
    public void testReduce() {
        List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9);
        //這里0是初始值,第一次執行規約應該是0+1,其中1是第一個值
        Integer sum = list.stream().reduce(0, (x,y) -> x + y);
        System.out.println("sum:"+sum);
        
        Optional<Integer> reduce = users.stream().map(User::getSalary).reduce(Integer::sum);
        System.out.println("sum2:"+reduce.get());
    }
    
    /*
     * 收集(stream的終止操作之一,forEach,reduce等也是)
     *  collect:將流轉換為其他形式,接收一個collection接口的實現,用於給stream元素做匯總的方法
     */
    @Test
    public void testCollect() {
        //map是數據轉換,將List<User> 轉換為String類型的Stream。 collect把新的Stream轉化為List<String>
        List<String> list = users.stream().map(User::getName)
            .collect(Collectors.toList());
        list.forEach(System.out::println);
        
        //這里是轉換為set
        users.stream().map(User::getName).collect(Collectors.toSet());
        //把list轉為其它的數據結構,這里是hashset
        HashSet<String> hashSet = users.stream().map(User::getName).
            collect(Collectors.toCollection(HashSet::new));
        
        Long count = users.stream().collect(Collectors.counting());
        Double avgAge = users.stream().collect(Collectors.averagingInt(User::getAge));
        
        //按條件分組
        Map<Status, List<User>> map = users.stream().collect(Collectors.groupingBy(User::getStatus));
        System.out.println("collectors分組功能, map:"+map);
        
        Map<Status, Map<String, List<User>>> collect = users.stream().collect(Collectors.groupingBy(
                User::getStatus, Collectors.groupingBy(u -> {
                    if(((User)u).getAge() <= 24) {
                        return "happy";
                    } else {
                        return "very happy";
                    }
                })));
        System.out.println("多級分組:"+collect);
        
        //按條件分區,true放在一組,false放在另一組
        Map<Boolean, List<User>> collect2 = users.stream().collect(Collectors.partitioningBy((u) -> u.getAge() > 24));
        System.out.println(collect2);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM