Stream Api

1.什麼是Stream

Stream Api對集合數據進行操作,就類似於使用sql執行的數據庫查詢

Stream是數據渠道,用於操作數據源(集合、數組等)所生成的元素序列.
集合講的是數據,Stream講的是計算

注意:

  • Stream自己不會存儲元素
  • Stream不會改變源對象.相反,他會返回一個持有結果的新Stream
  • Stream操作是延遲執行的,意味着他們會等到需要結果的時候才執行

1.1 Stream的操作三步驟

  • 1.創建Stream
    一個數據源(如:集合、數組),獲取一個流
  • 2.中間操作
    一箇中間操作鏈,對數據源的數據進行處理
  • 3.終止操作
    一旦執行了終止操作,就執行中間操作鏈,併產生結果,之後,不會再被使用

2.Stream實例化

2.1 通過集合

  • Stream<E> stream(): 返回一個順序流
  • Stream<E> parallelStream(): 返回一個並行流
public void test() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小張", 32));
    list.add(new Person("小王", 12));

    // default Stream<E> Stream() 返回一個順序流
    Stream<Person> stream = list.stream();

    // default Stream<E> parallelStream() 返回一個並行流
    Stream<Person> parallelStream = list.parallelStream();
}

2.2 通過數組

@Test
public void test2() {
    int[] arr = {1, 2, 3, 4, 5, 6};
    // 調用Arrays類的Stream<T> stream(T[] array) 返回一個流
    IntStream stream = Arrays.stream(arr);

    Person p1 = new Person("小張", 32);
    Person p2 = new Person("小王", 12);
    Person[] personArr = new Person[]{p1, p2};
    Stream<Person> stream1 = Arrays.stream(personArr);
}

2.3 通過Stream類的靜態方法

@Test
public void test3() {
    Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
    Stream<Long> longStream = Stream.of(1L, 2L, 3L, 4L, 5L);
    Stream<Double> doubleStream = Stream.of(1.0, 2.0, 3.0, 4.0, 5.0);
    Stream<String> stringStream = Stream.of("1", "2", "3", "4", "5");
    Stream<Person> personStream = Stream.of(new Person("小張", 32), new Person("小王", 12));
}

2.4 創建無限流

  • Stream<T> iterate(final T seed, final UnaryOperator<T> f)
    final T seed:初始值
    final UnaryOperator<T> f:函數式接口,參數和返回值都是一個類型的
// 遍歷從0開始的前10個偶數
 @Test
 public void test4() {
     Stream.iterate(0, t -> t + 2).limit(10).forEach(System.out::println);
 }
  • Stream<T> generate(Supplier<T> s)
    Supplier<T> s:無參數,返回類型爲任意類型的函數式接口
// 生成
Stream.generate(Math::random).limit(10).forEach(System.out::println);

3.Stream的中間操作

多個中間操作可以連接形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何處理!而在終止操作時,一次性全部處理,稱爲"惰性求值"

3.1 篩選和切片

  • filter(Predicate p)
    接收lambda,從流中排除某些元素
  • distinct()
    篩選,通過流所生成的元素 hashCode()和equals去除重複元素
  • limit(long maxSize)
    截斷流,使其元素不超過給定數量
  • skip(long n)
    跳過元素,返回一個扔掉了前n個元素的流,若流中元素不足n個,則返回一個空流,與limit(n)互補
@Test
public void test4() {
    getStream().filter(t -> t.age >20).forEach(System.out::println);
    getStream().limit(3).forEach(System.out::println);
    getStream().skip(2).forEach(System.out::println);
    // 需要重寫Person類的hashCode()和equals()方法
    getStream().distinct().forEach(System.out::println);
}

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小張", 32));
    list.add(new Person("小王", 12));
    list.add(new Person("小李", 16));
    return list.stream();
}

3.2 映射

  • map(Function<? super T, ? extends R> mapper)
    接收一個函數作爲參數,該函數會被應用到每個元素上,並將其映射爲一個新的元素
  • <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
    接收一個函數作爲參數,將流中每個值轉換成另一個流,然後將所有流連成一個流
@Test
public void test5() {
    List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
    // 獲取年齡大於20歲的人的姓名
    getStream().filter(t -> t.age > 20).map(t -> t.name).forEach(System.out::println);

    // 使用map
    Stream<Stream<Character>> streamStream = list.stream().map(StreamApi::fromStringToStream);
    streamStream.forEach(t -> {
        t.forEach(System.out::println);
        System.out.println("---");
    });

    // 使用flatMap
    Stream<Character> characterStream = list.stream().flatMap(StreamApi::fromStringToStream);
    characterStream.forEach(System.out::println);
}

public static Stream<Character> fromStringToStream(String str) {
    ArrayList<Character> list = new ArrayList<>();
    for (Character c : str.toCharArray()) {
        list.add(c);
    }
    return list.stream();
}

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小張", 32));
    list.add(new Person("小王", 12));
    list.add(new Person("小李", 16));
    return list.stream();
}

3.3 排序

@Test
public void test6() {
    List<Integer> list = Arrays.asList(12, 43, 65, 34, 87, 0, -98);
    // 自然排序
    list.stream().sorted().forEach(System.out::println);
    // 使用定製排序
    getStream().sorted((o1, o2) -> o2.age - o1.age).forEach(System.out::println);
}

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小張", 32));
    list.add(new Person("小王", 12));
    list.add(new Person("小李", 16));
    return list.stream();
}

4.Stream的終止操作

4.1 匹配和查找

  • boolean allMatch(Predicate<? super T> predicate): 檢查是否匹配所有元素
  • boolean anyMatch(Predicate<? super T> predicate): 檢查是否至少匹配一個元素
  • boolean noneMatch(Predicate<? super T> predicate): 檢查是否沒有匹配的元素
  • Optional<T> findFirst(): 返回第一個元素
  • Optional<T> findAny(): 返回當前流中任意元素(在parallelStream下使用)
  • long count(): 返回流中元素的總個數
  • Optional<T> max(Comparator<? super T> comparator): 返回流中最大值
  • Optional<T> min(Comparator<? super T> comparator): 返回流中最小值
  • void forEach(Consumer<? super T> action): 內部迭代
@Test
public void test6() {
    // 是否所有人的年齡都大於18歲
    boolean b1 = getStream().allMatch(t -> t.age > 18);
    System.out.println(b1);

    // 是否存在大於18歲的人
    boolean b2 = getStream().anyMatch(t -> t.age > 18);
    System.out.println(b2);

    // 是否所有人的年齡都不大於18
    boolean b3 = getStream().noneMatch(t -> t.age > 18);
    System.out.println(b3);

    // 返回第一個元素
    Optional<Person> first = getStream().findFirst();
    System.out.println(first);

    // 返回當前流中任意元素(在parallelStream下使用)
    Optional<Person> any = getStream().findAny();
    System.out.println(any);

    // 返回流中元素的總個數
    long count = getStream().count();
    System.out.println(count);

    // 返回流中最大值
    Optional<Person> max = getStream().max((o1, o2) -> Integer.compare(o1.age, o2.age));
    System.out.println(max);

    // 返回流中最小值
    Optional<Person> min = getStream().min((o1, o2) -> Integer.compare(o1.age, o2.age));
    System.out.println(min);
}

public static Stream<Person> getStream() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("小明", 25));
    list.add(new Person("小李", 16));
    list.add(new Person("小張", 32));
    list.add(new Person("小王", 12));
    return list.stream();
}

4.2 歸約

  • T reduce(T identity, BinaryOperator<T> accumulator); 可以將流中元素反覆結合起來,得到一個值
  • Optiona\l reduce(BinaryOperator<T> accumulator); 可以將流中元素反覆結合起來,得到一個值
public void test6() {
    // 計算1~10的自然數的總和
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer reduce = list.stream().reduce(0, Integer::sum);
    System.out.println(reduce);

    // 計算年齡的總和
    Stream<Integer> ageStream = getStream().map(t -> t.age);
    Optional<Integer> ageSum = ageStream.reduce(Integer::sum);
    System.out.println(ageSum);
}

4.3 收集

  • <R, A> R collect(Collector<? super T, A, R> collector);
// 將年紀大於20歲的人,存入一個集合中
List<Person> collect = getStream().filter(t -> t.age > 20).collect(Collectors.toList());
System.out.println(collect);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章