1. 程式人生 > >Java Stream特性與lambda表示式

Java Stream特性與lambda表示式

古人學問無遺力,少壯工夫老始成

Stream 簡介

Stream 流是jdk1.8版本引進的,那麼Stream主要是對Java中的集合所提出的的集合流抽象工具(java.util.stream),主要用於集合內的元素的計算,準確的說是過濾和統計計算。

lambda簡介

Java9 在語法上提供了Lambda表示式來傳遞方法體,簡化了之前方法必須藏身在不必要的類中的繁瑣。Lambda表示式體現了函數語言程式設計的思想,即一個函式亦可以作為另一個函式引數和返回值,使用了函式作引數/返回值的函式被稱為高階函式。

lambda使用例項

以Runnable介面為例, 如果要執行一個介面,其實就是執行的是run()方法,但是還得需要先建立一個Runnable介面,實現類。

這時候使用lambda就不必了,可以直接執行run()方法。

new Thread(()->System.out.println("Hello world")).start();

Stream流的使用例項

1)對Stream的理解

Stream不是一種真實的資料來源(不存在資料結構),所以我們沒有辦法直接來建立它,Stream只能依賴其他資料來源來轉換成我們的抽象操作。Stream本身是不存在,只是我們抽象出來的一個抽象操作,經過各種操作之後,Stream還需要轉換成真實的資料來源。
而且流是一次性資料,經過一次的中間操作選擇後,就發生改變,如果想對一開始的流操作,需要重新建立一開始的流,因為現在的流已經改變。
在這裡插入圖片描述


如上圖所述,現在的流的內容為(4,8,12)

2)Stream的建立

三中stream的建立方法

//第一種 通過Stream介面的of靜態方法建立一個流
Stream<String> stream = Stream.of("hello", "world", "helloworld");
//第二種 通過Arrays類的stream方法,實際上第一種of方法底層也是呼叫的Arrays.stream(values);
String[] array = new String[]{"hello","world","helloworld"};
Stream<String> stream3 = Arrays.stream(array);
//第三種 通過集合的stream方法,該方法是Collection介面的預設方法,所有集合都繼承了該方法
Stream<String> stream2 = Arrays.asList("hello","world","helloworld").stream();

接下來看一個簡單的例子
現有 Arrays.asList(1, 2, 3, 4, 5, 6); 一個列表
需求 找出偶數並返回一個新的陣列
傳統做法

public class Test {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        System.out.println(me(list));

    }
    public static List<Integer>me(List<Integer> list){
        ArrayList<Integer> list2 = new ArrayList<>();
        for (Integer integer : list) {
            if (integer%2==0){
                list2.add(integer);
            }
        }
        return list2;
    }
}

運用stream來做

public class Test1 {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
        list.stream().filter(x -> x % 2 == 0).forEach(s-> System.out.println(s));
    }
}

用流僅僅一句話,就可以實現,摘出來分析一下。

list.stream()     					###建立流物件
list.stream().filter()       			  ##filter  中間操作,相當於過濾器,中間要寫的就是判斷條件
list.stream().filter(x->x%2==0)          ##x->x    lambda 表示式   x%2==0   判斷條件。     

其實,我們發現用stream 其實就是用一些中間操作,要注意這些中間操作,並不是一呼叫就會生效的,只用執行終端操作時,中間的操作才會生效。這就是Stream的延遲特性。

3)stream的中間及其終端操作操作

在這裡插入圖片描述

4)分組例子(groupingBy)

學生類中來自不同地方的學生,有男生也有女生。
需求
現在根據地方分成不同的小組
根據性別分組
用stream流來做

Student類

package com.westos.test;

public class Student {
private String name;
private String sex;
private String loc;

@Override
public String toString() {
    return "Student{" +
            "name='" + name + '\'' +
            ", sex='" + sex + '\'' +
            ", loc='" + loc + '\'' +
            '}';
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getSex() { return sex; }
public void setSex(String sex) { this.sex = sex; }
public String getLoc() { return loc; }
public void setLoc(String loc) { this.loc = loc; }
public Student(String name, String sex, String loc) {
    this.name = name;
    this.sex = sex;
    this.loc = loc;
}}

實現方法按地區分組

package com.westos.test;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TestStudent {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("張", "男", "西安"),
                new Student("李", "男", "西安"),
                new Student("王", "女", "北京"),
                new Student("趙", "女", "上海"),
                new Student("周", "男", "北京"));
        Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student -> Student.getLoc()));
        System.out.println(collect);

    }
}

執行結果
{上海=[Student{name=‘趙’, sex=‘女’, loc=‘上海’}],
西安=[Student{name=‘張’, sex=‘男’, loc=‘西安’}, Student{name=‘李’, sex=‘男’, loc=‘西安’}],
北京=[Student{name=‘王’, sex=‘女’, loc=‘北京’}, Student{name=‘周’, sex=‘男’, loc=‘北京’}]}
按照性別分組

package com.westos.test;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TestStudent {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("張", "男", "西安"),
                new Student("李", "男", "西安"),
                new Student("王", "女", "北京"),
                new Student("趙", "女", "上海"),
                new Student("周", "男", "北京"));
        Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student -> Student.getSex()));
        System.out.println(collect);

    }
}

執行結果
{女=[Student{name=‘王’, sex=‘女’, loc=‘北京’},
Student{name=‘趙’, sex=‘女’, loc=‘上海’}],
男=[Student{name=‘張’, sex=‘男’, loc=‘西安’},
Student{name=‘李’, sex=‘男’, loc=‘西安’},
Student{name=‘周’, sex=‘男’, loc=‘北京’}]}

5)分割槽例子(partitioningBy)

再剛才的Student例子中再加入成績屬性。

那麼我們要做的是將現有的學生類,按照成績分成兩類,這個時候可以用到分割槽

package com.westos.test;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TestStudent {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("張", "男", "西安",89),
                new Student("李", "男", "西安",99),
                new Student("王", "女", "北京",45),
                new Student("趙", "女", "上海",25),
                new Student("周", "男", "北京",66));
        Map<Boolean, List<Student>> collect = students.stream().collect(Collectors.partitioningBy(s -> s.getSco() >= 50));
        List<Student> studentList = collect.get(false);//輸出小於50分的
        collect.get(true);//輸出大於等於50分的
        System.out.println(studentList);//輸出小於50分的
    }
}

結果
[Student{name=‘王’, sex=‘女’, loc=‘北京’, sco=45},
Student{name=‘趙’, sex=‘女’, loc=‘上海’, sco=25}]

總結:
其實分割槽會將我們的stream分成一個集合,集合中有兩個列表,一個是false對應的,也就是低於50分的,另一個就是true對應的列表,也就是大於等於50分的。
那個我們可以將分割槽總結,它就經過條件,將stream分成兩部分,一個是條件成立的,一個是篩選過後的。

6)總結

Stream每個操作都是依賴Lambda表示式或方法引用。
Stream操作是一種宣告式的資料處理方式。
Stream操作提高了資料處理效率、開發效率