StramApi常用操作

StramApi常用操作

什麼是流 ?

Stream 不是集合元素,它不是數據結構並不保存數據,它是有關算法和計算的,它更像一個高級版本的 Iterator。原始版本的 Iterator,用戶只能顯式地一個一個遍歷元素並對其執行某些操作;高級版本的 Stream,用戶只要給出需要對其包含的元素執行什麼操作,比如 “過濾掉長度大於 10 的字符串”、“獲取每個字符串的首字母”等,Stream 會隱式地在內部進行遍歷,做出相應的數據轉換。

Stream 就如同一個迭代器(Iterator),單向,不可往復,數據只能遍歷一次,遍歷過一次後即用盡了,就好比流水從面前流過,一去不復返.

流的結構

當我們使用一個流的時候,通常包括三個基本步驟:
獲取一個數據源(source)→ 數據轉換→執行操作獲取想要的結果,每次轉換原有 Stream 對象不改變,返回一個新的 Stream 對象(可以有多次轉換),這就允許對其操作可以像鏈條一樣排列,變成一個管道,如下圖所示。

流管道 (Stream Pipeline) 的構成

在這裏插入圖片描述

生成 Stream Source的方式

從 Collection 和數組

Collection.stream()
Collection.parallelStream()
Arrays.stream(T array) or Stream.of()

從 BufferedReader

java.io.BufferedReader.lines()

靜態工廠

java.util.stream.IntStream.range()
java.nio.file.Files.walk()

自己構建

java.util.Spliterator

其它

Random.ints()
BitSet.stream()
Pattern.splitAsStream(java.lang.CharSequence)
JarFile.stream()
流的操作類型分爲兩種:

Intermediate(中間):一個流可以後面跟隨零個或多個 intermediate 操作。其目的主要是打開流,做出某種程度的數據映射/過濾,然後返回一個新的流,交給下一個操作使用。這類操作都是惰性化的(lazy),就是說,僅僅調用到這類方法,並沒有真正開始流的遍歷。

Terminal(最終):一個流只能有一個 terminal 操作,當這個操作執行後,流就被使用“光”了,無法再被操作。所以這必定是流的最後一個操作。Terminal 操作的執行,纔會真正開始流的遍歷,並且會生成一個結果,或者一個 side effect。
在對於一個 Stream 進行多次轉換操作 (Intermediate 操作),每次都對 Stream 的每個元素進行轉換,而且是執行多次,這樣時間複雜度就是 N(轉換次數)個 for 循環裏把所有操作都做掉的總和嗎?其實不是這樣的,轉換操作都是 lazy 的,多個轉換操作只會在 Terminal 操作的時候融合起來,一次循環完成。我們可以這樣簡單的理解,Stream 裏有個操作函數的集合,每次轉換操作就是把轉換函數放入這個集合中,在 Terminal 操作的時候循環 Stream 對應的集合,然後對每個元素執行所有的函數。

一個流操作的示例

int sum = widgets.stream()
.filter(w -> w.getColor() == RED)
 .mapToInt(w -> w.getWeight())
 .sum();

stream() 獲取當前小物件的 source,filter 和 mapToInt 爲 intermediate 操作,進行數據篩選和轉換,最後一個 sum() 爲 terminal 操作,對符合條件的全部小物件作重量求和。

構造流的幾種常見方法

// 1. Individual values
Stream stream = Stream.of("a", "b", "c");
// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();

1.流轉換爲其它數據結構

1.1 轉爲數組 Array
String[] arr=Stream.toArray(String[]::new)

代碼:

private static  List<Person> getList() {
    List<Person> list = new ArrayList<>();
    list.add(new Person("范冰冰","女",28));
    list.add(new Person("劉亦菲","女",24));
    list.add(new Person("胡歌","男",30));
    return list;
}

public static void main(String[] args) {
    List<Person> list = getList();
    //list 轉 數組
    Person[] arr= list.stream().toArray(Person[]::new);
    Arrays.stream(arr).forEach(System.out::println);
}

效果:
在這裏插入圖片描述

1.2 轉爲集合 list,set Collection
List<String> list = stream.collect(Collectors.toList());
List<String> list = stream.collect(Collectors.toCollection(ArrayList::new));
Set set = stream.collect(Collectors.toSet());
Stack stack = stream.collect(Co`llectors.toColl`ection(Stack::new));

代碼:

  public static void main(String[] args) {
    List<Person> list = getList();
    //list 轉 數組
    Person[] arr= list.stream().toArray(Person[]::new);
    //數組 轉 list
    List<Person> collect = Arrays.stream(arr).collect(Collectors.toList());
}
1.3 轉爲字符串
String str = stream.collect(Collectors.joining()).toString();
//Collectors.joining 收集器 支持靈活的參數配置,可以指定字符串連接時的 分隔符,前綴 和 後綴 字符串

代碼:

final static String[] names = {"A", "B", "C", "D", "E"};
public static void main(String[] args) {
    String collect = Stream.of(names).collect(Collectors.joining("-", "{", "}"));
    System.out.println("字符串格式="+collect);
}

效果圖:

在這裏插入圖片描述

2.流的操作

流的操作
接下來,當把一個數據結構包裝成 Stream 後,就要開始對裏面的元素進行各類操作了。常見的操作可以歸類如下。
Intermediate:
map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered
Terminal:
forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

常用操作:

map: 把 input Stream 的每一個元素,映射成 output Stream 的另外一個元素。

在項目中的應用:

1.list對象轉換爲某個屬性的list字符串 (用來取list對象中的所有的對象的某個屬性的list)

private static  List<Person> getList() {
        List<Person> list = new ArrayList<>();
        list.add(new Person("范冰冰","女",28));
        list.add(new Person("劉亦菲","女",24));
        list.add(new Person("胡歌","男",30));
        return list;
    }

    public static void main(String[] args) {
        //獲取所有的學生名字
        List<Person> list = getList();
        List<String> resList = list.stream().map(Person::getName).collect(Collectors.toList());
        resList.stream().forEach(System.out::println);
    }

在這裏插入圖片描述
2.list對象轉化爲某兩個屬性拼接的list字符串

public static void main(String[] args) {
        //獲取所有人  "名字+年齡" 格式 的list
        List<Person> list = getList();
        List<String> resList = list.stream().map(e -> e.getName()+"+"+e.getAge()).collect(Collectors.toList());
        resList.stream().forEach(System.out::println);
    }

在這裏插入圖片描述
3.list對象按照某個屬性值進行分組

 private static  List<Person> getList() {
        List<Person> list = new ArrayList<>();
        list.add(new Person("范冰冰","女",28));
        list.add(new Person("劉亦菲","女",24));
        list.add(new Person("胡歌","男",30));
        list.add(new Person("胡歌","女",24));
        return list;
    }

    public static void main(String[] args) {
        //根據名字進行分組
        List<Person> list = getList();
        Map<Integer, List<Person>> collect = list.stream().collect(Collectors.groupingBy(Person::getAge));
        Set<Map.Entry<Integer, List<Person>>> entries = collect.entrySet();
        for(Map.Entry<Integer, List<Person>> entity:entries){
            System.out.println("key="+entity.getKey()+"value="+entity.getValue().size());
        }

    }

在這裏插入圖片描述
4.list對象按照某兩個屬性拼接進行分組


    private static  List<Person> getList() {
        List<Person> list = new ArrayList<>();
        list.add(new Person("范冰冰","女",28));
        list.add(new Person("劉亦菲","女",24));
        list.add(new Person("胡歌","男",24));
        list.add(new Person("胡歌","女",24));
        return list;
    }

    public static void main(String[] args) {
        //根據 "性別-年齡" 格式進行分組
        List<Person> list = getList();
        Map<String, List<Person>> collect = list.stream().collect(Collectors.groupingBy(e -> e.getGender() + "-" + String.valueOf(e.getAge())));
        Set<Map.Entry<String, List<Person>>> entries = collect.entrySet();
        for(Map.Entry<String, List<Person>> entity:entries){
            System.out.println("key="+entity.getKey()+"  value="+entity.getValue().size());
        }

    }

在這裏插入圖片描述

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