java代碼之美(2)---Java8 Stream

Stream

第一次看到Stream表達式就深深把我吸引,用它可使你的代碼更加整潔並且對集合的操做效率也會大大提升,若是你尚未用到java8的Stream特性,那就說明你確實out啦。html

1、概述

一、什麼是Stream

Stream是一種可供流式操做的數據視圖有些相似數據庫中視圖的概念它不改變源數據集合若是對其進行改變的操做它會返回一個新的數據集合。java

總的來說它有三大特性:在以後咱們會對照着詳細說明數據庫

       一、stream不存儲數據編程

       二、stream不改變源數據數組

       三、stream的延遲執行特性less

二、Stream優勢

  1. 代碼簡潔,函數式編程寫出的代碼簡潔且意圖明確,使用stream接口讓你今後告別for循環。函數式編程

  2. 多核友好,Java函數式編程使得編寫並行程序從未如此簡單,你須要的所有就是調用一下parallel()方法。函數

三、Stream API經常使用方法

Stream操做分類
中間操做(Intermediate operations) 無狀態(Stateless) unordered() filter() map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek()
有狀態(Stateful) distinct() sorted() sorted() limit() skip()
結束操做(Terminal operations) 非短路操做 forEach() forEachOrdered() toArray() reduce() collect() max() min() count()
短路操做(short-circuiting) anyMatch() allMatch() noneMatch() findFirst() findAny()

 

 

 

 

 

 

 

 

 

 

 

 

Stream上的全部操做分爲兩類:中間操做結束操做,中間操做只是一種標記,只有結束操做纔會觸發實際計算。post

中間操做又能夠分爲無狀態的和有狀態的:ui

      無狀態中間操做是指元素的處理不受前面元素的影響,而有狀態的中間操做必須等到全部元素處理以後才知道最終結果,好比排序是有狀態操做,在讀取全部元素以前並不能肯定排序結果;

結束操做又能夠分爲短路操做和非短路操做

      短路操做是指不用處理所有元素就能夠返回結果,好比找到第一個知足條件的元素。之因此要進行如此精細的劃分,是由於底層對每一種狀況的處理方式不一樣。

經常使用中間件

      filter:過濾流,過濾流中的元素,返回一個符合條件的Stream

      map:轉換流,將一種類型的流轉換爲另一種流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本類型對應的Stream)

 flatMap:簡單的說,就是一個或多個流合併成一個新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回對應的IntStream、LongStream、DoubleStream流。)

 distinct:返回去重的Stream。

  sorted:返回一個排序的Stream。

    peek:主要用來查看流中元素的數據狀態。

     limit:返回前n個元素數據組成的Stream。屬於短路操做

     skip:返回第n個元素後面數據組成的Stream。 

結束操做

  forEach: 循環操做Stream中數據。

  toArray: 返回流中元素對應的數組對象。

  reduce: 聚合操做,用來作統計。

  collect: 聚合操做,封裝目標數據。

min、max、count: 聚合操做,最小值,最大值,總數量。

   anyMatch: 短路操做,有一個符合條件返回true。

    allMatch: 全部數據都符合條件返回true。

noneMatch: 全部數據都不符合條件返回true。

    findFirst: 短路操做,獲取第一個元素。

     findAny: 短路操做,獲取任一元素。

forEachOrdered: 暗元素順序執行循環操做。

 

2、各類案例說明

多舉點例子,之後忘記了還能夠來找本身的博客,哈哈。

首先寫一個領域對象

public class Person {
    
    private Integer  id;
    
    private String name;
    
    private String sex;
    
    private Integer age;
    
    //提供get,set,和滿參構造函數
}

一、map中間件相關例子

 

public class TestMap {

    public static void main(String[] args) {
        List<Person> persionList = new ArrayList<Person>();
        persionList.add(new Person(1,"張三","男",38));
        persionList.add(new Person(2,"小小","女",2));
        persionList.add(new Person(3,"李四","男",65));
        persionList.add(new Person(4,"王五","女",20));
        persionList.add(new Person(5,"趙六","男",38));
        persionList.add(new Person(6,"大大","男",65));

        //一、只取出該集合中全部姓名組成一個新集合
        List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList());
        System.out.println(nameList.toString());

        //二、只取出該集合中全部id組成一個新集合
        List<Integer> idList=persionList.stream().mapToInt(Person::getId).boxed().collect(Collectors.toList());
        System.out.println(idList.toString());

        //三、list轉map,key值爲id,value爲Person對象
        Map<Integer, Person> personmap = persionList.stream().collect(Collectors.toMap(Person::getId, person -> person));
        System.out.println(personmap.toString());

        //四、list轉map,key值爲id,value爲name
        Map<Integer, String> namemap = persionList.stream().collect(Collectors.toMap(Person::getId, Person::getName));
        System.out.println(namemap.toString());

        //五、進行map集合存放,key爲age值 value爲Person對象 它會把相同age的對象放到一個集合中
        Map<Integer, List<Person>> ageMap = persionList.stream().collect(Collectors.groupingBy(Person::getAge));
        System.out.println(ageMap.toString());

        //六、獲取最小年齡
        Integer ageMin = persionList.stream().mapToInt(Person::getAge).min().getAsInt();
        System.out.println("最小年齡爲: "+ageMin);

        //七、獲取最大年齡
        Integer ageMax = persionList.stream().mapToInt(Person::getAge).max().getAsInt();
        System.out.println("最大年齡爲: "+ageMax);

        //八、集合年齡屬性求和
        Integer ageAmount = persionList.stream().mapToInt(Person::getAge).sum();
        System.out.println("年齡總和爲: "+ageAmount);
        
    }
}

 運行結果:

 

是否是以前要好幾層的for循環解決的問題,經過Stream只要一行代碼就能夠解決了。

這裏要注意,若是你list轉map的key若是不惟一,會報錯,因此若是你不肯定你的key是否惟一,能夠改爲以下:

 Map<Integer, String> map = persionList.stream().collect(
                Collectors.toMap(Person::getAge, Person::getName, (key1, key2) -> key1)
        );

 二、filter相關例子

public class TestFilter {

    public static void main(String[] args) {
        List<Person> persionList = new ArrayList<Person>();
        persionList.add(new Person(1, "張三", "男", 8));
        persionList.add(new Person(2, "小小", "女", 2));
        persionList.add(new Person(3, "李四", "男", 25));
        persionList.add(new Person(4, "王五", "女", 8));
        persionList.add(new Person(5, "趙六", "女", 25));
        persionList.add(new Person(6, "大大", "男", 65));

        //一、查找年齡大於20歲的人數
        long  age=persionList.stream().filter(p->p.getAge()>20).count();
        System.out.println(age);

        //二、查找年齡大於20歲,性別爲男的人數
       List<Person>  ageList=persionList.stream().filter(p->p.getAge()>20).filter(p->"男".equals(p.getSex())).collect(Collectors.toList());
        System.out.println(ageList.size());

    }
    /*
     *運行結果:
     *  3
     *  2
     */
}

 三、sorted相關例子

   對於數組舉例

public class TestSort {

    String[] arr1 = {"abc","a","bc","abcd"};

    /**
     * 按照字符長度排序
     */
    @Test
    public void testSorted1_(){
        Arrays.stream(arr1).sorted(Comparator.comparing(String::length)).forEach(System.out::println);
        //輸出:a、bc、abc、abcd
    }

    /**
     * 倒序
     * reversed(),java8泛型推導的問題,因此若是comparing裏面是非方法引用的lambda表達式就沒辦法直接使用reversed()
     * Comparator.reverseOrder():也是用於翻轉順序,用於比較對象(Stream裏面的類型必須是可比較的)
     * Comparator. naturalOrder():返回一個天然排序比較器,用於比較對象(Stream裏面的類型必須是可比較的)
     */
    @Test
    public void testSorted2_(){
        Arrays.stream(arr1).sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);
        //輸出:abcd、abc、bc、a
        Arrays.stream(arr1).sorted(Comparator.reverseOrder()).forEach(System.out::println);
        //輸出:bc、abcd、abc、a
        Arrays.stream(arr1).sorted(Comparator.naturalOrder()).forEach(System.out::println);
        //輸出:a、abc、abcd、bc
    }

    /**
     * 先按照首字母排序
     * 以後按照String的長度排序
     */
    @Test
    public void testSorted3_(){
        Arrays.stream(arr1).sorted(Comparator.comparing(this::com1).thenComparing(String::length)).forEach(System.out::println);
    }
//輸出:a、abc、abcd、bc
public char com1(String x){ return x.charAt(0); } }

 對於集合舉例

public class TestSort {

    public static void main(String[] args) {
        List<Person> persionList = new ArrayList<Person>();
        persionList.add(new Person(1, "張三", "男", 8));
        persionList.add(new Person(2, "小小", "女", 2));
        persionList.add(new Person(3, "李四", "男", 25));
        persionList.add(new Person(4, "王五", "女", 8));
        persionList.add(new Person(5, "趙六", "女", 25));
        persionList.add(new Person(6, "大大", "男", 65));

        //一、找到年齡最小的歲數
        Collections.sort(persionList, (x, y) -> x.getAge().compareTo(y.getAge()));
        Integer age = persionList.get(0).getAge();
        System.out.println("年齡最小的有:" + age);
        //輸出:年齡最小的有:2

        //二、找到年齡最小的姓名
        String name = persionList.stream()
                .sorted(Comparator.comparingInt(x -> x.getAge()))
                .findFirst()
                .get().getName();
        System.out.println("年齡最小的姓名:" + name);
        //輸出:年齡最小的姓名:小小
    }
}

 其它的就不具體寫了。之後遇到特殊的再往裏面補充。

 

參考

    一、跟上 Java 8 – Stream API 快速入門

   二、java8之stream

   三、[Java進階篇][函數式編程][Java 8+ Stream API]

   四、深刻理解Java Stream流水線

 

想太多,作太少,中間的落差就是煩惱。想沒有煩惱,要麼別想,要麼多作。中校【10】 

相關文章
相關標籤/搜索